From f6e884bbecffd517f51503f0693bc304a8ff5421 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 22 Apr 2026 05:27:28 +0000 Subject: [PATCH 01/49] chore: Bump version to v1.43.0 --- config/version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/version.php b/config/version.php index fd10b03a6..7f3c6d3d9 100644 --- a/config/version.php +++ b/config/version.php @@ -12,7 +12,7 @@ | */ - 'cc_version' => '1.42.0', + 'cc_version' => '1.43.0', 'show_cc_version' => true, ]; From ccee0aca4100e27000b6718c26dc3a2fc2c58550 Mon Sep 17 00:00:00 2001 From: t-kirita <252978932+t-kirita@users.noreply.github.com> Date: Wed, 22 Apr 2026 22:01:22 +0900 Subject: [PATCH 02/49] =?UTF-8?q?add:=20WYSIWYG=E3=82=A8=E3=83=87=E3=82=A3?= =?UTF-8?q?=E3=82=BF=20sandbox=5Fiframes=5Fexclusions=E3=81=ABcalendar.goo?= =?UTF-8?q?gle.com=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/views/plugins/common/wysiwyg.blade.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/views/plugins/common/wysiwyg.blade.php b/resources/views/plugins/common/wysiwyg.blade.php index e39e53e8d..78f8a58f6 100644 --- a/resources/views/plugins/common/wysiwyg.blade.php +++ b/resources/views/plugins/common/wysiwyg.blade.php @@ -306,6 +306,7 @@ 'dailymotion.com', 'embed.music.apple.com', 'google.com', + 'calendar.google.com', 'open.spotify.com', 'giphy.com', 'dai.ly', From 84f4db86ff5074a5b7a146ad4f401460b6f55c10 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 09:15:16 +0000 Subject: [PATCH 03/49] chore(deps-dev): bump axios from 1.15.0 to 1.15.2 Bumps [axios](https://github.com/axios/axios) from 1.15.0 to 1.15.2. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.15.0...v1.15.2) --- updated-dependencies: - dependency-name: axios dependency-version: 1.15.2 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index c6111edca..6d65303d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@fortawesome/fontawesome-free": "^6.7.2", "@popperjs/core": "^2.11.8", "@vue/compiler-sfc": "^3.5.13", - "axios": "^1.15.0", + "axios": "^1.15.2", "bootstrap": "^4.0.0", "codemirror": "^6.0.1", "dayjs": "^1.11.13", @@ -3585,9 +3585,9 @@ "optional": true }, "node_modules/axios": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", - "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.2.tgz", + "integrity": "sha512-wLrXxPtcrPTsNlJmKjkPnNPK2Ihe0hn0wGSaTEiHRPxwjvJwT3hKmXF4dpqxmPO9SoNb2FsYXj/xEo0gHN+D5A==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 02bc2d26e..08b1ef667 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "@fortawesome/fontawesome-free": "^6.7.2", "@popperjs/core": "^2.11.8", "@vue/compiler-sfc": "^3.5.13", - "axios": "^1.15.0", + "axios": "^1.15.2", "bootstrap": "^4.0.0", "codemirror": "^6.0.1", "dayjs": "^1.11.13", From 0bb6b68441367448f67beaeb117f884e51b1dc8f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 10:00:56 +0000 Subject: [PATCH 04/49] chore(deps-dev): bump postcss from 8.5.3 to 8.5.14 Bumps [postcss](https://github.com/postcss/postcss) from 8.5.3 to 8.5.14. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.5.3...8.5.14) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.14 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6d65303d6..c89e8a7d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8960,9 +8960,9 @@ } }, "node_modules/postcss": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", "dev": true, "funding": [ { @@ -8980,7 +8980,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.8", + "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, From 3ee486764750b41c6176edda7843a530c747b95e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 20:40:39 +0000 Subject: [PATCH 05/49] chore(deps-dev): bump fast-uri from 3.0.6 to 3.1.2 Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.0.6 to 3.1.2. - [Release notes](https://github.com/fastify/fast-uri/releases) - [Commits](https://github.com/fastify/fast-uri/compare/v3.0.6...v3.1.2) --- updated-dependencies: - dependency-name: fast-uri dependency-version: 3.1.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index c89e8a7d6..bd0a57501 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5908,9 +5908,9 @@ "optional": true }, "node_modules/fast-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "dev": true, "funding": [ { From 44aac918fd5808fd3b860dcbd35ab0ebd912824f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 May 2026 16:14:49 +0000 Subject: [PATCH 06/49] chore(deps-dev): bump @babel/plugin-transform-modules-systemjs Bumps [@babel/plugin-transform-modules-systemjs](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-modules-systemjs) from 7.27.1 to 7.29.4. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.29.4/packages/babel-plugin-transform-modules-systemjs) --- updated-dependencies: - dependency-name: "@babel/plugin-transform-modules-systemjs" dependency-version: 7.29.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 156 ++++++++++++++++++++++------------------------ 1 file changed, 76 insertions(+), 80 deletions(-) diff --git a/package-lock.json b/package-lock.json index c89e8a7d6..9c6b5c9a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,13 +46,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -112,16 +112,16 @@ } }, "node_modules/@babel/generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz", - "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.1", - "@babel/types": "^7.27.1", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { @@ -245,6 +245,16 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", @@ -260,29 +270,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz", - "integrity": "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -305,9 +315,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true, "license": "MIT", "engines": { @@ -375,9 +385,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", "engines": { @@ -424,13 +434,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.1.tgz", - "integrity": "sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.1" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -1036,16 +1046,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", - "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "version": "7.29.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.4.tgz", + "integrity": "sha512-N7QmZ0xRZfjHOfZeQLJjwgX2zS9pdGHSVl/cjSGlo4dXMqvurfxXDMKY4RqEKzPozV78VMcd0lxyG13mlbKc4w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.29.0" }, "engines": { "node": ">=6.9.0" @@ -1619,48 +1629,48 @@ } }, "node_modules/@babel/template": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.1.tgz", - "integrity": "sha512-Fyo3ghWMqkHHpHQCoBs2VnYjR4iWFFjguTDEqA5WgZDOrFesVjMhMM2FSqTKSoUSDO1VQtavj8NFpdRBEvJTtg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz", - "integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.1", - "@babel/parser": "^7.27.1", - "@babel/template": "^7.27.1", - "@babel/types": "^7.27.1", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", - "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1876,18 +1886,14 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -1900,16 +1906,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/source-map": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", @@ -1929,9 +1925,9 @@ "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "license": "MIT", "dependencies": { From 5caae18f0823ebe0ca142a7ca7f2acf9b3ada5c4 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Wed, 13 May 2026 16:13:14 +0900 Subject: [PATCH 07/49] feat(site): add default post roles for new buckets --- app/Models/Common/Buckets.php | 130 ++++++++ app/Plugins/Manage/SiteManage/SiteManage.php | 14 + app/Plugins/User/Bbses/BbsesPlugin.php | 2 +- app/Plugins/User/Blogs/BlogsPlugin.php | 2 +- app/Plugins/User/Cabinets/CabinetsPlugin.php | 2 +- .../User/Calendars/CalendarsPlugin.php | 2 +- app/Plugins/User/Contents/ContentsPlugin.php | 2 +- .../User/Databases/DatabasesPlugin.php | 10 +- app/Plugins/User/Faqs/FaqsPlugin.php | 5 +- .../User/Photoalbums/PhotoalbumsPlugin.php | 2 +- .../User/Reservations/ReservationsPlugin.php | 4 +- .../User/Slideshows/SlideshowsPlugin.php | 10 +- app/Plugins/User/UserPluginBase.php | 12 +- .../plugins/common/frame_edit_roles.blade.php | 10 +- .../manage/site/pdf/base_main.blade.php | 8 + .../views/plugins/manage/site/site.blade.php | 28 ++ .../SiteManageNewBucketDefaultRolesTest.php | 199 ++++++++++++ .../BbsesDefaultBucketRolesFeatureTest.php | 85 ++++++ .../BlogsDefaultBucketRolesFeatureTest.php | 48 +++ .../CabinetsDefaultBucketRolesFeatureTest.php | 40 +++ ...CalendarsDefaultBucketRolesFeatureTest.php | 39 +++ .../ContentsDefaultBucketRolesFeatureTest.php | 84 ++++++ ...DatabasesDefaultBucketRolesFeatureTest.php | 56 ++++ .../DefaultBucketRolesFeatureTestTrait.php | 146 +++++++++ .../FaqsDefaultBucketRolesFeatureTest.php | 45 +++ ...otoalbumsDefaultBucketRolesFeatureTest.php | 42 +++ ...ervationsDefaultBucketRolesFeatureTest.php | 40 +++ ...lideshowsDefaultBucketRolesFeatureTest.php | 44 +++ .../Common/BucketsDefaultPostRolesTest.php | 283 ++++++++++++++++++ 29 files changed, 1369 insertions(+), 25 deletions(-) create mode 100644 tests/Feature/Plugins/Manage/SiteManage/SiteManageNewBucketDefaultRolesTest.php create mode 100644 tests/Feature/Plugins/User/Bbses/BbsesDefaultBucketRolesFeatureTest.php create mode 100644 tests/Feature/Plugins/User/Blogs/BlogsDefaultBucketRolesFeatureTest.php create mode 100644 tests/Feature/Plugins/User/Cabinets/CabinetsDefaultBucketRolesFeatureTest.php create mode 100644 tests/Feature/Plugins/User/Calendars/CalendarsDefaultBucketRolesFeatureTest.php create mode 100644 tests/Feature/Plugins/User/Contents/ContentsDefaultBucketRolesFeatureTest.php create mode 100644 tests/Feature/Plugins/User/Databases/DatabasesDefaultBucketRolesFeatureTest.php create mode 100644 tests/Feature/Plugins/User/DefaultBucketRolesFeatureTestTrait.php create mode 100644 tests/Feature/Plugins/User/Faqs/FaqsDefaultBucketRolesFeatureTest.php create mode 100644 tests/Feature/Plugins/User/Photoalbums/PhotoalbumsDefaultBucketRolesFeatureTest.php create mode 100644 tests/Feature/Plugins/User/Reservations/ReservationsDefaultBucketRolesFeatureTest.php create mode 100644 tests/Feature/Plugins/User/Slideshows/SlideshowsDefaultBucketRolesFeatureTest.php create mode 100644 tests/Unit/Models/Common/BucketsDefaultPostRolesTest.php diff --git a/app/Models/Common/Buckets.php b/app/Models/Common/Buckets.php index c17fa9044..f3350380e 100644 --- a/app/Models/Common/Buckets.php +++ b/app/Models/Common/Buckets.php @@ -3,6 +3,7 @@ namespace App\Models\Common; use App\Models\Common\BucketsRoles; +use App\Models\Core\Configs; use App\Traits\ConnectRoleTrait; use Database\Factories\Common\BucketsFactory; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -14,6 +15,30 @@ class Buckets extends Model use ConnectRoleTrait; use HasFactory; + /** + * 新規バケツの投稿権限初期値に対応するConfig名 + */ + private const DEFAULT_NEW_BUCKET_POST_ROLE_CONFIGS = [ + 'role_article' => 'new_bucket_role_article_post_flag', + 'role_reporter' => 'new_bucket_role_reporter_post_flag', + ]; + + /** + * 新規バケツの投稿権限初期値を適用する対象プラグイン + */ + private const DEFAULT_POST_ROLE_TARGET_PLUGINS = [ + 'bbses', + 'blogs', + 'cabinets', + 'calendars', + 'contents', + 'databases', + 'faqs', + 'photoalbums', + 'reservations', + 'slideshows', + ]; + /** * create()やupdate()で入力を受け付ける ホワイトリスト */ @@ -27,6 +52,13 @@ class Buckets extends Model // Buckets のrole private $buckets_roles = null; + protected static function booted() + { + static::deleting(function ($bucket) { + BucketsRoles::where('buckets_id', $bucket->id)->delete(); + }); + } + /** * 投稿権限データをrole の配列で返却 */ @@ -221,6 +253,104 @@ public function needApprovalUser($user, $frame = null) return true; } + /** + * 新規バケツ作成時の投稿権限初期値を適用する。 + */ + public function initializeDefaultPostRoles(): void + { + $default_post_role_flags = self::getDefaultNewBucketPostRoleFlags(); + + foreach ($default_post_role_flags as $role => $post_flag) { + if ((int) $post_flag !== 1) { + continue; + } + + BucketsRoles::firstOrCreate( + [ + 'buckets_id' => $this->id, + 'role' => $role, + ], + [ + 'post_flag' => 1, + 'approval_flag' => 0, + ] + ); + } + } + + /** + * 投稿権限設定を持つプラグインの新規バケツなら、投稿権限初期値を適用する。 + */ + public function initializeDefaultPostRolesIfTargetPlugin(): void + { + if (!self::isDefaultPostRoleTargetPlugin($this->plugin_name)) { + return; + } + + $this->initializeDefaultPostRoles(); + } + + /** + * 新規バケツを作成し、対象プラグインだけ投稿権限初期値を適用する。 + */ + public static function createWithDefaultPostRoles(array $attributes): self + { + $bucket = self::create($attributes); + $bucket->initializeDefaultPostRolesIfTargetPlugin(); + + return $bucket; + } + + /** + * バケツを作成または更新し、新規作成時だけ投稿権限初期値を適用する。 + */ + public static function updateOrCreateWithDefaultPostRoles(array $attributes, array $values = []): self + { + $bucket = self::updateOrCreate($attributes, $values); + + if ($bucket->wasRecentlyCreated) { + $bucket->initializeDefaultPostRolesIfTargetPlugin(); + } + + return $bucket; + } + + /** + * 新規バケツの投稿権限初期値を適用する対象プラグインか判定する。 + */ + public static function isDefaultPostRoleTargetPlugin(?string $plugin_name): bool + { + return in_array($plugin_name, self::DEFAULT_POST_ROLE_TARGET_PLUGINS, true); + } + + /** + * 新規バケツ作成時の投稿権限初期値を取得する。 + */ + public static function getDefaultNewBucketPostRoleFlags(): array + { + $config_names = array_values(self::DEFAULT_NEW_BUCKET_POST_ROLE_CONFIGS); + $configs = Configs::getSharedConfigs(); + + if ($configs->isEmpty()) { + $configs = Configs::whereIn('name', $config_names)->get(); + } + + return self::resolveDefaultNewBucketPostRoleFlags($configs); + } + + /** + * Config群から新規バケツ作成時の投稿権限初期値を解決する。 + */ + private static function resolveDefaultNewBucketPostRoleFlags($configs): array + { + $configs = collect($configs); + + return [ + 'role_article' => (int) Configs::getConfigsValue($configs, self::DEFAULT_NEW_BUCKET_POST_ROLE_CONFIGS['role_article'], 0), + 'role_reporter' => (int) Configs::getConfigsValue($configs, self::DEFAULT_NEW_BUCKET_POST_ROLE_CONFIGS['role_reporter'], 0), + ]; + } + protected static function newFactory() { return BucketsFactory::new(); diff --git a/app/Plugins/Manage/SiteManage/SiteManage.php b/app/Plugins/Manage/SiteManage/SiteManage.php index cc10b76ab..71729c9cf 100644 --- a/app/Plugins/Manage/SiteManage/SiteManage.php +++ b/app/Plugins/Manage/SiteManage/SiteManage.php @@ -331,6 +331,20 @@ public function update($request, $page_id = null) 'value' => $request->additional_theme] ); + // 新規バケツ作成時のモデレータ投稿権限 + $configs = Configs::updateOrCreate( + ['name' => 'new_bucket_role_article_post_flag'], + ['category' => 'general', + 'value' => (isset($request->new_bucket_role_article_post_flag) ? $request->new_bucket_role_article_post_flag : 0)] + ); + + // 新規バケツ作成時の編集者投稿権限 + $configs = Configs::updateOrCreate( + ['name' => 'new_bucket_role_reporter_post_flag'], + ['category' => 'general', + 'value' => (isset($request->new_bucket_role_reporter_post_flag) ? $request->new_bucket_role_reporter_post_flag : 0)] + ); + // 画面の基本の背景色 $configs = Configs::updateOrCreate( ['name' => 'base_background_color'], diff --git a/app/Plugins/User/Bbses/BbsesPlugin.php b/app/Plugins/User/Bbses/BbsesPlugin.php index ec9d75104..2bc151456 100644 --- a/app/Plugins/User/Bbses/BbsesPlugin.php +++ b/app/Plugins/User/Bbses/BbsesPlugin.php @@ -761,7 +761,7 @@ public function saveBuckets($request, $page_id, $frame_id, $bucket_id = null) } // バケツの取得。なければ登録。 - $bucket = Buckets::updateOrCreate( + $bucket = Buckets::updateOrCreateWithDefaultPostRoles( ['id' => $bucket_id], ['bucket_name' => $request->name, 'plugin_name' => 'bbses'], ); diff --git a/app/Plugins/User/Blogs/BlogsPlugin.php b/app/Plugins/User/Blogs/BlogsPlugin.php index fa9d8ffd5..7234d454d 100644 --- a/app/Plugins/User/Blogs/BlogsPlugin.php +++ b/app/Plugins/User/Blogs/BlogsPlugin.php @@ -1333,7 +1333,7 @@ public function saveBuckets($request, $page_id, $frame_id, $blogs_id = null) // 画面から渡ってくるblogs_id が空ならバケツとブログを新規登録 if (empty($request->blogs_id)) { // バケツの登録 - $bucket = Buckets::create([ + $bucket = Buckets::createWithDefaultPostRoles([ 'bucket_name' => $request->blog_name, 'plugin_name' => 'blogs' ]); diff --git a/app/Plugins/User/Cabinets/CabinetsPlugin.php b/app/Plugins/User/Cabinets/CabinetsPlugin.php index 56efe19eb..3099b7832 100644 --- a/app/Plugins/User/Cabinets/CabinetsPlugin.php +++ b/app/Plugins/User/Cabinets/CabinetsPlugin.php @@ -1129,7 +1129,7 @@ private function getMoveValidator($request) private function saveCabinet($request, $frame_id, $bucket_id) { // バケツの取得。なければ登録。 - $bucket = Buckets::updateOrCreate( + $bucket = Buckets::updateOrCreateWithDefaultPostRoles( ['id' => $bucket_id], ['bucket_name' => $request->name, 'plugin_name' => 'cabinets'], ); diff --git a/app/Plugins/User/Calendars/CalendarsPlugin.php b/app/Plugins/User/Calendars/CalendarsPlugin.php index 36a6c914b..f25c8ae25 100644 --- a/app/Plugins/User/Calendars/CalendarsPlugin.php +++ b/app/Plugins/User/Calendars/CalendarsPlugin.php @@ -598,7 +598,7 @@ public function saveBuckets($request, $page_id, $frame_id, $bucket_id = null) } // バケツの取得。なければ登録。 - $bucket = Buckets::updateOrCreate( + $bucket = Buckets::updateOrCreateWithDefaultPostRoles( ['id' => $bucket_id], ['bucket_name' => $request->name, 'plugin_name' => 'calendars'], ); diff --git a/app/Plugins/User/Contents/ContentsPlugin.php b/app/Plugins/User/Contents/ContentsPlugin.php index 0f70a071d..c565f837e 100644 --- a/app/Plugins/User/Contents/ContentsPlugin.php +++ b/app/Plugins/User/Contents/ContentsPlugin.php @@ -550,7 +550,7 @@ public function store($request, $page_id = null, $frame_id = null, $id = null, $ // バケツがまだ登録されていなかったら登録する。 if (empty($this->buckets)) { - $bucket = Buckets::create([ + $bucket = Buckets::createWithDefaultPostRoles([ 'bucket_name' => $request->bucket_name ?? '無題', 'plugin_name' => 'contents' ]); diff --git a/app/Plugins/User/Databases/DatabasesPlugin.php b/app/Plugins/User/Databases/DatabasesPlugin.php index 6230dfa21..1de9a57ff 100644 --- a/app/Plugins/User/Databases/DatabasesPlugin.php +++ b/app/Plugins/User/Databases/DatabasesPlugin.php @@ -2136,10 +2136,10 @@ public function saveBuckets($request, $page_id, $frame_id, $databases_id = null) // 画面から渡ってくるdatabases_id が空ならバケツとブログを新規登録 if (empty($databases_id)) { // バケツの登録 - $bucket = new Buckets(); - $bucket->bucket_name = $request->databases_name; - $bucket->plugin_name = 'databases'; - $bucket->save(); + $bucket = Buckets::createWithDefaultPostRoles([ + 'bucket_name' => $request->databases_name, + 'plugin_name' => 'databases', + ]); if (empty($request->copy_databases_id)) { // 登録 @@ -2359,7 +2359,7 @@ public function destroyBuckets($request, $page_id, $frame_id, $databases_id) BucketsRoles::where('buckets_id', $databases->bucket_id)->delete(); // backetsの削除 - Buckets::where('id', $databases->bucket_id)->delete(); + Buckets::destroy($databases->bucket_id); // change: このバケツを表示している全ページのフレームのバケツIDを消す // // バケツIDの取得のためにFrame を取得(Frame を更新する前に取得しておく) diff --git a/app/Plugins/User/Faqs/FaqsPlugin.php b/app/Plugins/User/Faqs/FaqsPlugin.php index df66f21d1..779003454 100644 --- a/app/Plugins/User/Faqs/FaqsPlugin.php +++ b/app/Plugins/User/Faqs/FaqsPlugin.php @@ -961,10 +961,11 @@ public function saveBuckets($request, $page_id, $frame_id, $faqs_id = null) // 画面から渡ってくるfaqs_id が空ならバケツとFAQを新規登録 if (empty($request->faqs_id)) { // バケツの登録 - $bucket_id = DB::table('buckets')->insertGetId([ + $bucket = Buckets::createWithDefaultPostRoles([ 'bucket_name' => $request->faq_name, 'plugin_name' => 'faqs' ]); + $bucket_id = $bucket->id; // FAQデータ新規オブジェクト $faqs = new Faqs(); @@ -1043,7 +1044,7 @@ public function destroyBuckets($request, $page_id, $frame_id, $faqs_id) Frame::where('id', $frame_id)->update(['bucket_id' => null]); // backetsの削除 - Buckets::where('id', $frame->bucket_id)->delete(); + Buckets::destroy($frame->bucket_id); } // 削除処理はredirect 付のルートで呼ばれて、処理後はページの再表示が行われるため、ここでは何もしない。 } diff --git a/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php b/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php index 6bab9e2b4..59c410ca9 100644 --- a/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php +++ b/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php @@ -1833,7 +1833,7 @@ private function getContentsControlValidator($request) private function savePhotoalbum($request, $frame_id, $bucket_id) { // バケツの取得。なければ登録。 - $bucket = Buckets::updateOrCreate( + $bucket = Buckets::updateOrCreateWithDefaultPostRoles( ['id' => $bucket_id], ['bucket_name' => $request->name, 'plugin_name' => 'photoalbums'], ); diff --git a/app/Plugins/User/Reservations/ReservationsPlugin.php b/app/Plugins/User/Reservations/ReservationsPlugin.php index e5e0524bc..537df8cfb 100644 --- a/app/Plugins/User/Reservations/ReservationsPlugin.php +++ b/app/Plugins/User/Reservations/ReservationsPlugin.php @@ -1611,7 +1611,7 @@ public function saveBuckets($request, $page_id, $frame_id, $reservations_id = nu if (empty($request->reservations_id)) { // 画面から渡ってくるid が空ならバケツと施設を新規登録 // バケツの登録 - $bucket = Buckets::create([ + $bucket = Buckets::createWithDefaultPostRoles([ 'bucket_name' => $request->reservation_name, 'plugin_name' => 'reservations' ]); @@ -1701,7 +1701,7 @@ public function destroyBuckets($request, $page_id, $frame_id, $reservations_id) Frame::where('bucket_id', $reservation->bucket_id)->update(['bucket_id' => null]); // backetsの削除 - Buckets::where('id', $reservation->bucket_id)->delete(); + Buckets::destroy($reservation->bucket_id); // 施設予約を削除する。 $reservation->delete(); diff --git a/app/Plugins/User/Slideshows/SlideshowsPlugin.php b/app/Plugins/User/Slideshows/SlideshowsPlugin.php index 31d04dea6..cf4ab23ba 100644 --- a/app/Plugins/User/Slideshows/SlideshowsPlugin.php +++ b/app/Plugins/User/Slideshows/SlideshowsPlugin.php @@ -242,10 +242,10 @@ public function saveBuckets($request, $page_id, $frame_id, $slideshows_id = null /** * 新規登録用の処理 */ - $bucket = new Buckets(); - $bucket->bucket_name = '無題'; - $bucket->plugin_name = 'slideshows'; - $bucket->save(); + $bucket = Buckets::createWithDefaultPostRoles([ + 'bucket_name' => '無題', + 'plugin_name' => 'slideshows', + ]); // スライドショーデータ新規オブジェクト $slideshows = new Slideshows(); @@ -325,7 +325,7 @@ public function destroyBuckets($request, $page_id, $frame_id, $slideshows_id) $slideshows = Slideshows::find($slideshows_id); // backetsの削除 - Buckets::where('id', $slideshows->bucket_id)->delete(); + Buckets::destroy($slideshows->bucket_id); // バケツIDの取得のためにFrame を取得(Frame を更新する前に取得しておく) $frame = Frame::where('id', $frame_id)->first(); diff --git a/app/Plugins/User/UserPluginBase.php b/app/Plugins/User/UserPluginBase.php index ddc2048af..30bba27b9 100644 --- a/app/Plugins/User/UserPluginBase.php +++ b/app/Plugins/User/UserPluginBase.php @@ -615,6 +615,7 @@ public function editBucketsRoles($request, $page_id, $frame_id, $id = null, $use { // Buckets の取得 $buckets = $this->getBuckets($frame_id); + $default_post_role_flags = []; if ($this->frame->plugin_name == 'contents' || $buckets) { // 固定記事プラグイン(=コンテンツプラグイン)はバケツありなし、どちらでも表示する。 @@ -624,10 +625,15 @@ public function editBucketsRoles($request, $page_id, $frame_id, $id = null, $use return $this->commonView('empty_bucket_setting'); } + if ($this->frame->plugin_name == 'contents' && empty($buckets)) { + $default_post_role_flags = Buckets::getDefaultNewBucketPostRoleFlags(); + } + return $this->commonView('frame_edit_roles', [ - 'buckets' => $buckets, - 'plugin_name' => $this->frame->plugin_name, - 'use_approval' => $use_approval, + 'buckets' => $buckets, + 'plugin_name' => $this->frame->plugin_name, + 'use_approval' => $use_approval, + 'default_post_role_flags' => $default_post_role_flags, ]); } diff --git a/resources/views/plugins/common/frame_edit_roles.blade.php b/resources/views/plugins/common/frame_edit_roles.blade.php index 785a73f58..7f1a4e077 100644 --- a/resources/views/plugins/common/frame_edit_roles.blade.php +++ b/resources/views/plugins/common/frame_edit_roles.blade.php @@ -18,6 +18,12 @@ {{-- 登録後メッセージ表示 --}} @include('plugins.common.flash_message_for_frame') +@php + $default_post_role_flags = $default_post_role_flags ?? []; + $role_article_post_checked = $buckets ? $buckets->canPost("role_article") : !empty($default_post_role_flags['role_article']); + $role_reporter_post_checked = $buckets ? $buckets->canPost("role_reporter") : !empty($default_post_role_flags['role_reporter']); +@endphp +
plugin_name/saveBucketsRoles/$page->id/$frame_id#frame-$frame_id") }}" name="{{$frame->plugin_name}}_buckets_form" method="POST"> {{ csrf_field() }} plugin_name/editBucketsRoles/$page->id/$frame_id#frame-$frame_id") }}"> @@ -38,7 +44,7 @@ モデレータ
- @if($buckets && $buckets->canPost("role_article")) + @if($role_article_post_checked) @else @@ -64,7 +70,7 @@ 編集者
- @if($buckets && $buckets->canPost("role_reporter")) + @if($role_reporter_post_checked) @else diff --git a/resources/views/plugins/manage/site/pdf/base_main.blade.php b/resources/views/plugins/manage/site/pdf/base_main.blade.php index 6fbd7517c..5cca1e700 100644 --- a/resources/views/plugins/manage/site/pdf/base_main.blade.php +++ b/resources/views/plugins/manage/site/pdf/base_main.blade.php @@ -46,6 +46,14 @@ 基本レイアウト {{$base_layout_title}} + + プラグイン新規作成時のモデレータ投稿権限 + @if (Configs::getConfigsValue($configs, 'new_bucket_role_article_post_flag', 0) == '1') 許可する @else 許可しない @endif + + + プラグイン新規作成時の編集者投稿権限 + @if (Configs::getConfigsValue($configs, 'new_bucket_role_reporter_post_flag', 0) == '1') 許可する @else 許可しない @endif + 背景色 {{Configs::getConfigsValue($configs, 'base_background_color', null)}} diff --git a/resources/views/plugins/manage/site/site.blade.php b/resources/views/plugins/manage/site/site.blade.php index d1508d81f..763143c01 100644 --- a/resources/views/plugins/manage/site/site.blade.php +++ b/resources/views/plugins/manage/site/site.blade.php @@ -551,6 +551,34 @@ class="custom-control-input"
+ {{-- プラグイン新規作成時の投稿権限 --}} +
+ +

+ 掲示板やブログなどを新しく作成したとき、投稿を許可する権限の初期値です。 + 既存のプラグイン設定は変更されません。 +

+
+
+ @if(Configs::getConfigsValueAndOld($configs, "new_bucket_role_article_post_flag", 0) == 1) + + @else + + @endif + +
+
+ @if(Configs::getConfigsValueAndOld($configs, "new_bucket_role_reporter_post_flag", 0) == 1) + + @else + + @endif + +
+
+ 作成後は、各プラグインの権限設定で個別に変更できます。 +
+ {{-- Submitボタン --}}
diff --git a/tests/Feature/Plugins/Manage/SiteManage/SiteManageNewBucketDefaultRolesTest.php b/tests/Feature/Plugins/Manage/SiteManage/SiteManageNewBucketDefaultRolesTest.php new file mode 100644 index 000000000..c606d4627 --- /dev/null +++ b/tests/Feature/Plugins/Manage/SiteManage/SiteManageNewBucketDefaultRolesTest.php @@ -0,0 +1,199 @@ +seed(); + } + + /** + * 未設定状態では両方のチェックボックスが未チェックで表示されること。 + */ + public function testIndexShowsBothCheckboxesUncheckedWhenConfigsAreMissing(): void + { + $admin = $this->createSiteAdminUser(); + + $response = $this->actingAs($admin)->get('/manage/site'); + + $response->assertOk(); + $response->assertSee('プラグイン新規作成時の投稿権限'); + $response->assertDontSee('id="new_bucket_role_article_post_flag" class="custom-control-input" checked="checked"', false); + $response->assertDontSee('id="new_bucket_role_reporter_post_flag" class="custom-control-input" checked="checked"', false); + } + + /** + * 保存済みの設定があれば、画面のチェック状態へ反映されること。 + */ + public function testIndexShowsSavedFlagValues(): void + { + $admin = $this->createSiteAdminUser(); + $this->setDefaultPostRoleConfigs(1, 0); + + $response = $this->actingAs($admin)->get('/manage/site'); + + $response->assertOk(); + $response->assertSee('id="new_bucket_role_article_post_flag" class="custom-control-input" checked="checked"', false); + $response->assertDontSee('id="new_bucket_role_reporter_post_flag" class="custom-control-input" checked="checked"', false); + } + + /** + * 両方ONで保存した設定がConfigに反映され、再表示時にも維持されること。 + */ + public function testUpdateCanSaveBothFlagsAsEnabled(): void + { + $admin = $this->createSiteAdminUser(); + + $response = $this->actingAs($admin)->post('/manage/site/update', $this->buildBasePayload([ + 'new_bucket_role_article_post_flag' => 1, + 'new_bucket_role_reporter_post_flag' => 1, + ])); + + $response->assertRedirect('/manage/site'); + $this->assertDatabaseHas('configs', [ + 'name' => 'new_bucket_role_article_post_flag', + 'category' => 'general', + 'value' => '1', + ]); + $this->assertDatabaseHas('configs', [ + 'name' => 'new_bucket_role_reporter_post_flag', + 'category' => 'general', + 'value' => '1', + ]); + } + + /** + * 片方だけONでも保存でき、画面再表示も保存内容に追従すること。 + */ + public function testUpdateCanSaveOnlyOneFlagAsEnabled(): void + { + $admin = $this->createSiteAdminUser(); + + $response = $this->actingAs($admin)->post('/manage/site/update', $this->buildBasePayload([ + 'new_bucket_role_article_post_flag' => 1, + ])); + + $response->assertRedirect('/manage/site'); + $this->assertDatabaseHas('configs', [ + 'name' => 'new_bucket_role_article_post_flag', + 'category' => 'general', + 'value' => '1', + ]); + $this->assertDatabaseHas('configs', [ + 'name' => 'new_bucket_role_reporter_post_flag', + 'category' => 'general', + 'value' => '0', + ]); + } + + /** + * 一度ONにした設定を外して保存すると、Configが0に戻ること。 + */ + public function testUpdateCanTurnFlagsOffAgain(): void + { + $admin = $this->createSiteAdminUser(); + $this->setDefaultPostRoleConfigs(1, 1); + + $response = $this->actingAs($admin)->post('/manage/site/update', $this->buildBasePayload()); + + $response->assertRedirect('/manage/site'); + $this->assertDatabaseHas('configs', [ + 'name' => 'new_bucket_role_article_post_flag', + 'category' => 'general', + 'value' => '0', + ]); + $this->assertDatabaseHas('configs', [ + 'name' => 'new_bucket_role_reporter_post_flag', + 'category' => 'general', + 'value' => '0', + ]); + } + + /** + * サイト管理者権限を持つユーザーを作成する。 + */ + private function createSiteAdminUser(): User + { + $user = User::factory()->create(); + + UsersRoles::factory()->create([ + 'users_id' => $user->id, + 'target' => 'manage', + 'role_name' => 'admin_site', + 'role_value' => 1, + ]); + + return $user; + } + + /** + * プラグイン新規作成時用の投稿権限Configを保存する。 + */ + private function setDefaultPostRoleConfigs(int $articleFlag, int $reporterFlag): void + { + Configs::updateOrCreate( + ['name' => 'new_bucket_role_article_post_flag'], + ['category' => 'general', 'value' => $articleFlag] + ); + Configs::updateOrCreate( + ['name' => 'new_bucket_role_reporter_post_flag'], + ['category' => 'general', 'value' => $reporterFlag] + ); + } + + /** + * サイト基本設定更新に必要な最低限の入力値を組み立てる。 + */ + private function buildBasePayload(array $overrides = []): array + { + return array_merge([ + 'base_site_name' => 'テストサイト', + 'base_theme' => '', + 'base_layout' => '0|0|0|0', + 'additional_theme' => '', + 'base_background_color' => '', + 'base_header_color' => '', + 'base_header_font_color_class' => BaseHeaderFontColorClass::navbar_dark, + 'base_header_optional_class' => '', + 'body_optional_class' => '', + 'center_area_optional_class' => '', + 'footer_area_optional_class' => '', + 'base_header_hidden' => 0, + 'base_header_login_link' => 0, + 'base_login_password_reset' => 0, + 'base_login_redirect_previous_page' => BaseLoginRedirectPage::top_page, + 'base_login_redirect_select_page' => '', + 'use_mypage' => 0, + 'mypage_top_notice' => '', + 'mypage_bottom_notice' => '', + 'smartphone_menu_template' => SmartphoneMenuTemplateType::none, + ], $overrides); + } +} diff --git a/tests/Feature/Plugins/User/Bbses/BbsesDefaultBucketRolesFeatureTest.php b/tests/Feature/Plugins/User/Bbses/BbsesDefaultBucketRolesFeatureTest.php new file mode 100644 index 000000000..a48075cba --- /dev/null +++ b/tests/Feature/Plugins/User/Bbses/BbsesDefaultBucketRolesFeatureTest.php @@ -0,0 +1,85 @@ +seed(); + } + + /** + * 新規作成時は、サイト管理の初期値どおりにBucketsRolesが作られること。 + */ + public function testSaveBucketsCreatesDefaultRolesOnlyOnNewBucket(): void + { + $this->assertSaveBucketsCreatesDefaultRoles('bbses', [ + 'name' => '掲示板テスト', + 'use_like' => 0, + 'like_button_name' => '', + ], 1, 0); + } + + /** + * 既存バケツ更新では新規初期化を走らせず、既存権限も上書きしないこと。 + */ + public function testSaveBucketsDoesNotInitializeRolesOnExistingBucketUpdate(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame] = $this->createPluginFrame('bbses'); + $bucket = Buckets::factory()->create([ + 'bucket_name' => '既存掲示板', + 'plugin_name' => 'bbses', + ]); + $frame->update(['bucket_id' => $bucket->id]); + BucketsRoles::create([ + 'buckets_id' => $bucket->id, + 'role' => 'role_article', + 'post_flag' => 0, + 'approval_flag' => 1, + ]); + $this->setDefaultPostRoleConfigs(1, 1); + + $response = $this->actingAs($admin)->post("/redirect/plugin/bbses/saveBuckets/{$page->id}/{$frame->id}/{$bucket->id}", [ + 'redirect_path' => url("/plugin/bbses/editBuckets/{$page->id}/{$frame->id}#frame-{$frame->id}"), + 'name' => '既存掲示板を更新', + 'use_like' => 0, + 'like_button_name' => '', + ]); + + $response->assertStatus(302); + + $this->assertDatabaseCount('buckets_roles', 1); + $this->assertDatabaseHas('buckets_roles', [ + 'buckets_id' => $bucket->id, + 'role' => 'role_article', + 'post_flag' => 0, + 'approval_flag' => 1, + ]); + $this->assertDatabaseMissing('buckets_roles', [ + 'buckets_id' => $bucket->id, + 'role' => 'role_reporter', + ]); + } +} diff --git a/tests/Feature/Plugins/User/Blogs/BlogsDefaultBucketRolesFeatureTest.php b/tests/Feature/Plugins/User/Blogs/BlogsDefaultBucketRolesFeatureTest.php new file mode 100644 index 000000000..543ef355f --- /dev/null +++ b/tests/Feature/Plugins/User/Blogs/BlogsDefaultBucketRolesFeatureTest.php @@ -0,0 +1,48 @@ +seed(); + } + + /** + * ブログ新規作成では、サイト管理の初期値どおりの投稿権限が作られること。 + */ + public function testSaveBucketsCreatesDefaultRolesOnBlogCreation(): void + { + $this->assertSaveBucketsCreatesDefaultRoles('blogs', [ + 'blogs_id' => '', + 'blog_name' => 'ブログテスト', + 'rss' => 0, + 'rss_count' => 10, + 'use_like' => 0, + 'like_button_name' => '', + 'use_view_count_spectator' => 0, + 'narrowing_down_type' => 0, + 'narrowing_down_type_for_created_id' => 0, + 'narrowing_down_type_for_posted_month' => 0, + ]); + } +} diff --git a/tests/Feature/Plugins/User/Cabinets/CabinetsDefaultBucketRolesFeatureTest.php b/tests/Feature/Plugins/User/Cabinets/CabinetsDefaultBucketRolesFeatureTest.php new file mode 100644 index 000000000..c4177ceef --- /dev/null +++ b/tests/Feature/Plugins/User/Cabinets/CabinetsDefaultBucketRolesFeatureTest.php @@ -0,0 +1,40 @@ +seed(); + } + + /** + * キャビネット新規作成では、サイト管理の初期値どおりの投稿権限が作られること。 + */ + public function testSaveBucketsCreatesDefaultRolesOnCabinetCreation(): void + { + $this->assertSaveBucketsCreatesDefaultRoles('cabinets', [ + 'name' => 'キャビネットテスト', + 'upload_max_size' => '2048', + ]); + } +} diff --git a/tests/Feature/Plugins/User/Calendars/CalendarsDefaultBucketRolesFeatureTest.php b/tests/Feature/Plugins/User/Calendars/CalendarsDefaultBucketRolesFeatureTest.php new file mode 100644 index 000000000..e60c90742 --- /dev/null +++ b/tests/Feature/Plugins/User/Calendars/CalendarsDefaultBucketRolesFeatureTest.php @@ -0,0 +1,39 @@ +seed(); + } + + /** + * カレンダー新規作成では、サイト管理の初期値どおりの投稿権限が作られること。 + */ + public function testSaveBucketsCreatesDefaultRolesOnCalendarCreation(): void + { + $this->assertSaveBucketsCreatesDefaultRoles('calendars', [ + 'name' => 'カレンダーテスト', + ]); + } +} diff --git a/tests/Feature/Plugins/User/Contents/ContentsDefaultBucketRolesFeatureTest.php b/tests/Feature/Plugins/User/Contents/ContentsDefaultBucketRolesFeatureTest.php new file mode 100644 index 000000000..a85e069b8 --- /dev/null +++ b/tests/Feature/Plugins/User/Contents/ContentsDefaultBucketRolesFeatureTest.php @@ -0,0 +1,84 @@ +seed(); + } + + /** + * バケツ未作成の権限画面では、サイト管理の初期値をチェック状態に反映すること。 + */ + public function testEditBucketsRolesShowsSiteDefaultsBeforeBucketExists(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame] = $this->createPluginFrame('contents'); + $this->setDefaultPostRoleConfigs(1, 0); + + $response = $this->actingAs($admin)->get("/plugin/contents/editBucketsRoles/{$page->id}/{$frame->id}"); + + $response->assertOk(); + $response->assertSee('id="role_article_post" checked="checked"', false); + $response->assertDontSee('id="role_reporter_post" checked="checked"', false); + } + + /** + * サイト管理の初期値が両方OFFなら、未作成バケツの画面でも未チェック表示になること。 + */ + public function testEditBucketsRolesShowsUncheckedWhenSiteDefaultsAreOff(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame] = $this->createPluginFrame('contents'); + $this->setDefaultPostRoleConfigs(0, 0); + + $response = $this->actingAs($admin)->get("/plugin/contents/editBucketsRoles/{$page->id}/{$frame->id}"); + + $response->assertOk(); + $response->assertDontSee('id="role_article_post" checked="checked"', false); + $response->assertDontSee('id="role_reporter_post" checked="checked"', false); + } + + /** + * 初回投稿で作られるバケツには、サイト管理の初期値どおりの投稿権限だけが作られること。 + */ + public function testFirstStoreCreatesBucketsRolesFromSiteDefaults(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame] = $this->createPluginFrame('contents'); + $this->setDefaultPostRoleConfigs(1, 0); + + $response = $this->actingAs($admin)->post("/redirect/plugin/contents/store/{$page->id}/{$frame->id}", [ + 'redirect_path' => url("/plugin/contents/edit/{$page->id}/{$frame->id}#frame-{$frame->id}"), + 'contents' => '初回投稿本文', + 'bucket_name' => '固定記事テスト', + ]); + + $response->assertStatus(302); + + $bucket = Buckets::query()->findOrFail($frame->fresh()->bucket_id); + $this->assertFrameUsesBucket($frame, $bucket); + $this->assertDefaultPostRolesForBucket($bucket, 1, 0); + } +} diff --git a/tests/Feature/Plugins/User/Databases/DatabasesDefaultBucketRolesFeatureTest.php b/tests/Feature/Plugins/User/Databases/DatabasesDefaultBucketRolesFeatureTest.php new file mode 100644 index 000000000..7b9c7a15d --- /dev/null +++ b/tests/Feature/Plugins/User/Databases/DatabasesDefaultBucketRolesFeatureTest.php @@ -0,0 +1,56 @@ +seed(); + } + + /** + * データベース新規作成では、サイト管理の初期値どおりの投稿権限が作られること。 + */ + public function testSaveBucketsCreatesDefaultRolesOnDatabaseCreation(): void + { + $this->assertSaveBucketsCreatesDefaultRoles('databases', [ + 'databases_name' => 'データベーステスト', + 'copy_databases_id' => '', + 'posted_role_display_control_flag' => 0, + 'search_results_empty_message' => '', + 'use_like' => 0, + 'like_button_name' => '', + 'mail_send_flag' => 0, + 'mail_send_address' => '', + 'user_mail_send_flag' => 0, + 'from_mail_name' => '', + 'mail_subject' => '', + 'mail_databaseat' => '', + 'data_save_flag' => 0, + 'after_message' => '', + 'numbering_use_flag' => 0, + 'numbering_prefix' => '', + 'save_searched_word' => 0, + 'full_text_search' => 0, + ]); + } +} diff --git a/tests/Feature/Plugins/User/DefaultBucketRolesFeatureTestTrait.php b/tests/Feature/Plugins/User/DefaultBucketRolesFeatureTestTrait.php new file mode 100644 index 000000000..d5dca21a7 --- /dev/null +++ b/tests/Feature/Plugins/User/DefaultBucketRolesFeatureTestTrait.php @@ -0,0 +1,146 @@ +createContentAdminUser(); + [$page, $frame] = $this->createPluginFrame($plugin_name); + $this->setDefaultPostRoleConfigs($article_flag, $reporter_flag); + + $response = $this->actingAs($admin)->post( + "/redirect/plugin/{$plugin_name}/saveBuckets/{$page->id}/{$frame->id}", + array_merge( + [ + 'redirect_path' => url("/plugin/{$plugin_name}/createBuckets/{$page->id}/{$frame->id}#frame-{$frame->id}"), + ], + $payload + ) + ); + + $this->assertContains($response->getStatusCode(), [200, 302]); + + $bucket = Buckets::query() + ->where('plugin_name', $plugin_name) + ->latest('id') + ->firstOrFail(); + + $this->assertFrameUsesBucket($frame, $bucket); + $this->assertDefaultPostRolesForBucket($bucket, $article_flag, $reporter_flag); + } + + /** + * フレームが作成されたバケツを表示対象にしていることを検証する。 + */ + protected function assertFrameUsesBucket(Frame $frame, Buckets $bucket): void + { + $this->assertDatabaseHas('frames', [ + 'id' => $frame->id, + 'bucket_id' => $bucket->id, + ]); + } + + /** + * 指定バケツに、サイト管理の初期値どおりの投稿権限が作られたことを検証する。 + */ + protected function assertDefaultPostRolesForBucket(Buckets $bucket, int $article_flag, int $reporter_flag): void + { + $this->assertDefaultPostRoleForBucket($bucket, 'role_article', $article_flag); + $this->assertDefaultPostRoleForBucket($bucket, 'role_reporter', $reporter_flag); + } + + /** + * 指定ロールの投稿権限が、初期値ONなら存在し、OFFなら存在しないことを検証する。 + */ + private function assertDefaultPostRoleForBucket(Buckets $bucket, string $role, int $post_flag): void + { + if ($post_flag === 1) { + $this->assertDatabaseHas('buckets_roles', [ + 'buckets_id' => $bucket->id, + 'role' => $role, + 'post_flag' => 1, + 'approval_flag' => 0, + ]); + return; + } + + $this->assertDatabaseMissing('buckets_roles', [ + 'buckets_id' => $bucket->id, + 'role' => $role, + ]); + } + + /** + * コンテンツ管理者権限を持つユーザーを作成する。 + */ + protected function createContentAdminUser(): User + { + $user = User::factory()->create(); + + UsersRoles::factory()->create([ + 'users_id' => $user->id, + 'target' => 'base', + 'role_name' => 'role_article_admin', + 'role_value' => 1, + ]); + + return $user; + } + + /** + * バケツ未作成のプラグインフレームを作成する。 + * + * @return array{0: \App\Models\Common\Page, 1: \App\Models\Common\Frame} + */ + protected function createPluginFrame(string $plugin_name): array + { + $page = Page::factory()->create(); + $frame = Frame::create([ + 'page_id' => $page->id, + 'area_id' => 2, + 'plugin_name' => $plugin_name, + 'bucket_id' => null, + 'template' => 'default', + 'display_sequence' => 1, + ]); + + return [$page, $frame]; + } + + /** + * 新規バケツ用の投稿権限Configを保存する。 + */ + protected function setDefaultPostRoleConfigs(int $article_flag, int $reporter_flag): void + { + Configs::updateOrCreate( + ['name' => 'new_bucket_role_article_post_flag'], + ['category' => 'general', 'value' => $article_flag] + ); + Configs::updateOrCreate( + ['name' => 'new_bucket_role_reporter_post_flag'], + ['category' => 'general', 'value' => $reporter_flag] + ); + } +} diff --git a/tests/Feature/Plugins/User/Faqs/FaqsDefaultBucketRolesFeatureTest.php b/tests/Feature/Plugins/User/Faqs/FaqsDefaultBucketRolesFeatureTest.php new file mode 100644 index 000000000..d7fdb134c --- /dev/null +++ b/tests/Feature/Plugins/User/Faqs/FaqsDefaultBucketRolesFeatureTest.php @@ -0,0 +1,45 @@ +seed(); + } + + /** + * FAQ新規作成では、サイト管理の初期値どおりの投稿権限が作られること。 + */ + public function testSaveBucketsCreatesDefaultRolesOnFaqCreation(): void + { + $this->assertSaveBucketsCreatesDefaultRoles('faqs', [ + 'faqs_id' => '', + 'faq_name' => 'FAQテスト', + 'view_count' => 10, + 'rss' => 0, + 'rss_count' => 0, + 'sequence_conditions' => 0, + 'display_posted_at_flag' => 0, + ], 1, 0); + } +} diff --git a/tests/Feature/Plugins/User/Photoalbums/PhotoalbumsDefaultBucketRolesFeatureTest.php b/tests/Feature/Plugins/User/Photoalbums/PhotoalbumsDefaultBucketRolesFeatureTest.php new file mode 100644 index 000000000..f0d5d1cfd --- /dev/null +++ b/tests/Feature/Plugins/User/Photoalbums/PhotoalbumsDefaultBucketRolesFeatureTest.php @@ -0,0 +1,42 @@ +seed(); + } + + /** + * フォトアルバム新規作成では、サイト管理の初期値どおりの投稿権限が作られること。 + */ + public function testSaveBucketsCreatesDefaultRolesOnPhotoalbumCreation(): void + { + $this->assertSaveBucketsCreatesDefaultRoles('photoalbums', [ + 'name' => 'フォトアルバムテスト', + 'image_upload_max_size' => '2048', + 'image_upload_max_px' => 'asis', + 'video_upload_max_size' => '2048', + ]); + } +} diff --git a/tests/Feature/Plugins/User/Reservations/ReservationsDefaultBucketRolesFeatureTest.php b/tests/Feature/Plugins/User/Reservations/ReservationsDefaultBucketRolesFeatureTest.php new file mode 100644 index 000000000..3f2b3d9d4 --- /dev/null +++ b/tests/Feature/Plugins/User/Reservations/ReservationsDefaultBucketRolesFeatureTest.php @@ -0,0 +1,40 @@ +seed(); + } + + /** + * 施設予約新規作成では、サイト管理の初期値どおりの投稿権限が作られること。 + */ + public function testSaveBucketsCreatesDefaultRolesOnReservationCreation(): void + { + $this->assertSaveBucketsCreatesDefaultRoles('reservations', [ + 'reservations_id' => '', + 'reservation_name' => '施設予約テスト', + ]); + } +} diff --git a/tests/Feature/Plugins/User/Slideshows/SlideshowsDefaultBucketRolesFeatureTest.php b/tests/Feature/Plugins/User/Slideshows/SlideshowsDefaultBucketRolesFeatureTest.php new file mode 100644 index 000000000..77d857a50 --- /dev/null +++ b/tests/Feature/Plugins/User/Slideshows/SlideshowsDefaultBucketRolesFeatureTest.php @@ -0,0 +1,44 @@ +seed(); + } + + /** + * スライドショー新規作成では、サイト管理の初期値どおりの投稿権限が作られること。 + */ + public function testSaveBucketsCreatesDefaultRolesOnSlideshowCreation(): void + { + $this->assertSaveBucketsCreatesDefaultRoles('slideshows', [ + 'slideshows_name' => 'スライドショーテスト', + 'control_display_flag' => 0, + 'indicators_display_flag' => 0, + 'fade_use_flag' => 0, + 'image_interval' => 5000, + 'height' => '', + ]); + } +} diff --git a/tests/Unit/Models/Common/BucketsDefaultPostRolesTest.php b/tests/Unit/Models/Common/BucketsDefaultPostRolesTest.php new file mode 100644 index 000000000..a501dff56 --- /dev/null +++ b/tests/Unit/Models/Common/BucketsDefaultPostRolesTest.php @@ -0,0 +1,283 @@ +clearSharedConfigsFromRequest(); + } + + /** + * Config未登録の環境では既存挙動を保ち、初期権限を追加しないこと。 + */ + public function testInitializeDefaultPostRolesDoesNotCreateRolesWhenConfigIsMissing(): void + { + $bucket = $this->createBucket(); + + $bucket->initializeDefaultPostRoles(); + + $this->assertDatabaseCount('buckets_roles', 0); + } + + /** + * モデレータだけONなら、そのロールだけに投稿権限を初期投入すること。 + */ + public function testInitializeDefaultPostRolesCreatesOnlyArticleRoleWhenEnabled(): void + { + $bucket = $this->createBucket(); + $this->setDefaultPostRoleConfigs(1, 0); + + $bucket->initializeDefaultPostRoles(); + + $this->assertDatabaseHas('buckets_roles', [ + 'buckets_id' => $bucket->id, + 'role' => 'role_article', + 'post_flag' => 1, + 'approval_flag' => 0, + ]); + $this->assertDatabaseMissing('buckets_roles', [ + 'buckets_id' => $bucket->id, + 'role' => 'role_reporter', + ]); + } + + /** + * 編集者だけONなら、そのロールだけに投稿権限を初期投入すること。 + */ + public function testInitializeDefaultPostRolesCreatesOnlyReporterRoleWhenEnabled(): void + { + $bucket = $this->createBucket(); + $this->setDefaultPostRoleConfigs(0, 1); + + $bucket->initializeDefaultPostRoles(); + + $this->assertDatabaseHas('buckets_roles', [ + 'buckets_id' => $bucket->id, + 'role' => 'role_reporter', + 'post_flag' => 1, + 'approval_flag' => 0, + ]); + $this->assertDatabaseMissing('buckets_roles', [ + 'buckets_id' => $bucket->id, + 'role' => 'role_article', + ]); + } + + /** + * 両方ONなら、対象2ロールの初期権限をまとめて作成すること。 + */ + public function testInitializeDefaultPostRolesCreatesBothRolesWhenEnabled(): void + { + $bucket = $this->createBucket(); + $this->setDefaultPostRoleConfigs(1, 1); + + $bucket->initializeDefaultPostRoles(); + + $this->assertDatabaseCount('buckets_roles', 2); + $this->assertDatabaseHas('buckets_roles', [ + 'buckets_id' => $bucket->id, + 'role' => 'role_article', + 'post_flag' => 1, + 'approval_flag' => 0, + ]); + $this->assertDatabaseHas('buckets_roles', [ + 'buckets_id' => $bucket->id, + 'role' => 'role_reporter', + 'post_flag' => 1, + 'approval_flag' => 0, + ]); + } + + /** + * 同じ初期化を繰り返しても、権限レコードが重複しないこと。 + */ + public function testInitializeDefaultPostRolesIsIdempotent(): void + { + $bucket = $this->createBucket(); + $this->setDefaultPostRoleConfigs(1, 1); + + $bucket->initializeDefaultPostRoles(); + $bucket->initializeDefaultPostRoles(); + + $this->assertDatabaseCount('buckets_roles', 2); + } + + /** + * 既存のBucketsRolesがある場合は、その設定を勝手に上書きしないこと。 + */ + public function testInitializeDefaultPostRolesDoesNotOverwriteExistingRole(): void + { + $bucket = $this->createBucket(); + $this->setDefaultPostRoleConfigs(1, 0); + + BucketsRoles::create([ + 'buckets_id' => $bucket->id, + 'role' => 'role_article', + 'post_flag' => 0, + 'approval_flag' => 1, + ]); + + $bucket->initializeDefaultPostRoles(); + + $this->assertDatabaseCount('buckets_roles', 1); + $this->assertDatabaseHas('buckets_roles', [ + 'buckets_id' => $bucket->id, + 'role' => 'role_article', + 'post_flag' => 0, + 'approval_flag' => 1, + ]); + } + + /** + * 共通作成APIでは、投稿権限設定を持つプラグインだけ初期権限を作成すること。 + */ + public function testCreateWithDefaultPostRolesAppliesOnlyTargetPlugin(): void + { + $this->setDefaultPostRoleConfigs(1, 1); + + $target_bucket = Buckets::createWithDefaultPostRoles([ + 'bucket_name' => '対象掲示板', + 'plugin_name' => 'bbses', + ]); + $non_target_bucket = Buckets::createWithDefaultPostRoles([ + 'bucket_name' => '対象外リンクリスト', + 'plugin_name' => 'linklists', + ]); + + $this->assertDatabaseHas('buckets_roles', [ + 'buckets_id' => $target_bucket->id, + 'role' => 'role_article', + 'post_flag' => 1, + ]); + $this->assertDatabaseHas('buckets_roles', [ + 'buckets_id' => $target_bucket->id, + 'role' => 'role_reporter', + 'post_flag' => 1, + ]); + $this->assertDatabaseMissing('buckets_roles', [ + 'buckets_id' => $non_target_bucket->id, + ]); + } + + /** + * 共通更新APIでは、新規作成時だけ初期権限を作成し、既存バケツ更新では作成しないこと。 + */ + public function testUpdateOrCreateWithDefaultPostRolesAppliesOnlyWhenCreated(): void + { + $this->setDefaultPostRoleConfigs(1, 0); + + $bucket = Buckets::updateOrCreateWithDefaultPostRoles( + ['id' => null], + ['bucket_name' => '新規ブログ', 'plugin_name' => 'blogs'] + ); + BucketsRoles::query()->delete(); + + Buckets::updateOrCreateWithDefaultPostRoles( + ['id' => $bucket->id], + ['bucket_name' => '更新ブログ', 'plugin_name' => 'blogs'] + ); + + $this->assertDatabaseCount('buckets_roles', 0); + } + + /** + * 対象プラグインの判定は、権限設定タブを持つ代表プラグインだけを対象にすること。 + */ + public function testIsDefaultPostRoleTargetPlugin(): void + { + $this->assertTrue(Buckets::isDefaultPostRoleTargetPlugin('bbses')); + $this->assertTrue(Buckets::isDefaultPostRoleTargetPlugin('databases')); + $this->assertFalse(Buckets::isDefaultPostRoleTargetPlugin('learningtasks')); + $this->assertFalse(Buckets::isDefaultPostRoleTargetPlugin('linklists')); + $this->assertFalse(Buckets::isDefaultPostRoleTargetPlugin('whatsnews')); + $this->assertFalse(Buckets::isDefaultPostRoleTargetPlugin(null)); + } + + /** + * Buckets削除時は関連するBucketsRolesも同時に片づけること。 + */ + public function testDestroyRemovesRelatedBucketsRoles(): void + { + $bucket = $this->createBucket(); + BucketsRoles::create([ + 'buckets_id' => $bucket->id, + 'role' => 'role_article', + 'post_flag' => 1, + 'approval_flag' => 0, + ]); + BucketsRoles::create([ + 'buckets_id' => $bucket->id, + 'role' => 'role_reporter', + 'post_flag' => 1, + 'approval_flag' => 0, + ]); + + Buckets::destroy($bucket->id); + + $this->assertDatabaseMissing('buckets_roles', [ + 'buckets_id' => $bucket->id, + 'role' => 'role_article', + ]); + $this->assertDatabaseMissing('buckets_roles', [ + 'buckets_id' => $bucket->id, + 'role' => 'role_reporter', + ]); + } + + /** + * テスト対象のバケツを1件作成する。 + */ + private function createBucket(): Buckets + { + return Buckets::factory()->create([ + 'plugin_name' => 'contents', + ]); + } + + /** + * 新規バケツ用の投稿権限Configを保存する。 + */ + private function setDefaultPostRoleConfigs(int $article_flag, int $reporter_flag): void + { + Configs::updateOrCreate( + ['name' => 'new_bucket_role_article_post_flag'], + ['category' => 'general', 'value' => $article_flag] + ); + Configs::updateOrCreate( + ['name' => 'new_bucket_role_reporter_post_flag'], + ['category' => 'general', 'value' => $reporter_flag] + ); + + $this->clearSharedConfigsFromRequest(); + } + + /** + * Request属性の共有Configを外し、DBフォールバックの条件をそろえる。 + */ + private function clearSharedConfigsFromRequest(): void + { + app(Request::class)->attributes->remove('configs'); + } +} From 51af3b24821ca055ba02db529de7bbdec0aeb187 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Thu, 14 May 2026 15:59:18 +0900 Subject: [PATCH 08/49] fix(site): improve base settings navigation --- .../views/plugins/manage/site/site.blade.php | 495 +++++++++++------- .../SiteManageNewBucketDefaultRolesTest.php | 3 +- 2 files changed, 309 insertions(+), 189 deletions(-) diff --git a/resources/views/plugins/manage/site/site.blade.php b/resources/views/plugins/manage/site/site.blade.php index 763143c01..ac1f447e0 100644 --- a/resources/views/plugins/manage/site/site.blade.php +++ b/resources/views/plugins/manage/site/site.blade.php @@ -25,194 +25,233 @@ {{csrf_field()}} - {{-- サイト名 --}} -
- - - サイト名(各ページで上書き可能) -
+ @php + $site_setting_sections = [ + ['id' => 'site-settings-common', 'label' => 'よく使う設定'], + ['id' => 'site-settings-design', 'label' => '外観・ヘッダー'], + ['id' => 'site-settings-login', 'label' => 'ログイン'], + ['id' => 'site-settings-mypage', 'label' => 'マイページ'], + ['id' => 'site-settings-display-limit', 'label' => '表示・操作制限'], + ['id' => 'site-settings-plugin-permission', 'label' => 'プラグインの権限設定'], + ]; + @endphp - {{-- 基本テーマ --}} -
- - -
- - {{-- 追加テーマ --}} -
- - - 基本テーマとは別のテーマを追加で読み込みます。スタイルの読み込み順は追加テーマの方が後になる為、スタイル競合時は追加テーマのものが優先されます。 -
+
+ + - @php - $layout_default = config('connect.BASE_LAYOUT_DEFAULT'); - $base_layout_value = Configs::getConfigsValue($configs, 'base_layout', $layout_default); - $base_layout_value = $base_layout_value ?: $layout_default; - @endphp - {{-- 基本レイアウト --}} -
- -
-
- @if (old('base_layout', $base_layout_value) == '0|0|0|0') - - @else - - @endif - -
-
- @if (old('base_layout', $base_layout_value) == '0|0|0|1') - - @else - - @endif - -
-
- @if (old('base_layout', $base_layout_value) == '0|0|1|0') - - @else - - @endif - -
-
- @if (old('base_layout', $base_layout_value) == '0|0|1|1') - - @else - - @endif - -
-
- @if (old('base_layout', $base_layout_value) == '0|1|0|0') - - @else - - @endif - -
-
- @if (old('base_layout', $base_layout_value) == '0|1|0|1') - - @else - - @endif - -
-
- @if (old('base_layout', $base_layout_value) == '0|1|1|0') - - @else - - @endif - -
-
- @if (old('base_layout', $base_layout_value) == '0|1|1|1') - - @else - - @endif - -
-
- @if (old('base_layout', $base_layout_value) == '1|0|0|0') - - @else - - @endif - -
-
- @if (old('base_layout', $base_layout_value) == '1|0|0|1') - - @else - - @endif - -
-
- @if (old('base_layout', $base_layout_value) == '1|0|1|0') - - @else - - @endif - -
-
- @if (old('base_layout', $base_layout_value) == '1|0|1|1') - - @else - - @endif - -
-
- @if (old('base_layout', $base_layout_value) == '1|1|0|0') - - @else - - @endif - -
-
- @if (old('base_layout', $base_layout_value) == '1|1|0|1') - - @else - - @endif - -
-
- @if (old('base_layout', $base_layout_value) == '1|1|1|0') - - @else - - @endif - -
-
- @if (old('base_layout', $base_layout_value) == '1|1|1|1') - - @else - - @endif - -
-
- 全ページに適用する基本レイアウトです。各ページのレイアウト設定で上書きできます。 -
+
+
+
よく使う設定
+ + {{-- サイト名 --}} +
+ + + サイト名(各ページで上書き可能) +
+ + {{-- 基本テーマ --}} +
+ + +
-
+ {{-- 追加テーマ --}} +
+ + + 基本テーマとは別のテーマを追加で読み込みます。スタイルの読み込み順は追加テーマの方が後になる為、スタイル競合時は追加テーマのものが優先されます。 +
+ + @php + $layout_default = config('connect.BASE_LAYOUT_DEFAULT'); + $base_layout_value = Configs::getConfigsValue($configs, 'base_layout', $layout_default); + $base_layout_value = $base_layout_value ?: $layout_default; + @endphp + {{-- 基本レイアウト --}} +
+ +
+
+ @if (old('base_layout', $base_layout_value) == '0|0|0|0') + + @else + + @endif + +
+
+ @if (old('base_layout', $base_layout_value) == '0|0|0|1') + + @else + + @endif + +
+
+ @if (old('base_layout', $base_layout_value) == '0|0|1|0') + + @else + + @endif + +
+
+ @if (old('base_layout', $base_layout_value) == '0|0|1|1') + + @else + + @endif + +
+
+ @if (old('base_layout', $base_layout_value) == '0|1|0|0') + + @else + + @endif + +
+
+ @if (old('base_layout', $base_layout_value) == '0|1|0|1') + + @else + + @endif + +
+
+ @if (old('base_layout', $base_layout_value) == '0|1|1|0') + + @else + + @endif + +
+
+ @if (old('base_layout', $base_layout_value) == '0|1|1|1') + + @else + + @endif + +
+
+ @if (old('base_layout', $base_layout_value) == '1|0|0|0') + + @else + + @endif + +
+
+ @if (old('base_layout', $base_layout_value) == '1|0|0|1') + + @else + + @endif + +
+
+ @if (old('base_layout', $base_layout_value) == '1|0|1|0') + + @else + + @endif + +
+
+ @if (old('base_layout', $base_layout_value) == '1|0|1|1') + + @else + + @endif + +
+
+ @if (old('base_layout', $base_layout_value) == '1|1|0|0') + + @else + + @endif + +
+
+ @if (old('base_layout', $base_layout_value) == '1|1|0|1') + + @else + + @endif + +
+
+ @if (old('base_layout', $base_layout_value) == '1|1|1|0') + + @else + + @endif + +
+
+ @if (old('base_layout', $base_layout_value) == '1|1|1|1') + + @else + + @endif + +
+
+ 全ページに適用する基本レイアウトです。各ページのレイアウト設定で上書きできます。 +
+
+ +
+
外観・ヘッダー
+ +
@php $placeholder_message = 'HTMLカラーコードを入力'; @endphp @@ -356,6 +395,10 @@ スマートフォンでヘッダーバーのメニューを表示する時、スマートフォン画面の高さ以上にメニューが増えると、ヘッダーバーが固定される関係でメニューがスクロールしないため、画面外のメニューが押せなくなります。
+
+ +
+
ログイン
{{-- ログインリンクの表示 --}}
@@ -455,6 +498,10 @@ class="custom-control-input" @include('plugins.common.errors_inline', ['name' => 'base_login_redirect_select_page'])
+
+ +
+
マイページ
{{-- マイページ --}}
@@ -497,6 +544,10 @@ class="custom-control-input" マイページ(/mypage)の下部に表示するお知らせ(HTML可)
+
+ +
+
表示・操作制限
{{-- 画像の保存機能の無効化 --}}
@@ -550,14 +601,18 @@ class="custom-control-input" @endforeach
+
+ +
+
プラグインの権限設定
- {{-- プラグイン新規作成時の投稿権限 --}} + {{-- 新規作成時の投稿権限 --}}
- -

+ + 掲示板やブログなどを新しく作成したとき、投稿を許可する権限の初期値です。 既存のプラグイン設定は変更されません。 -

+
@if(Configs::getConfigsValueAndOld($configs, "new_bucket_role_article_post_flag", 0) == 1) @@ -578,11 +633,14 @@ class="custom-control-input"
作成後は、各プラグインの権限設定で個別に変更できます。
+
{{-- Submitボタン --}} -
+
+
+
@@ -595,6 +653,67 @@ class="custom-control-input" } }, }).mount('#app'); + + (function() { + const sections = Array.from(document.querySelectorAll('.site-settings-section')); + const anchors = Array.from(document.querySelectorAll('.site-settings-anchor')); + + if (!sections.length || !anchors.length) { + return; + } + + // 現在位置に対応する目次リンクだけを選択状態にする。 + const activate = function(section_id) { + anchors.forEach(function(anchor) { + const is_active = anchor.dataset.targetSection === section_id; + anchor.classList.toggle('active', is_active); + + if (is_active) { + anchor.setAttribute('aria-current', 'true'); + } else { + anchor.removeAttribute('aria-current'); + } + }); + }; + + // 画面上部から一定距離を過ぎた最後のセクションを現在位置として扱う。 + const getCurrentSectionId = function() { + const scroll_offset = 120; + let current_section_id = sections[0].id; + + sections.forEach(function(section) { + if (section.getBoundingClientRect().top <= scroll_offset) { + current_section_id = section.id; + } + }); + + return current_section_id; + }; + + // スクロールイベントが連続しても、描画更新は1フレームに1回に抑える。 + let ticking = false; + const updateActiveAnchor = function() { + activate(getCurrentSectionId()); + ticking = false; + }; + + const requestUpdate = function() { + if (!ticking) { + window.requestAnimationFrame(updateActiveAnchor); + ticking = true; + } + }; + + anchors.forEach(function(anchor) { + anchor.addEventListener('click', function() { + activate(anchor.dataset.targetSection); + }); + }); + + window.addEventListener('scroll', requestUpdate, { passive: true }); + window.addEventListener('resize', requestUpdate); + updateActiveAnchor(); + })(); @endsection diff --git a/tests/Feature/Plugins/Manage/SiteManage/SiteManageNewBucketDefaultRolesTest.php b/tests/Feature/Plugins/Manage/SiteManage/SiteManageNewBucketDefaultRolesTest.php index c606d4627..a28f0062d 100644 --- a/tests/Feature/Plugins/Manage/SiteManage/SiteManageNewBucketDefaultRolesTest.php +++ b/tests/Feature/Plugins/Manage/SiteManage/SiteManageNewBucketDefaultRolesTest.php @@ -44,7 +44,8 @@ public function testIndexShowsBothCheckboxesUncheckedWhenConfigsAreMissing(): vo $response = $this->actingAs($admin)->get('/manage/site'); $response->assertOk(); - $response->assertSee('プラグイン新規作成時の投稿権限'); + $response->assertSee('プラグインの権限設定'); + $response->assertSee('新規作成時の投稿権限'); $response->assertDontSee('id="new_bucket_role_article_post_flag" class="custom-control-input" checked="checked"', false); $response->assertDontSee('id="new_bucket_role_reporter_post_flag" class="custom-control-input" checked="checked"', false); } From 919f8a8c2437d9703ea79006ec9ab103a98b3e07 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Thu, 14 May 2026 16:27:12 +0900 Subject: [PATCH 09/49] fix(whatsnews): decode html entities in excerpts --- .../User/Whatsnews/WhatsnewsPlugin.php | 20 ++++++++++++++----- .../whatsnews/card_04/whatsnews.blade.php | 7 +------ .../whatsnews/default/whatsnews.blade.php | 7 +------ .../user/whatsnews/onerow/whatsnews.blade.php | 7 +------ 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/app/Plugins/User/Whatsnews/WhatsnewsPlugin.php b/app/Plugins/User/Whatsnews/WhatsnewsPlugin.php index b6cff7575..e81add069 100644 --- a/app/Plugins/User/Whatsnews/WhatsnewsPlugin.php +++ b/app/Plugins/User/Whatsnews/WhatsnewsPlugin.php @@ -250,7 +250,8 @@ private function getWhatsnews($whatsnews_frame, $method = null) } // 記事詳細から、最初の画像を抜き出して設定する。 - $whatsnews = $this->addWhatsnewsValues($whatsnews); + $post_detail_length = FrameConfig::getConfigValueAndOld($this->frame_configs, WhatsnewFrameConfig::post_detail_length); + $whatsnews = $this->addWhatsnewsValues($whatsnews, $post_detail_length); // 一旦オブジェクト変数へ。(Singleton のため。フレーム表示確認でコアが使用する) $this->whatsnews_results = array($whatsnews, $link_pattern, $link_base); @@ -314,21 +315,30 @@ private function addWhatsnewsValue($whatsnew, $post_detail_length = null) } // タイトルのタグを取り除き, データベース、ウィジウィグ型のタイトル指定に対応 - $whatsnew->post_title_strip_tags = strip_tags($whatsnew->post_title); + $whatsnew->post_title_strip_tags = $this->stripTagsAndDecodeEntities($whatsnew->post_title); // タグを取り除き、指定に応じて文字数制限した本文 + $post_detail_strip_tags = $this->stripTagsAndDecodeEntities($whatsnew->post_detail); if ($post_detail_length) { - $whatsnew->post_detail_strip_tags = mb_substr(strip_tags($whatsnew->post_detail), 0, $post_detail_length); - if (mb_strlen(strip_tags($whatsnew->post_detail)) > $post_detail_length) { + $whatsnew->post_detail_strip_tags = mb_substr($post_detail_strip_tags, 0, $post_detail_length); + if (mb_strlen($post_detail_strip_tags) > $post_detail_length) { $whatsnew->post_detail_strip_tags = $whatsnew->post_detail_strip_tags . '...'; } } else { - $whatsnew->post_detail_strip_tags = strip_tags($whatsnew->post_detail); + $whatsnew->post_detail_strip_tags = $post_detail_strip_tags; } return $whatsnew; } + /** + * 新着表示用にタグを除去し、本文中のHTMLエンティティを文字として扱える形に戻す。 + */ + private function stripTagsAndDecodeEntities(?string $value): string + { + return html_entity_decode(strip_tags($value ?? ''), ENT_QUOTES | ENT_HTML5, 'UTF-8'); + } + private function buildQueryGetWhatsnews($whatsnews_frame, $union_sqls) { // ベースの新着DUAL(ダミーテーブル) diff --git a/resources/views/plugins/user/whatsnews/card_04/whatsnews.blade.php b/resources/views/plugins/user/whatsnews/card_04/whatsnews.blade.php index 44ddbbd6d..bf05cfe5a 100755 --- a/resources/views/plugins/user/whatsnews/card_04/whatsnews.blade.php +++ b/resources/views/plugins/user/whatsnews/card_04/whatsnews.blade.php @@ -112,12 +112,7 @@ {{-- 本文 --}} @if (FrameConfig::getConfigValueAndOld($frame_configs, WhatsnewFrameConfig::post_detail))
- @if (FrameConfig::getConfigValueAndOld($frame_configs, WhatsnewFrameConfig::post_detail_length) == 0 || - mb_strlen(strip_tags($whatsnew->post_detail)) <= FrameConfig::getConfigValueAndOld($frame_configs, WhatsnewFrameConfig::post_detail_length)) - {{ strip_tags($whatsnew->post_detail) }} - @else - {{ mb_substr(strip_tags($whatsnew->post_detail), 0, FrameConfig::getConfigValueAndOld($frame_configs, WhatsnewFrameConfig::post_detail_length)) }}... - @endif + {{ $whatsnew->post_detail_strip_tags }}
@endif diff --git a/resources/views/plugins/user/whatsnews/default/whatsnews.blade.php b/resources/views/plugins/user/whatsnews/default/whatsnews.blade.php index f194545b2..6f7b52e2b 100644 --- a/resources/views/plugins/user/whatsnews/default/whatsnews.blade.php +++ b/resources/views/plugins/user/whatsnews/default/whatsnews.blade.php @@ -63,12 +63,7 @@ {{-- 本文 --}} @if (FrameConfig::getConfigValueAndOld($frame_configs, WhatsnewFrameConfig::post_detail))
- @if (FrameConfig::getConfigValueAndOld($frame_configs, WhatsnewFrameConfig::post_detail_length) == 0 || - mb_strlen(strip_tags($whatsnew->post_detail)) <= FrameConfig::getConfigValueAndOld($frame_configs, WhatsnewFrameConfig::post_detail_length)) - {{ strip_tags($whatsnew->post_detail) }} - @else - {{ mb_substr(strip_tags($whatsnew->post_detail), 0, FrameConfig::getConfigValueAndOld($frame_configs, WhatsnewFrameConfig::post_detail_length)) }}... - @endif + {{ $whatsnew->post_detail_strip_tags }}
@endif diff --git a/resources/views/plugins/user/whatsnews/onerow/whatsnews.blade.php b/resources/views/plugins/user/whatsnews/onerow/whatsnews.blade.php index 145e3d2b1..aad720b7b 100644 --- a/resources/views/plugins/user/whatsnews/onerow/whatsnews.blade.php +++ b/resources/views/plugins/user/whatsnews/onerow/whatsnews.blade.php @@ -90,12 +90,7 @@ {{-- 本文 --}} @if (FrameConfig::getConfigValueAndOld($frame_configs, WhatsnewFrameConfig::post_detail))
- @if (FrameConfig::getConfigValueAndOld($frame_configs, WhatsnewFrameConfig::post_detail_length) == 0 || - mb_strlen(strip_tags($whatsnew->post_detail)) <= FrameConfig::getConfigValueAndOld($frame_configs, WhatsnewFrameConfig::post_detail_length)) - {{ strip_tags($whatsnew->post_detail) }} - @else - {{ mb_substr(strip_tags($whatsnew->post_detail), 0, FrameConfig::getConfigValueAndOld($frame_configs, WhatsnewFrameConfig::post_detail_length)) }}... - @endif + {{ $whatsnew->post_detail_strip_tags }}
@endif From b51c3826222792832db5baf5305007462f1225d5 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Thu, 14 May 2026 16:50:36 +0900 Subject: [PATCH 10/49] fix(menus): show tree children before menu settings saved --- app/Plugins/User/Menus/MenusPlugin.php | 17 ++++++- .../Menus/MenusModeratorEditFeatureTest.php | 49 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/app/Plugins/User/Menus/MenusPlugin.php b/app/Plugins/User/Menus/MenusPlugin.php index 624f64f2a..70d88a0cb 100644 --- a/app/Plugins/User/Menus/MenusPlugin.php +++ b/app/Plugins/User/Menus/MenusPlugin.php @@ -87,7 +87,7 @@ public function declareRole() public function index($request, $page_id, $frame_id) { // メニュー - $menu = Menu::where('frame_id', $frame_id)->first(); + $menu = Menu::where('frame_id', $frame_id)->first() ?? $this->getDefaultMenu($frame_id); //Log::debug(json_encode( $menu, JSON_UNESCAPED_UNICODE)); // ページに対する権限 @@ -233,6 +233,21 @@ private function isModeratorEditAllowed(): bool return (bool) FrameConfig::getConfigValue($this->frame_configs, MenuFrameConfig::menu_allow_moderator_edit, 0); } + /** + * メニュー設定が未保存のフレームでも、表示時は初期設定で扱う。 + */ + private function getDefaultMenu($frame_id): Menu + { + return new Menu([ + 'frame_id' => $frame_id, + 'select_flag' => 0, + 'page_ids' => '', + 'folder_close_font' => 0, + 'folder_open_font' => 0, + 'indent_font' => 0, + ]); + } + /** * メニュー編集権限の判定 */ diff --git a/tests/Feature/Plugins/User/Menus/MenusModeratorEditFeatureTest.php b/tests/Feature/Plugins/User/Menus/MenusModeratorEditFeatureTest.php index 278c2947d..3e45a0439 100644 --- a/tests/Feature/Plugins/User/Menus/MenusModeratorEditFeatureTest.php +++ b/tests/Feature/Plugins/User/Menus/MenusModeratorEditFeatureTest.php @@ -11,6 +11,10 @@ use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; +/** + * メニュープラグインの編集権限と、表示設定が保存されていない初期状態の公開表示を検証する。 + * 画面経由の保存結果と、公開メニューに出る利用者視点の表示をFeatureテストで守る。 + */ class MenusModeratorEditFeatureTest extends TestCase { use RefreshDatabase; @@ -270,4 +274,49 @@ public function testEditButtonVisibilityReflectsPermissions(): void $permitted_response->assertSee('menu-edit-button'); $permitted_response->assertDontSee('設定メニュー'); } + + /** + * ディレクトリ展開式は、メニュー設定を保存していない新規フレームでも配下ページの存在と展開状態を示す。 + */ + public function testOpenCurrentTreeShowsChildrenWithDefaultSettingsWhenMenuIsNotSaved(): void + { + $parent = $this->createPublicPage('親ページ', '/parent-page', $this->page); + $this->createPublicPage('子ページ', '/parent-page/child-page', $parent); + Frame::whereKey($this->frame->id)->update(['template' => 'opencurrenttree']); + $this->frame = $this->frame->fresh(); + + $root_response = $this->get($this->index_url); + $root_response->assertStatus(200); + $root_response->assertSee('親ページ'); + $root_response->assertSee('fas fa-plus', false); + $root_response->assertDontSee('子ページ'); + + Frame::whereKey($this->frame->id)->update(['page_id' => $parent->id]); + $this->frame = $this->frame->fresh(); + + $parent_response = $this->get("/plugin/menus/index/{$parent->id}/{$this->frame->id}"); + $parent_response->assertStatus(200); + $parent_response->assertSee('親ページ'); + $parent_response->assertSee('子ページ'); + $parent_response->assertSee('fas fa-minus', false); + + $this->assertNull(Menu::where('frame_id', $this->frame->id)->first()); + } + + /** + * メニュー表示対象のページ階層を作る。 + */ + private function createPublicPage(string $name, string $permanent_link, Page $parent): Page + { + $page = Page::factory()->create([ + 'page_name' => $name, + 'permanent_link' => $permanent_link, + 'base_display_flag' => 1, + 'membership_flag' => 0, + ]); + + $page->appendToNode($parent)->save(); + + return $page->fresh(); + } } From 9f8fc7128eb0f27f99c826a5a83686bfd11c3c21 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Fri, 15 May 2026 17:58:46 +0900 Subject: [PATCH 11/49] feat(uploadfile): add detailed filtering and sorting --- .../UploadfileManage/UploadfileManage.php | 245 ++++++++++++++-- .../plugins/manage/uploadfile/index.blade.php | 103 ++++++- .../UploadfileManageSearchTest.php | 277 ++++++++++++++++++ 3 files changed, 591 insertions(+), 34 deletions(-) create mode 100644 tests/Feature/Plugins/Manage/UploadfileManage/UploadfileManageSearchTest.php diff --git a/app/Plugins/Manage/UploadfileManage/UploadfileManage.php b/app/Plugins/Manage/UploadfileManage/UploadfileManage.php index a8ed391a4..94682d4a4 100644 --- a/app/Plugins/Manage/UploadfileManage/UploadfileManage.php +++ b/app/Plugins/Manage/UploadfileManage/UploadfileManage.php @@ -9,6 +9,7 @@ use App\Models\Common\Uploads; use App\Models\Core\Configs; +use App\Models\Core\Plugins; use App\Utilities\Storage\StorageUsageCalculator; use App\Plugins\Manage\ManagePluginBase; @@ -36,6 +37,51 @@ class UploadfileManage extends ManagePluginBase */ private $allowed_per_page = [10, 50, 100]; + /** + * 検索条件として扱う項目 + */ + private $search_condition_keys = [ + 'client_original_name', + 'id', + 'size_from', + 'size_to', + 'size_unit', + 'page_name', + 'created_at_from', + 'created_at_to', + 'plugin_names', + 'sort', + ]; + + /** + * 並べ替えの許可された値 + */ + private $allowed_sorts = [ + 'id_asc', + 'id_desc', + 'client_original_name_asc', + 'client_original_name_desc', + 'size_asc', + 'size_desc', + 'created_at_asc', + 'created_at_desc', + 'plugin_name_asc', + 'plugin_name_desc', + 'page_name_asc', + 'page_name_desc', + 'download_count_desc', + 'play_count_desc', + ]; + + /** + * ファイルサイズ検索で許可する単位 + */ + private $allowed_size_units = [ + 'byte', + 'KB', + 'MB', + ]; + /** * 権限定義 */ @@ -83,34 +129,11 @@ public function index($request) ->leftJoin('plugins', 'plugins.plugin_name', '=', 'uploads.plugin_name') ->leftJoin('pages', 'pages.id', '=', 'uploads.page_id'); - if ($request->session()->has('search_condition.client_original_name')) { - $uploads_query->where('client_original_name', 'like', '%' . $request->session()->get('search_condition.client_original_name') . '%'); - } + $search_condition = $request->session()->get('search_condition', []); + $this->applySearchConditions($uploads_query, $search_condition); // 表示順 - $sort = 'id_desc'; - if ($request->session()->has('search_condition.sort')) { - $sort = session('search_condition.sort'); - } - if ($sort == 'id_asc') { - $uploads_query->orderBy('id', 'asc'); - } elseif ($sort == 'id_desc') { - $uploads_query->orderBy('id', 'desc'); - } elseif ($sort == 'client_original_name_asc') { - $uploads_query->orderBy('client_original_name', 'asc'); - } elseif ($sort == 'client_original_name_desc') { - $uploads_query->orderBy('client_original_name', 'desc'); - } elseif ($sort == 'size_asc') { - $uploads_query->orderBy('size', 'asc'); - } elseif ($sort == 'size_desc') { - $uploads_query->orderBy('size', 'desc'); - } elseif ($sort == 'created_at_asc') { - $uploads_query->orderBy('created_at', 'asc'); - } elseif ($sort == 'created_at_desc') { - $uploads_query->orderBy('created_at', 'desc'); - } elseif ($sort == 'download_count_desc') { - $uploads_query->orderBy('download_count', 'desc'); - } + $this->applySort($uploads_query, $this->getSort($search_condition)); // 表示件数の取得 ※デフォルトは10件 $per_page = $this->allowed_per_page[0]; @@ -128,6 +151,11 @@ public function index($request) // データ使用量の計算 $storage_usage = StorageUsageCalculator::getDataUsage(); + // プラグイン絞り込み用の一覧 + $uploadfile_plugins = Plugins::orderBy('display_sequence') + ->orderBy('plugin_name') + ->get(); + // 入力値をsessionへ保存(検索用) $request->flash(); @@ -138,6 +166,9 @@ public function index($request) "uploads" => $uploads, "allowed_per_page" => $this->allowed_per_page, "storage_usage" => $storage_usage, + "search_condition_keys" => $this->search_condition_keys, + "is_search_condition_set" => $this->isSearchConditionSet($search_condition), + "uploadfile_plugins" => $uploadfile_plugins, ]); } @@ -147,10 +178,7 @@ public function index($request) public function search($request) { // 検索ボタンが押されたときはここが実行される。検索条件を設定してindex を呼ぶ。 - $search_condition = [ - "client_original_name" => $request->input('search_condition.client_original_name'), - "sort" => $request->input('search_condition.sort'), - ]; + $search_condition = $this->getSearchConditionFromRequest($request); session(["search_condition" => $search_condition]); @@ -162,6 +190,163 @@ public function search($request) return redirect("/manage/uploadfile"); } + /** + * リクエストから検索条件を取得する + */ + private function getSearchConditionFromRequest($request) + { + $search_condition = []; + foreach ($this->search_condition_keys as $key) { + $value = $request->input('search_condition.' . $key); + $search_condition[$key] = is_string($value) ? trim($value) : $value; + } + + if (!in_array($search_condition['sort'], $this->allowed_sorts)) { + $search_condition['sort'] = 'id_desc'; + } + if (!in_array($search_condition['size_unit'], $this->allowed_size_units)) { + $search_condition['size_unit'] = 'MB'; + } + + return $search_condition; + } + + /** + * 検索条件をクエリに適用する + */ + private function applySearchConditions($uploads_query, array $search_condition) + { + if (!empty($search_condition['client_original_name'])) { + $uploads_query->where('uploads.client_original_name', 'like', '%' . $search_condition['client_original_name'] . '%'); + } + + if (!empty($search_condition['id']) && is_numeric($search_condition['id'])) { + $uploads_query->where('uploads.id', intval($search_condition['id'])); + } + + if (isset($search_condition['size_from']) && is_numeric($search_condition['size_from'])) { + $uploads_query->where('uploads.size', '>=', $this->convertSizeToBytes($search_condition['size_from'], $search_condition['size_unit'] ?? 'MB')); + } + + if (isset($search_condition['size_to']) && is_numeric($search_condition['size_to'])) { + $uploads_query->where('uploads.size', '<=', $this->convertSizeToBytes($search_condition['size_to'], $search_condition['size_unit'] ?? 'MB')); + } + + if (!empty($search_condition['page_name'])) { + $uploads_query->where('pages.page_name', 'like', '%' . $search_condition['page_name'] . '%'); + } + + if (!empty($search_condition['created_at_from'])) { + $uploads_query->whereDate('uploads.created_at', '>=', $search_condition['created_at_from']); + } + + if (!empty($search_condition['created_at_to'])) { + $uploads_query->whereDate('uploads.created_at', '<=', $search_condition['created_at_to']); + } + + $plugin_names = $this->getSelectedPluginNames($search_condition); + if (!empty($plugin_names)) { + $uploads_query->whereIn('uploads.plugin_name', $plugin_names); + } + } + + /** + * 入力されたファイルサイズをbyteに変換する + */ + private function convertSizeToBytes($size, $unit) + { + if ($unit == 'MB') { + return intval($size * 1024 * 1024); + } elseif ($unit == 'KB') { + return intval($size * 1024); + } + + return intval($size); + } + + /** + * 選択されたプラグイン名を配列で取得する + */ + private function getSelectedPluginNames(array $search_condition) + { + if (empty($search_condition['plugin_names'])) { + return []; + } + + $plugin_names = is_array($search_condition['plugin_names']) + ? $search_condition['plugin_names'] + : [$search_condition['plugin_names']]; + + return array_values(array_filter($plugin_names, function ($plugin_name) { + return $plugin_name !== ''; + })); + } + + /** + * 並べ替え条件を取得する + */ + private function getSort(array $search_condition) + { + if (!empty($search_condition['sort']) && in_array($search_condition['sort'], $this->allowed_sorts)) { + return $search_condition['sort']; + } + + return 'id_desc'; + } + + /** + * 並べ替え条件をクエリに適用する + */ + private function applySort($uploads_query, $sort) + { + if ($sort == 'id_asc') { + $uploads_query->orderBy('uploads.id', 'asc'); + } elseif ($sort == 'id_desc') { + $uploads_query->orderBy('uploads.id', 'desc'); + } elseif ($sort == 'client_original_name_asc') { + $uploads_query->orderBy('uploads.client_original_name', 'asc')->orderBy('uploads.id', 'asc'); + } elseif ($sort == 'client_original_name_desc') { + $uploads_query->orderBy('uploads.client_original_name', 'desc')->orderBy('uploads.id', 'desc'); + } elseif ($sort == 'size_asc') { + $uploads_query->orderBy('uploads.size', 'asc')->orderBy('uploads.id', 'asc'); + } elseif ($sort == 'size_desc') { + $uploads_query->orderBy('uploads.size', 'desc')->orderBy('uploads.id', 'desc'); + } elseif ($sort == 'created_at_asc') { + $uploads_query->orderBy('uploads.created_at', 'asc')->orderBy('uploads.id', 'asc'); + } elseif ($sort == 'created_at_desc') { + $uploads_query->orderBy('uploads.created_at', 'desc')->orderBy('uploads.id', 'desc'); + } elseif ($sort == 'plugin_name_asc') { + $uploads_query->orderBy('plugins.display_sequence', 'asc')->orderBy('uploads.plugin_name', 'asc')->orderBy('uploads.id', 'asc'); + } elseif ($sort == 'plugin_name_desc') { + $uploads_query->orderBy('plugins.display_sequence', 'desc')->orderBy('uploads.plugin_name', 'desc')->orderBy('uploads.id', 'desc'); + } elseif ($sort == 'page_name_asc') { + $uploads_query->orderBy('pages.page_name', 'asc')->orderBy('uploads.id', 'asc'); + } elseif ($sort == 'page_name_desc') { + $uploads_query->orderBy('pages.page_name', 'desc')->orderBy('uploads.id', 'desc'); + } elseif ($sort == 'download_count_desc') { + $uploads_query->orderBy('uploads.download_count', 'desc')->orderBy('uploads.id', 'desc'); + } elseif ($sort == 'play_count_desc') { + $uploads_query->orderBy('uploads.play_count', 'desc')->orderBy('uploads.id', 'desc'); + } + } + + /** + * 検索条件が指定されているか判定する + */ + private function isSearchConditionSet(array $search_condition) + { + foreach ($this->search_condition_keys as $key) { + if ($key == 'sort') { + continue; + } + if (isset($search_condition[$key]) && $search_condition[$key] !== '') { + return true; + } + } + + return !empty($search_condition['sort']) && $search_condition['sort'] != 'id_desc'; + } + /** * 検索条件クリア処理 */ diff --git a/resources/views/plugins/manage/uploadfile/index.blade.php b/resources/views/plugins/manage/uploadfile/index.blade.php index 9547826d9..5d4cf1a89 100644 --- a/resources/views/plugins/manage/uploadfile/index.blade.php +++ b/resources/views/plugins/manage/uploadfile/index.blade.php @@ -97,10 +97,10 @@
- @if (Session::has('search_condition.client_original_name') || Session::has('search_condition.sort')) + @if ($is_search_condition_set)
@else
@@ -118,6 +118,86 @@
+ {{-- ID --}} +
+ +
+ +
+
+ + {{-- ファイルサイズ --}} +
+ +
+
+
+ +
+
+
+ +
+
+ +
+
+
+
+ + {{-- ページ名 --}} +
+ +
+ +
+
+ + {{-- アップロード日付 --}} +
+ +
+
+
+ +
+
+
+ +
+
+
+
+ + {{-- プラグイン --}} +
+ +
+ @php + $selected_plugin_names = Session::get('search_condition.plugin_names', []); + if (!is_array($selected_plugin_names)) { + $selected_plugin_names = [$selected_plugin_names]; + } + @endphp +
+ @foreach($uploadfile_plugins as $uploadfile_plugin) +
+
+ plugin_name, $selected_plugin_names)) checked="checked" @endif> + +
+
+ @endforeach +
+
+
+ {{-- 並べ替え --}}
@@ -131,7 +211,12 @@ + + + + +
@@ -170,8 +255,18 @@ {{-- (右側)表示件数選択 --}}
{{ csrf_field() }} - - + @foreach($search_condition_keys as $search_condition_key) + @php + $search_condition_value = Session::get('search_condition.' . $search_condition_key); + @endphp + @if(is_array($search_condition_value)) + @foreach($search_condition_value as $value) + + @endforeach + @else + + @endif + @endforeach + @endif + @endforeach + + + + @if (!empty($keyword)) + + クリア + + @endif +
diff --git a/resources/views/plugins/user/blogs/default/blogs_list_buckets.blade.php b/resources/views/plugins/user/blogs/default/blogs_list_buckets.blade.php index 427b61108..3e6aceaf1 100644 --- a/resources/views/plugins/user/blogs/default/blogs_list_buckets.blade.php +++ b/resources/views/plugins/user/blogs/default/blogs_list_buckets.blade.php @@ -14,6 +14,13 @@ @section("plugin_setting_$frame->id") +@include('plugins.common.list_buckets_keyword_search', [ + 'action_url' => url('/')."/plugin/blogs/listBuckets/{$page->id}/{$frame_id}#frame-{$frame->id}", + 'clear_url' => url('/')."/plugin/blogs/listBuckets/{$page->id}/{$frame_id}#frame-{$frame->id}", + 'frame' => $frame, + 'keyword' => $keyword, +]) +
{{ csrf_field() }} @@ -51,7 +58,7 @@ {{-- ページング処理 --}} - @include('plugins.common.user_paginate', ['posts' => $blogs, 'frame' => $frame, 'aria_label_name' => $frame->plugin_name_full . '選択', 'class' => 'form-group']) + @include('plugins.common.user_paginate', ['posts' => $blogs, 'frame' => $frame, 'appends' => ['keyword' => $keyword], 'aria_label_name' => $frame->plugin_name_full . '選択', 'class' => 'form-group'])
diff --git a/resources/views/plugins/user/contents/default/contents_list_buckets.blade.php b/resources/views/plugins/user/contents/default/contents_list_buckets.blade.php index 070b6232e..82d56f0cb 100644 --- a/resources/views/plugins/user/contents/default/contents_list_buckets.blade.php +++ b/resources/views/plugins/user/contents/default/contents_list_buckets.blade.php @@ -13,6 +13,19 @@ @endsection @section("plugin_setting_$frame->id") +@php + $base_list_url = url('/')."/plugin/contents/listBuckets/{$page->id}/{$frame_id}"; + $keyword_query = empty($keyword) ? '' : '&' . http_build_query(['keyword' => $keyword]); +@endphp + +@include('plugins.common.list_buckets_keyword_search', [ + 'action_url' => "{$base_list_url}#frame-{$frame->id}", + 'clear_url' => "{$base_list_url}?" . http_build_query(['sort' => $request_order_str]) . "#frame-{$frame->id}", + 'frame' => $frame, + 'keyword' => $keyword, + 'hidden_inputs' => ['sort' => $request_order_str], +]) + {{ csrf_field() }} @@ -20,7 +33,7 @@
選択 - id}}">更新日 + id}}">更新日 @if ($request_order_str == "contents_updated_at|asc") @elseif ($request_order_str == "contents_updated_at|desc") @@ -28,7 +41,7 @@ @endif - id}}">使用ページ + id}}">使用ページ @if ($request_order_str == "page_name|asc") @elseif ($request_order_str == "page_name|desc") @@ -36,7 +49,7 @@ @endif - id}}">データ名 + id}}">データ名 @if ($request_order_str == "bucket_name|asc") @elseif ($request_order_str == "bucket_name|desc") @@ -44,7 +57,7 @@ @endif - id}}">フレームタイトル + id}}">フレームタイトル @if ($request_order_str == "frame_title|asc") @elseif ($request_order_str == "frame_title|desc") @@ -52,7 +65,7 @@ @endif - id}}">内容 + id}}">内容 @if ($request_order_str == "content_text|asc") @elseif ($request_order_str == "content_text|desc") @@ -78,7 +91,7 @@
{{-- ページング処理 --}} - @include('plugins.common.user_paginate', ['posts' => $buckets_list, 'frame' => $frame, 'appends' => ['sort' => $request_order_str], 'aria_label_name' => $frame->plugin_name_full . '選択', 'class' => 'form-group']) + @include('plugins.common.user_paginate', ['posts' => $buckets_list, 'frame' => $frame, 'appends' => ['sort' => $request_order_str, 'keyword' => $keyword], 'aria_label_name' => $frame->plugin_name_full . '選択', 'class' => 'form-group'])
diff --git a/tests/Feature/Plugins/User/Blogs/BlogsBucketSearchFeatureTest.php b/tests/Feature/Plugins/User/Blogs/BlogsBucketSearchFeatureTest.php new file mode 100644 index 000000000..7d139c6c2 --- /dev/null +++ b/tests/Feature/Plugins/User/Blogs/BlogsBucketSearchFeatureTest.php @@ -0,0 +1,78 @@ +seed(); + } + + /** + * ブログの選択一覧では、ブログ名に一致する候補だけが残り、記事本文だけの一致では候補にしないこと。 + */ + public function testListBucketsCanSearchByBlogNameOnly(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame] = $this->createPluginFrame('blogs'); + + $this->createBlogBucket('MATCHブログ', '検索に一致しない記事本文'); + $this->createBlogBucket('対象外ブログ', '記事本文にMATCHがあります'); + + $response = $this->actingAs($admin)->get("/plugin/blogs/listBuckets/{$page->id}/{$frame->id}?keyword=MATCH"); + + $response->assertOk(); + $response->assertSee('MATCHブログ'); + $response->assertDontSee('対象外ブログ'); + $response->assertSee('name="keyword"', false); + $response->assertSee('value="MATCH"', false); + } + + /** + * ブログ検索確認に必要なバケツ・ブログ・記事をまとめて作成する。 + */ + private function createBlogBucket(string $blog_name, string $post_text): void + { + $bucket = Buckets::create([ + 'bucket_name' => $blog_name, + 'plugin_name' => 'blogs', + ]); + + $blog = Blogs::create([ + 'bucket_id' => $bucket->id, + 'blog_name' => $blog_name, + ]); + + BlogsPosts::create([ + 'contents_id' => null, + 'blogs_id' => $blog->id, + 'post_title' => $blog_name . 'の記事', + 'post_text' => $post_text, + 'status' => StatusType::active, + 'posted_at' => now(), + ]); + } +} diff --git a/tests/Feature/Plugins/User/Contents/ContentsBucketSearchFeatureTest.php b/tests/Feature/Plugins/User/Contents/ContentsBucketSearchFeatureTest.php new file mode 100644 index 000000000..74258073a --- /dev/null +++ b/tests/Feature/Plugins/User/Contents/ContentsBucketSearchFeatureTest.php @@ -0,0 +1,90 @@ +seed(); + } + + /** + * 固定記事の選択一覧では、フレームタイトル・データ名・本文のいずれに一致しても候補に残ること。 + */ + public function testListBucketsCanSearchByFrameTitleBucketNameAndBody(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame] = $this->createPluginFrame('contents'); + $bucket_page = Page::factory()->create(); + + $this->createContentBucket($bucket_page, 'search-by-frame-title', '通常本文', 'MATCHフレーム'); + $this->createContentBucket($bucket_page, 'MATCH-search-by-bucket-name', '通常本文', '通常フレーム'); + $this->createContentBucket($bucket_page, 'search-by-body', '本文にMATCHがあります', '通常フレーム2'); + $this->createContentBucket($bucket_page, 'outside-content', '対象外本文', '対象外フレーム'); + + $response = $this->actingAs($admin)->get("/plugin/contents/listBuckets/{$page->id}/{$frame->id}?keyword=MATCH"); + + $response->assertOk(); + $response->assertSee('search-by-frame-title'); + $response->assertSee('MATCH-search-by-bucket-name'); + $response->assertSee('search-by-body'); + $response->assertDontSee('outside-content'); + $response->assertSee('name="keyword"', false); + $response->assertSee('value="MATCH"', false); + } + + /** + * 固定記事の検索確認に必要なバケツ・本文・利用フレームをまとめて作成する。 + */ + private function createContentBucket( + Page $page, + string $bucket_name, + string $content_text, + string $frame_title + ): void { + $bucket = Buckets::create([ + 'bucket_name' => $bucket_name, + 'plugin_name' => 'contents', + ]); + + Contents::create([ + 'bucket_id' => $bucket->id, + 'content_text' => $content_text, + 'status' => StatusType::active, + ]); + + Frame::create([ + 'page_id' => $page->id, + 'area_id' => 2, + 'frame_title' => $frame_title, + 'plugin_name' => 'contents', + 'bucket_id' => $bucket->id, + 'template' => 'default', + 'display_sequence' => 1, + ]); + } +} From ff94bf1fb5a5451c8c8658584343b0cc13ac9e75 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Fri, 15 May 2026 19:20:17 +0900 Subject: [PATCH 15/49] fix(list-buckets): handle zero keyword search --- app/Plugins/User/Blogs/BlogsPlugin.php | 2 +- app/Plugins/User/Contents/ContentsPlugin.php | 2 +- .../list_buckets_keyword_search.blade.php | 2 +- .../default/contents_list_buckets.blade.php | 2 +- .../Blogs/BlogsBucketSearchFeatureTest.php | 20 +++++++++++++++++ .../ContentsBucketSearchFeatureTest.php | 22 +++++++++++++++++++ 6 files changed, 46 insertions(+), 4 deletions(-) diff --git a/app/Plugins/User/Blogs/BlogsPlugin.php b/app/Plugins/User/Blogs/BlogsPlugin.php index 3d2522e00..a6ba8e584 100644 --- a/app/Plugins/User/Blogs/BlogsPlugin.php +++ b/app/Plugins/User/Blogs/BlogsPlugin.php @@ -1249,7 +1249,7 @@ public function listBuckets($request, $page_id, $frame_id, $id = null) ->where('frames.id', $frame_id); }); - if (!empty($keyword)) { + if ($keyword !== '') { $blogs->where('blogs.blog_name', 'like', '%' . $keyword . '%'); } diff --git a/app/Plugins/User/Contents/ContentsPlugin.php b/app/Plugins/User/Contents/ContentsPlugin.php index 9a5cdcf09..e45b4b27d 100644 --- a/app/Plugins/User/Contents/ContentsPlugin.php +++ b/app/Plugins/User/Contents/ContentsPlugin.php @@ -809,7 +809,7 @@ public function listBuckets($request, $page_id, $frame_id, $id = null) ->leftJoin('pages', 'pages.id', '=', 'frames.page_id') ->where('buckets.plugin_name', 'contents'); - if (!empty($keyword)) { + if ($keyword !== '') { $buckets_query->where(function ($query) use ($keyword) { $query->where('frames.frame_title', 'like', '%' . $keyword . '%') ->orWhere('buckets.bucket_name', 'like', '%' . $keyword . '%') diff --git a/resources/views/plugins/common/list_buckets_keyword_search.blade.php b/resources/views/plugins/common/list_buckets_keyword_search.blade.php index dc0a5e562..0d9edebd2 100644 --- a/resources/views/plugins/common/list_buckets_keyword_search.blade.php +++ b/resources/views/plugins/common/list_buckets_keyword_search.blade.php @@ -24,7 +24,7 @@ - @if (!empty($keyword)) + @if ($keyword !== '') クリア diff --git a/resources/views/plugins/user/contents/default/contents_list_buckets.blade.php b/resources/views/plugins/user/contents/default/contents_list_buckets.blade.php index 82d56f0cb..bdf124674 100644 --- a/resources/views/plugins/user/contents/default/contents_list_buckets.blade.php +++ b/resources/views/plugins/user/contents/default/contents_list_buckets.blade.php @@ -15,7 +15,7 @@ @section("plugin_setting_$frame->id") @php $base_list_url = url('/')."/plugin/contents/listBuckets/{$page->id}/{$frame_id}"; - $keyword_query = empty($keyword) ? '' : '&' . http_build_query(['keyword' => $keyword]); + $keyword_query = $keyword === '' ? '' : '&' . http_build_query(['keyword' => $keyword]); @endphp @include('plugins.common.list_buckets_keyword_search', [ diff --git a/tests/Feature/Plugins/User/Blogs/BlogsBucketSearchFeatureTest.php b/tests/Feature/Plugins/User/Blogs/BlogsBucketSearchFeatureTest.php index 7d139c6c2..4423ef586 100644 --- a/tests/Feature/Plugins/User/Blogs/BlogsBucketSearchFeatureTest.php +++ b/tests/Feature/Plugins/User/Blogs/BlogsBucketSearchFeatureTest.php @@ -51,6 +51,26 @@ public function testListBucketsCanSearchByBlogNameOnly(): void $response->assertSee('value="MATCH"', false); } + /** + * ブログ名検索では、数値の0も有効な検索語として扱われ、未指定と同じ全件表示にならないこと。 + */ + public function testListBucketsCanSearchByZeroKeyword(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame] = $this->createPluginFrame('blogs'); + + $this->createBlogBucket('2026年度ブログ', '通常の記事本文'); + $this->createBlogBucket('通常ブログ', '対象外の記事本文'); + + $response = $this->actingAs($admin)->get("/plugin/blogs/listBuckets/{$page->id}/{$frame->id}?keyword=0"); + + $response->assertOk(); + $response->assertSee('2026年度ブログ'); + $response->assertDontSee('通常ブログ'); + $response->assertSee('value="0"', false); + $response->assertSee('クリア'); + } + /** * ブログ検索確認に必要なバケツ・ブログ・記事をまとめて作成する。 */ diff --git a/tests/Feature/Plugins/User/Contents/ContentsBucketSearchFeatureTest.php b/tests/Feature/Plugins/User/Contents/ContentsBucketSearchFeatureTest.php index 74258073a..5e4215391 100644 --- a/tests/Feature/Plugins/User/Contents/ContentsBucketSearchFeatureTest.php +++ b/tests/Feature/Plugins/User/Contents/ContentsBucketSearchFeatureTest.php @@ -57,6 +57,28 @@ public function testListBucketsCanSearchByFrameTitleBucketNameAndBody(): void $response->assertSee('value="MATCH"', false); } + /** + * 固定記事検索では、数値の0も有効な検索語として扱われ、ソートやページングでも条件を維持すること。 + */ + public function testListBucketsCanSearchByZeroKeyword(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame] = $this->createPluginFrame('contents'); + $bucket_page = Page::factory()->create(); + + $this->createContentBucket($bucket_page, '2026年度固定記事', '通常本文', '通常フレーム'); + $this->createContentBucket($bucket_page, '通常固定記事', '対象外本文', '対象外フレーム'); + + $response = $this->actingAs($admin)->get("/plugin/contents/listBuckets/{$page->id}/{$frame->id}?keyword=0"); + + $response->assertOk(); + $response->assertSee('2026年度固定記事'); + $response->assertDontSee('通常固定記事'); + $response->assertSee('value="0"', false); + $response->assertSee('keyword=0', false); + $response->assertSee('クリア'); + } + /** * 固定記事の検索確認に必要なバケツ・本文・利用フレームをまとめて作成する。 */ From 454b70dd286924ce3fdb28f265acfb5439e7dbca Mon Sep 17 00:00:00 2001 From: gakigaki Date: Tue, 19 May 2026 09:18:44 +0900 Subject: [PATCH 16/49] feat(whatsnews): add cabinet calendar photoalbum targets --- app/Plugins/User/Cabinets/CabinetsPlugin.php | 66 ++++- .../User/Calendars/CalendarsPlugin.php | 31 +- .../User/Photoalbums/PhotoalbumsPlugin.php | 80 ++++- .../WhatsnewsTargetPluginsFeatureTest.php | 273 ++++++++++++++++++ 4 files changed, 436 insertions(+), 14 deletions(-) create mode 100644 tests/Feature/Plugins/User/Whatsnews/WhatsnewsTargetPluginsFeatureTest.php diff --git a/app/Plugins/User/Cabinets/CabinetsPlugin.php b/app/Plugins/User/Cabinets/CabinetsPlugin.php index 3099b7832..293406768 100644 --- a/app/Plugins/User/Cabinets/CabinetsPlugin.php +++ b/app/Plugins/User/Cabinets/CabinetsPlugin.php @@ -46,6 +46,11 @@ class CabinetsPlugin extends UserPluginBase /* オブジェクト変数 */ + /** + * 新着機能を使うか + */ + public $use_whatsnew = true; + /** * POST チェックに使用する getPost() 関数を使うか * [TODO] 現在(2021/11/10)は、管理者がアップしたファイルも、編集者が削除できるため、getPost()は使わない設定にする。 @@ -65,7 +70,7 @@ public function getPublicFunctions() { // 標準関数以外で画面などから呼ばれる関数の定義 $functions = array(); - $functions['get'] = ['index', 'download', 'changeDirectory']; + $functions['get'] = ['index', 'show', 'download', 'changeDirectory']; $functions['post'] = ['makeFolder', 'upload', 'deleteContents', 'rename', 'move']; return $functions; } @@ -94,6 +99,39 @@ private function getPluginBucket($bucket_id) return Cabinet::firstOrNew(['bucket_id' => $bucket_id]); } + /* スタティック関数 */ + + /** + * 新着情報用メソッド + */ + public static function getWhatsnewArgs() + { + $return[] = DB::table('cabinet_contents') + ->select( + 'frames.page_id as page_id', + 'frames.id as frame_id', + 'cabinet_contents.id as post_id', + 'cabinet_contents.name as post_title', + 'cabinet_contents.comment as post_detail', + DB::raw("null as important"), + DB::raw('COALESCE(cabinet_contents.updated_at, cabinet_contents.created_at) as posted_at'), + 'cabinet_contents.created_name as posted_name', + DB::raw("null as classname"), + DB::raw("null as category"), + DB::raw('"cabinets" as plugin_name') + ) + ->join('cabinets', 'cabinets.id', '=', 'cabinet_contents.cabinet_id') + ->join('frames', 'frames.bucket_id', '=', 'cabinets.bucket_id') + ->where('frames.disable_whatsnews', 0) + ->whereNotNull('cabinet_contents.parent_id') + ->whereNull('cabinet_contents.deleted_at'); + + $return[] = 'show_page_frame_post'; + $return[] = '/plugin/cabinets/show'; + + return $return; + } + /* 画面アクション関数 */ /** @@ -171,6 +209,32 @@ public function index($request, $page_id, $frame_id, $parent_id = null) ]); } + /** + * 新着情報からキャビネットコンテンツへ遷移する + * + * @param \Illuminate\Http\Request $request リクエスト + * @param int $page_id ページID + * @param int $frame_id フレームID + * @param int $cabinet_content_id キャビネットコンテンツID + */ + public function show($request, $page_id, $frame_id, $cabinet_content_id) + { + $cabinet = $this->getPluginBucket($this->frame->bucket_id); + $cabinet_content = CabinetContent::where('id', $cabinet_content_id) + ->where('cabinet_id', $cabinet->id) + ->first(); + + if (empty($cabinet_content)) { + abort(404, 'コンテンツがありません。'); + } + + $parent_id = $cabinet_content->is_folder == CabinetContent::is_folder_on + ? $cabinet_content->id + : $cabinet_content->parent_id; + + return $this->index($request, $page_id, $frame_id, $parent_id); + } + /** * フォルダを移動する */ diff --git a/app/Plugins/User/Calendars/CalendarsPlugin.php b/app/Plugins/User/Calendars/CalendarsPlugin.php index f25c8ae25..8f91b5118 100644 --- a/app/Plugins/User/Calendars/CalendarsPlugin.php +++ b/app/Plugins/User/Calendars/CalendarsPlugin.php @@ -39,6 +39,11 @@ class CalendarsPlugin extends UserPluginBase { /* オブジェクト変数 */ + /** + * 新着機能を使うか + */ + public $use_whatsnew = true; + /** * 変更時のPOSTデータ */ @@ -154,23 +159,25 @@ private function getPosts($from_date, $to_date) public static function getWhatsnewArgs() { // 戻り値('sql_method'、'link_pattern'、'link_base') - $return[] = DB::table('calendars_posts') + $return[] = DB::table('calendar_posts') ->select( - 'frames.page_id as page_id', - 'frames.id as frame_id', - 'calendars_posts.id as post_id', - 'calendars_posts.title as post_title', - DB::raw("null as important"), - 'calendars_posts.created_at as posted_at', - 'calendars_posts.created_name as posted_name', - DB::raw("null as classname"), - DB::raw("null as category"), + 'frames.page_id as page_id', + 'frames.id as frame_id', + 'calendar_posts.id as post_id', + 'calendar_posts.title as post_title', + 'calendar_posts.body as post_detail', + DB::raw("null as important"), + 'calendar_posts.created_at as posted_at', + 'calendar_posts.created_name as posted_name', + DB::raw("null as classname"), + DB::raw("null as category"), DB::raw('"calendars" as plugin_name') ) - ->join('calendars', 'calendars.id', '=', 'calendars_posts.calendars_id') + ->join('calendars', 'calendars.id', '=', 'calendar_posts.calendar_id') ->join('frames', 'frames.bucket_id', '=', 'calendars.bucket_id') ->where('frames.disable_whatsnews', 0) - ->whereNull('calendars_posts.deleted_at'); + ->where('calendar_posts.status', StatusType::active) + ->whereNull('calendar_posts.deleted_at'); $return[] = 'show_page_frame_post'; $return[] = '/plugin/calendars/show'; diff --git a/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php b/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php index 59c410ca9..bee4579d4 100644 --- a/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php +++ b/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php @@ -6,6 +6,7 @@ use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Validator; use Illuminate\Validation\Rule; @@ -50,6 +51,11 @@ class PhotoalbumsPlugin extends UserPluginBase */ /* オブジェクト変数 */ + /** + * 新着機能を使うか + */ + public $use_whatsnew = true; + // ファイルダウンロードURL private $download_url = ''; @@ -67,7 +73,7 @@ public function getPublicFunctions() { // 標準関数以外で画面などから呼ばれる関数の定義 $functions = array(); - $functions['get'] = ['index', 'download', 'changeDirectory', 'embed', 'detail', 'moreContents']; + $functions['get'] = ['index', 'show', 'download', 'changeDirectory', 'embed', 'detail', 'moreContents']; $functions['post'] = ['makeFolder', 'editFolder', 'upload', 'uploadVideo', 'editContents', 'editVideo', 'deleteContents', 'updateViewSequence', 'updateHiddenFolders']; return $functions; } @@ -105,6 +111,40 @@ private function getPluginBucket($bucket_id) return Photoalbum::firstOrNew(['bucket_id' => $bucket_id]); } + /* スタティック関数 */ + + /** + * 新着情報用メソッド + */ + public static function getWhatsnewArgs() + { + $return[] = DB::table('photoalbum_contents') + ->select( + 'frames.page_id as page_id', + 'frames.id as frame_id', + 'photoalbum_contents.id as post_id', + DB::raw("COALESCE(NULLIF(photoalbum_contents.name, ''), uploads.client_original_name) as post_title"), + 'photoalbum_contents.description as post_detail', + DB::raw("null as important"), + DB::raw('COALESCE(photoalbum_contents.updated_at, photoalbum_contents.created_at) as posted_at'), + 'photoalbum_contents.created_name as posted_name', + DB::raw("null as classname"), + DB::raw("null as category"), + DB::raw('"photoalbums" as plugin_name') + ) + ->join('photoalbums', 'photoalbums.id', '=', 'photoalbum_contents.photoalbum_id') + ->join('frames', 'frames.bucket_id', '=', 'photoalbums.bucket_id') + ->leftJoin('uploads', 'uploads.id', '=', 'photoalbum_contents.upload_id') + ->where('frames.disable_whatsnews', 0) + ->whereNotNull('photoalbum_contents.parent_id') + ->whereNull('photoalbum_contents.deleted_at'); + + $return[] = 'show_page_frame_post'; + $return[] = '/plugin/photoalbums/show'; + + return $return; + } + /* 画面アクション関数 */ /** @@ -161,6 +201,44 @@ public function index($request, $page_id, $frame_id, $parent_id = null) ], $index_display_items)); } + /** + * 新着情報からフォトアルバムコンテンツへ遷移する + * + * @param \Illuminate\Http\Request $request リクエスト + * @param int $page_id ページID + * @param int $frame_id フレームID + * @param int $photoalbum_content_id フォトアルバムコンテンツID + */ + public function show($request, $page_id, $frame_id, $photoalbum_content_id) + { + $photoalbum = $this->getPluginBucket($this->frame->bucket_id); + $photoalbum_content = PhotoalbumContent::where('id', $photoalbum_content_id) + ->where('photoalbum_id', $photoalbum->id) + ->first(); + + if (empty($photoalbum_content)) { + abort(404, 'コンテンツがありません。'); + } + + $hidden_folder_ids = $this->getHiddenFolderIds($this->frame_configs); + if (!empty($hidden_folder_ids)) { + $ancestors = PhotoalbumContent::ancestorsAndSelf($photoalbum_content->id); + if ($this->isHiddenPhotoalbumContent($photoalbum_content, $hidden_folder_ids, $ancestors->keyBy('id'))) { + abort(404, 'コンテンツがありません。'); + } + } + + if ($photoalbum_content->is_folder == PhotoalbumContent::is_folder_on) { + return $this->index($request, $page_id, $frame_id, $photoalbum_content->id); + } + + if ($photoalbum_content->isVideo($photoalbum_content->mimetype)) { + return $this->detail($request, $page_id, $frame_id, $photoalbum_content->id); + } + + return $this->index($request, $page_id, $frame_id, $photoalbum_content->parent_id); + } + /** * 親配下の表示可能コンテンツを、表示設定の並び順で取得する。 * diff --git a/tests/Feature/Plugins/User/Whatsnews/WhatsnewsTargetPluginsFeatureTest.php b/tests/Feature/Plugins/User/Whatsnews/WhatsnewsTargetPluginsFeatureTest.php new file mode 100644 index 000000000..7a1748221 --- /dev/null +++ b/tests/Feature/Plugins/User/Whatsnews/WhatsnewsTargetPluginsFeatureTest.php @@ -0,0 +1,273 @@ +seed(); + } + + /** + * キャビネット・カレンダー・フォトアルバムが、新着情報設定の対象プラグインとして選択できること。 + */ + public function testTargetPluginsIncludeCabinetsCalendarsAndPhotoalbums(): void + { + $target_plugins = WhatsnewTargetPluginTool::getMembers(); + + $this->assertArrayHasKey('cabinets', $target_plugins); + $this->assertArrayHasKey('calendars', $target_plugins); + $this->assertArrayHasKey('photoalbums', $target_plugins); + } + + /** + * 追加対象の各プラグインが、新着情報の共通列を持つ公開済みコンテンツを返すこと。 + */ + public function testAddedPluginsReturnWhatsnewRows(): void + { + $this->createCabinetContent('学校だより.pdf', '学校だよりをアップしました。'); + $this->createCalendarPost('授業参観', '授業参観のお知らせです。'); + $this->createPhotoalbumContent('遠足写真', '遠足の写真です。'); + + [$cabinet_query, $cabinet_link_pattern, $cabinet_link_base] = CabinetsPlugin::getWhatsnewArgs(); + [$calendar_query, $calendar_link_pattern, $calendar_link_base] = CalendarsPlugin::getWhatsnewArgs(); + [$photoalbum_query, $photoalbum_link_pattern, $photoalbum_link_base] = PhotoalbumsPlugin::getWhatsnewArgs(); + + $cabinet_row = $cabinet_query->where('cabinet_contents.name', '学校だより.pdf')->first(); + $calendar_row = $calendar_query->where('calendar_posts.title', '授業参観')->first(); + $photoalbum_row = $photoalbum_query->where('photoalbum_contents.name', '遠足写真')->first(); + + $this->assertSame('show_page_frame_post', $cabinet_link_pattern); + $this->assertSame('/plugin/cabinets/show', $cabinet_link_base); + $this->assertSame('cabinets', $cabinet_row->plugin_name); + $this->assertSame('学校だより.pdf', $cabinet_row->post_title); + $this->assertSame('学校だよりをアップしました。', $cabinet_row->post_detail); + + $this->assertSame('show_page_frame_post', $calendar_link_pattern); + $this->assertSame('/plugin/calendars/show', $calendar_link_base); + $this->assertSame('calendars', $calendar_row->plugin_name); + $this->assertSame('授業参観', $calendar_row->post_title); + $this->assertSame('授業参観のお知らせです。', $calendar_row->post_detail); + + $this->assertSame('show_page_frame_post', $photoalbum_link_pattern); + $this->assertSame('/plugin/photoalbums/show', $photoalbum_link_base); + $this->assertSame('photoalbums', $photoalbum_row->plugin_name); + $this->assertSame('遠足写真', $photoalbum_row->post_title); + $this->assertSame('遠足の写真です。', $photoalbum_row->post_detail); + } + + /** + * キャビネットの新着リンク先アクションが、リダイレクトレスポンスではなく表示画面を返すこと。 + */ + public function testCabinetWhatsnewLinkTargetReturnsViewWithoutRedirectResponse(): void + { + $content = $this->createCabinetContent('学校だより.pdf', '学校だよりをアップしました。'); + $frame = $this->getFrameByBucketId(Cabinet::find($content->cabinet_id)->bucket_id); + \Request::merge(['frame_configs' => new \Illuminate\Database\Eloquent\Collection()]); + $plugin = new CabinetsPlugin(Page::find($frame->page_id), $frame, Page::defaultOrder()->get()); + + $response = $plugin->show(request(), $frame->page_id, $frame->id, $content->id); + + $this->assertInstanceOf(\Illuminate\View\View::class, $response); + $this->assertNotInstanceOf(\Illuminate\Http\RedirectResponse::class, $response); + $this->assertSame('plugins.user.cabinets.default.index', $response->getName()); + $this->assertTrue($response->getData()['cabinet_contents']->contains('id', $content->id)); + } + + /** + * フォトアルバムの新着リンク先アクションが、リダイレクトレスポンスではなく表示画面を返すこと。 + */ + public function testPhotoalbumWhatsnewLinkTargetReturnsViewWithoutRedirectResponse(): void + { + $content = $this->createPhotoalbumContent('遠足写真', '遠足の写真です。'); + $frame = $this->getFrameByBucketId(Photoalbum::find($content->photoalbum_id)->bucket_id); + \Request::merge(['frame_configs' => new \Illuminate\Database\Eloquent\Collection()]); + $plugin = new PhotoalbumsPlugin(Page::find($frame->page_id), $frame, Page::defaultOrder()->get()); + + $response = $plugin->show(request(), $frame->page_id, $frame->id, $content->id); + + $this->assertInstanceOf(\Illuminate\View\View::class, $response); + $this->assertNotInstanceOf(\Illuminate\Http\RedirectResponse::class, $response); + $this->assertSame('plugins.user.photoalbums.default.index', $response->getName()); + $this->assertTrue($response->getData()['photoalbum_image_items']->contains('id', $content->id)); + } + + /** + * 指定プラグイン用のページ・バケツ・フレームをまとめて作成する。 + */ + private function createPluginFrame(string $plugin_name): array + { + $page = Page::factory()->create([ + 'permanent_link' => "/test-{$plugin_name}", + ]); + + $bucket = Buckets::factory()->create([ + 'bucket_name' => "Test {$plugin_name}", + 'plugin_name' => $plugin_name, + ]); + + $frame = Frame::factory()->create([ + 'page_id' => $page->id, + 'area_id' => 2, + 'frame_title' => "Test {$plugin_name}", + 'plugin_name' => $plugin_name, + 'plug_name' => $plugin_name, + 'bucket_id' => $bucket->id, + 'content_open_type' => ContentOpenType::always_open, + ]); + + return [$page, $bucket, $frame]; + } + + /** + * 指定バケツを配置しているフレームを取得する。 + */ + private function getFrameByBucketId(int $bucket_id): Frame + { + return Frame::where('bucket_id', $bucket_id)->firstOrFail(); + } + + /** + * キャビネットに新着対象のファイルを作成する。 + */ + private function createCabinetContent(string $name, string $comment): CabinetContent + { + [$page, $bucket] = $this->createPluginFrame('cabinets'); + + $cabinet = Cabinet::create([ + 'bucket_id' => $bucket->id, + 'name' => 'Test Cabinet', + 'upload_max_size' => 1024, + ]); + + $root = CabinetContent::create([ + 'cabinet_id' => $cabinet->id, + 'upload_id' => null, + 'name' => $cabinet->name, + 'is_folder' => CabinetContent::is_folder_on, + 'parent_id' => null, + ]); + + $upload = Uploads::create([ + 'client_original_name' => $name, + 'mimetype' => 'application/pdf', + 'extension' => 'pdf', + 'size' => 123, + 'plugin_name' => 'cabinets', + 'page_id' => $page->id, + 'temporary_flag' => 0, + ]); + + $content = $root->children()->create([ + 'cabinet_id' => $cabinet->id, + 'upload_id' => $upload->id, + 'name' => $name, + 'is_folder' => CabinetContent::is_folder_off, + ]); + $content->comment = $comment; + $content->save(); + + return $content; + } + + /** + * カレンダーに新着対象の予定を作成する。 + */ + private function createCalendarPost(string $title, string $body): CalendarPost + { + [, $bucket] = $this->createPluginFrame('calendars'); + + $calendar = Calendar::create([ + 'bucket_id' => $bucket->id, + 'name' => 'Test Calendar', + ]); + + return CalendarPost::create([ + 'calendar_id' => $calendar->id, + 'allday_flag' => 1, + 'start_date' => now()->toDateString(), + 'start_time' => '00:00:00', + 'end_date' => now()->toDateString(), + 'end_time' => '23:59:59', + 'title' => $title, + 'body' => $body, + ]); + } + + /** + * フォトアルバムに新着対象の画像を作成する。 + */ + private function createPhotoalbumContent(string $name, string $description): PhotoalbumContent + { + [$page, $bucket] = $this->createPluginFrame('photoalbums'); + + $photoalbum = Photoalbum::create([ + 'bucket_id' => $bucket->id, + 'name' => 'Test Photoalbum', + 'image_upload_max_size' => 1024, + 'image_upload_max_px' => 1024, + 'video_upload_max_size' => 1024, + ]); + + $root = PhotoalbumContent::create([ + 'photoalbum_id' => $photoalbum->id, + 'upload_id' => null, + 'poster_upload_id' => null, + 'name' => $photoalbum->name, + 'is_folder' => PhotoalbumContent::is_folder_on, + 'parent_id' => null, + ]); + + $upload = Uploads::create([ + 'client_original_name' => "{$name}.jpg", + 'mimetype' => 'image/jpeg', + 'extension' => 'jpg', + 'size' => 123, + 'plugin_name' => 'photoalbums', + 'page_id' => $page->id, + 'temporary_flag' => 0, + ]); + + return $root->children()->create([ + 'photoalbum_id' => $photoalbum->id, + 'upload_id' => $upload->id, + 'poster_upload_id' => null, + 'name' => $name, + 'description' => $description, + 'is_folder' => PhotoalbumContent::is_folder_off, + 'is_cover' => PhotoalbumContent::is_cover_off, + 'mimetype' => 'image/jpeg', + ]); + } +} From 6deef88d3463a4560c85783511cc2d5f5d2f26ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 May 2026 20:50:35 +0000 Subject: [PATCH 17/49] chore(deps): bump setasign/fpdi from 2.6.4 to 2.6.7 Bumps [setasign/fpdi](https://github.com/Setasign/FPDI) from 2.6.4 to 2.6.7. - [Release notes](https://github.com/Setasign/FPDI/releases) - [Commits](https://github.com/Setasign/FPDI/compare/v2.6.4...v2.6.7) --- updated-dependencies: - dependency-name: setasign/fpdi dependency-version: 2.6.7 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- composer.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.lock b/composer.lock index 9b50e96ca..376417bb3 100644 --- a/composer.lock +++ b/composer.lock @@ -3929,27 +3929,27 @@ }, { "name": "setasign/fpdi", - "version": "v2.6.4", + "version": "v2.6.7", "source": { "type": "git", "url": "https://github.com/Setasign/FPDI.git", - "reference": "4b53852fde2734ec6a07e458a085db627c60eada" + "reference": "388c51e69982a3fc16698710b763e8107a49f510" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Setasign/FPDI/zipball/4b53852fde2734ec6a07e458a085db627c60eada", - "reference": "4b53852fde2734ec6a07e458a085db627c60eada", + "url": "https://api.github.com/repos/Setasign/FPDI/zipball/388c51e69982a3fc16698710b763e8107a49f510", + "reference": "388c51e69982a3fc16698710b763e8107a49f510", "shasum": "" }, "require": { "ext-zlib": "*", - "php": "^7.1 || ^8.0" + "php": ">=7.2 <=8.5.99999" }, "conflict": { "setasign/tfpdf": "<1.31" }, "require-dev": { - "phpunit/phpunit": "^7", + "phpunit/phpunit": "^8.5.52", "setasign/fpdf": "~1.8.6", "setasign/tfpdf": "~1.33", "squizlabs/php_codesniffer": "^3.5", @@ -3989,7 +3989,7 @@ ], "support": { "issues": "https://github.com/Setasign/FPDI/issues", - "source": "https://github.com/Setasign/FPDI/tree/v2.6.4" + "source": "https://github.com/Setasign/FPDI/tree/v2.6.7" }, "funding": [ { @@ -3997,7 +3997,7 @@ "type": "tidelift" } ], - "time": "2025-08-05T09:57:14+00:00" + "time": "2026-05-13T10:16:22+00:00" }, { "name": "swiftmailer/swiftmailer", From 9e50f6dbc5b494ef196d77ea28a0ab3f158c3955 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Wed, 20 May 2026 14:06:59 +0900 Subject: [PATCH 18/49] fix(whatsnews): exclude hidden photoalbum contents --- .../User/Photoalbums/PhotoalbumsPlugin.php | 179 +++++++++++++++--- .../WhatsnewsTargetPluginsFeatureTest.php | 87 +++++++++ 2 files changed, 241 insertions(+), 25 deletions(-) diff --git a/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php b/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php index bee4579d4..faa89f3fc 100644 --- a/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php +++ b/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php @@ -118,31 +118,160 @@ private function getPluginBucket($bucket_id) */ public static function getWhatsnewArgs() { - $return[] = DB::table('photoalbum_contents') - ->select( - 'frames.page_id as page_id', - 'frames.id as frame_id', - 'photoalbum_contents.id as post_id', - DB::raw("COALESCE(NULLIF(photoalbum_contents.name, ''), uploads.client_original_name) as post_title"), - 'photoalbum_contents.description as post_detail', - DB::raw("null as important"), - DB::raw('COALESCE(photoalbum_contents.updated_at, photoalbum_contents.created_at) as posted_at'), - 'photoalbum_contents.created_name as posted_name', - DB::raw("null as classname"), - DB::raw("null as category"), - DB::raw('"photoalbums" as plugin_name') - ) - ->join('photoalbums', 'photoalbums.id', '=', 'photoalbum_contents.photoalbum_id') - ->join('frames', 'frames.bucket_id', '=', 'photoalbums.bucket_id') - ->leftJoin('uploads', 'uploads.id', '=', 'photoalbum_contents.upload_id') - ->where('frames.disable_whatsnews', 0) - ->whereNotNull('photoalbum_contents.parent_id') - ->whereNull('photoalbum_contents.deleted_at'); - - $return[] = 'show_page_frame_post'; - $return[] = '/plugin/photoalbums/show'; - - return $return; + $query = self::buildWhatsnewQuery(); + $hidden_folder_ids_by_frame = self::getHiddenFolderIdsByFrame(); + $hidden_content_ids_by_frame = self::resolveHiddenContentIdsByFrame($hidden_folder_ids_by_frame); + + self::excludeHiddenContentIdsByFrame($query, $hidden_content_ids_by_frame); + + return [ + $query, + 'show_page_frame_post', + '/plugin/photoalbums/show', + ]; + } + + /** + * 新着情報の基本クエリを作成する。 + */ + private static function buildWhatsnewQuery() + { + return DB::table('photoalbum_contents') + ->select( + 'frames.page_id as page_id', + 'frames.id as frame_id', + 'photoalbum_contents.id as post_id', + DB::raw("COALESCE(NULLIF(photoalbum_contents.name, ''), uploads.client_original_name) as post_title"), + 'photoalbum_contents.description as post_detail', + DB::raw("null as important"), + DB::raw('COALESCE(photoalbum_contents.updated_at, photoalbum_contents.created_at) as posted_at'), + 'photoalbum_contents.created_name as posted_name', + DB::raw("null as classname"), + DB::raw("null as category"), + DB::raw('"photoalbums" as plugin_name') + ) + ->join('photoalbums', 'photoalbums.id', '=', 'photoalbum_contents.photoalbum_id') + ->join('frames', 'frames.bucket_id', '=', 'photoalbums.bucket_id') + ->leftJoin('uploads', 'uploads.id', '=', 'photoalbum_contents.upload_id') + ->where('frames.disable_whatsnews', 0) + ->whereNotNull('photoalbum_contents.parent_id') + ->whereNull('photoalbum_contents.deleted_at'); + } + + /** + * フレームごとの非表示アルバムIDを取得する。 + */ + private static function getHiddenFolderIdsByFrame(): array + { + $frame_configs = request()->attributes->get('frame_configs'); + if (empty($frame_configs)) { + $frame_configs = FrameConfig::where('name', PhotoalbumFrameConfig::hidden_folder_ids)->get(); + } else { + $frame_configs = $frame_configs->where('name', PhotoalbumFrameConfig::hidden_folder_ids); + } + + $hidden_folder_ids_by_frame = []; + foreach ($frame_configs as $frame_config) { + $hidden_folder_ids = self::parseHiddenFolderIds($frame_config->value); + if (empty($hidden_folder_ids)) { + continue; + } + + $frame_id = (int) $frame_config->frame_id; + $hidden_folder_ids_by_frame[$frame_id] = array_values(array_unique(array_merge( + $hidden_folder_ids_by_frame[$frame_id] ?? [], + $hidden_folder_ids + ))); + } + + return $hidden_folder_ids_by_frame; + } + + /** + * フレームごとの非表示アルバムIDを、配下コンテンツIDへ展開する。 + */ + private static function resolveHiddenContentIdsByFrame(array $hidden_folder_ids_by_frame): array + { + if (empty($hidden_folder_ids_by_frame)) { + return []; + } + + $hidden_folder_ids = array_values(array_unique(array_merge(...array_values($hidden_folder_ids_by_frame)))); + $hidden_folders = PhotoalbumContent::whereIn('id', $hidden_folder_ids) + ->where('is_folder', PhotoalbumContent::is_folder_on) + ->whereNull('deleted_at') + ->get(['id', 'photoalbum_id', '_lft', '_rgt']) + ->keyBy('id'); + + $hidden_content_ids_by_frame = []; + foreach ($hidden_folder_ids_by_frame as $frame_id => $folder_ids) { + $content_ids = []; + foreach ($folder_ids as $folder_id) { + $folder = $hidden_folders->get($folder_id); + if (empty($folder)) { + continue; + } + + $content_ids = array_merge($content_ids, self::getDescendantPhotoalbumContentIds($folder)); + } + + if (!empty($content_ids)) { + $hidden_content_ids_by_frame[$frame_id] = array_values(array_unique($content_ids)); + } + } + + return $hidden_content_ids_by_frame; + } + + /** + * パイプ区切りの非表示アルバムIDを配列に変換する。 + */ + private static function parseHiddenFolderIds($value): array + { + $ids = explode(FrameConfig::CHECKBOX_SEPARATOR, (string) $value); + $ids = array_map('intval', $ids); + $ids = array_filter($ids, static function ($id) { + return $id > 0; + }); + + return array_values(array_unique($ids)); + } + + /** + * 非表示アルバム自身と配下コンテンツのIDを取得する。 + */ + private static function getDescendantPhotoalbumContentIds(PhotoalbumContent $folder): array + { + return PhotoalbumContent::where('photoalbum_id', $folder->photoalbum_id) + ->whereNotNull('parent_id') + ->whereNull('deleted_at') + ->where('_lft', '>=', $folder->_lft) + ->where('_rgt', '<=', $folder->_rgt) + ->pluck('id') + ->all(); + } + + /** + * フレームごとの非表示コンテンツIDを新着取得条件から除外する。 + */ + private static function excludeHiddenContentIdsByFrame($query, array $hidden_content_ids_by_frame): void + { + if (empty($hidden_content_ids_by_frame)) { + return; + } + + $query->where(function ($query) use ($hidden_content_ids_by_frame) { + foreach ($hidden_content_ids_by_frame as $frame_id => $content_ids) { + if (empty($content_ids)) { + continue; + } + + $query->where(function ($query) use ($frame_id, $content_ids) { + $query->where('frames.id', '!=', $frame_id) + ->orWhereNotIn('photoalbum_contents.id', $content_ids); + }); + } + }); } /* 画面アクション関数 */ diff --git a/tests/Feature/Plugins/User/Whatsnews/WhatsnewsTargetPluginsFeatureTest.php b/tests/Feature/Plugins/User/Whatsnews/WhatsnewsTargetPluginsFeatureTest.php index 7a1748221..97b9f9e6b 100644 --- a/tests/Feature/Plugins/User/Whatsnews/WhatsnewsTargetPluginsFeatureTest.php +++ b/tests/Feature/Plugins/User/Whatsnews/WhatsnewsTargetPluginsFeatureTest.php @@ -3,10 +3,12 @@ namespace Tests\Feature\Plugins\User\Whatsnews; use App\Enums\ContentOpenType; +use App\Enums\PhotoalbumFrameConfig; use App\Models\Common\Buckets; use App\Models\Common\Frame; use App\Models\Common\Page; use App\Models\Common\Uploads; +use App\Models\Core\FrameConfig; use App\Models\User\Cabinets\Cabinet; use App\Models\User\Cabinets\CabinetContent; use App\Models\User\Calendars\Calendar; @@ -123,6 +125,60 @@ public function testPhotoalbumWhatsnewLinkTargetReturnsViewWithoutRedirectRespon $this->assertTrue($response->getData()['photoalbum_image_items']->contains('id', $content->id)); } + /** + * フォトアルバムの非表示アルバムと配下の写真が、新着情報に表示されないこと。 + */ + public function testPhotoalbumWhatsnewRowsExcludeHiddenFolderContents(): void + { + [$page, $bucket, $frame] = $this->createPluginFrame('photoalbums'); + + $photoalbum = Photoalbum::create([ + 'bucket_id' => $bucket->id, + 'name' => 'Test Photoalbum', + 'image_upload_max_size' => 1024, + 'image_upload_max_px' => 1024, + 'video_upload_max_size' => 1024, + ]); + + $root = PhotoalbumContent::create([ + 'photoalbum_id' => $photoalbum->id, + 'upload_id' => null, + 'poster_upload_id' => null, + 'name' => $photoalbum->name, + 'is_folder' => PhotoalbumContent::is_folder_on, + 'parent_id' => null, + ]); + + $hidden_folder = $root->children()->create([ + 'photoalbum_id' => $photoalbum->id, + 'upload_id' => null, + 'poster_upload_id' => null, + 'name' => '非表示アルバム', + 'is_folder' => PhotoalbumContent::is_folder_on, + 'is_cover' => PhotoalbumContent::is_cover_off, + ]); + + $this->createPhotoalbumImageContent($page, $root, '公開写真', '公開写真の説明です。'); + $this->createPhotoalbumImageContent($page, $hidden_folder, '非表示写真', '非表示写真の説明です。'); + + FrameConfig::create([ + 'frame_id' => $frame->id, + 'name' => PhotoalbumFrameConfig::hidden_folder_ids, + 'value' => (string) $hidden_folder->id, + ]); + + [$photoalbum_query] = PhotoalbumsPlugin::getWhatsnewArgs(); + + $post_titles = $photoalbum_query + ->where('frames.id', $frame->id) + ->pluck('post_title') + ->all(); + + $this->assertContains('公開写真', $post_titles); + $this->assertNotContains('非表示アルバム', $post_titles); + $this->assertNotContains('非表示写真', $post_titles); + } + /** * 指定プラグイン用のページ・バケツ・フレームをまとめて作成する。 */ @@ -270,4 +326,35 @@ private function createPhotoalbumContent(string $name, string $description): Pho 'mimetype' => 'image/jpeg', ]); } + + /** + * 指定したアルバム配下に新着対象の画像を作成する。 + */ + private function createPhotoalbumImageContent( + Page $page, + PhotoalbumContent $parent, + string $name, + string $description + ): PhotoalbumContent { + $upload = Uploads::create([ + 'client_original_name' => "{$name}.jpg", + 'mimetype' => 'image/jpeg', + 'extension' => 'jpg', + 'size' => 123, + 'plugin_name' => 'photoalbums', + 'page_id' => $page->id, + 'temporary_flag' => 0, + ]); + + return $parent->children()->create([ + 'photoalbum_id' => $parent->photoalbum_id, + 'upload_id' => $upload->id, + 'poster_upload_id' => null, + 'name' => $name, + 'description' => $description, + 'is_folder' => PhotoalbumContent::is_folder_off, + 'is_cover' => PhotoalbumContent::is_cover_off, + 'mimetype' => 'image/jpeg', + ]); + } } From cbc09e8adc581fb2a3a6683e4a69bc405bef0a87 Mon Sep 17 00:00:00 2001 From: masaton0216 Date: Wed, 20 May 2026 15:12:57 +0900 Subject: [PATCH 19/49] =?UTF-8?q?fix:=20=E3=82=B3=E3=82=A2=20MS365?= =?UTF-8?q?=E3=83=A1=E3=83=BC=E3=83=AB=E8=AA=8D=E8=A8=BC=20=E6=B7=BB?= =?UTF-8?q?=E4=BB=98=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=A7=E6=9C=AC?= =?UTF-8?q?=E6=96=87=E3=81=8C=E4=B8=8A=E6=9B=B8=E3=81=8D=E3=81=95=E3=82=8C?= =?UTF-8?q?=E3=81=A6=E3=81=97=E3=81=BE=E3=81=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Transport/MicrosoftGraphTransport.php | 10 ++ .../Transport/MicrosoftGraphTransportTest.php | 96 +++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/app/Mail/Transport/MicrosoftGraphTransport.php b/app/Mail/Transport/MicrosoftGraphTransport.php index b12ea4d17..4627f0590 100644 --- a/app/Mail/Transport/MicrosoftGraphTransport.php +++ b/app/Mail/Transport/MicrosoftGraphTransport.php @@ -194,6 +194,10 @@ protected function getContentType(Swift_Mime_SimpleMessage $message): string /** * メール本文を取得 * + * 本文パートと添付ファイルは同じ children に並ぶため、 + * Swift_Attachment は本文候補から除外する。 + * (除外しないと text/html や text/plain の添付ファイルの中身が本文として返ってしまう) + * * @param Swift_Mime_SimpleMessage $message * @return string */ @@ -204,12 +208,18 @@ protected function getBody(Swift_Mime_SimpleMessage $message): string // マルチパートの場合、HTMLパートを優先 if ($message->getChildren()) { foreach ($message->getChildren() as $child) { + if ($child instanceof \Swift_Attachment) { + continue; + } if (strpos($child->getContentType(), self::CONTENT_TYPE_HTML) !== false) { return $child->getBody(); } } // HTMLが見つからなければテキストパート foreach ($message->getChildren() as $child) { + if ($child instanceof \Swift_Attachment) { + continue; + } if (strpos($child->getContentType(), self::CONTENT_TYPE_PLAIN) !== false) { return $child->getBody(); } diff --git a/tests/Unit/Mail/Transport/MicrosoftGraphTransportTest.php b/tests/Unit/Mail/Transport/MicrosoftGraphTransportTest.php index 0a4f20c63..46320a4d3 100644 --- a/tests/Unit/Mail/Transport/MicrosoftGraphTransportTest.php +++ b/tests/Unit/Mail/Transport/MicrosoftGraphTransportTest.php @@ -695,4 +695,100 @@ public function testConvertToGraphMessageWithoutAttachment(): void // 添付ファイルがない場合はattachmentsキーが存在しない $this->assertArrayNotHasKey('attachments', $graph_message); } + + /** + * 本文取得テスト:HTML添付ファイルは本文として採用されない + * + * text/html な Swift_Attachment が children に含まれていても、 + * 本文パート(text/plain の MimePart)が優先されること。 + */ + public function testGetBodyIgnoresHtmlAttachment(): void + { + // 本文パート(text/plain) + $text_part = $this->createMock(\Swift_Mime_MimePart::class); + $text_part->method('getContentType')->willReturn('text/plain'); + $text_part->method('getBody')->willReturn('テキスト本文'); + + // 添付ファイル(text/html) + $html_attachment = $this->createMock(\Swift_Attachment::class); + $html_attachment->method('getContentType')->willReturn('text/html'); + $html_attachment->method('getBody')->willReturn('添付HTMLの中身'); + + // メッセージのモック(本文 + HTML添付) + $message = $this->createMock(Swift_Mime_SimpleMessage::class); + $message->method('getBody')->willReturn('デフォルト本文'); + $message->method('getChildren')->willReturn([$text_part, $html_attachment]); + + $reflection = new \ReflectionClass($this->transport); + $method = $reflection->getMethod('getBody'); + $method->setAccessible(true); + + $body = $method->invoke($this->transport, $message); + + // HTML添付の中身ではなく、本文パートのテキストが返ること + $this->assertEquals('テキスト本文', $body); + } + + /** + * 本文取得テスト:テキスト添付ファイルは本文として採用されない + * + * text/plain な Swift_Attachment が children に含まれていても、 + * 本文パート(text/html の MimePart)が優先されること。 + */ + public function testGetBodyIgnoresTextAttachment(): void + { + // 本文パート(text/html) + $html_part = $this->createMock(\Swift_Mime_MimePart::class); + $html_part->method('getContentType')->willReturn('text/html'); + $html_part->method('getBody')->willReturn('

HTML本文

'); + + // 添付ファイル(text/plain) + $text_attachment = $this->createMock(\Swift_Attachment::class); + $text_attachment->method('getContentType')->willReturn('text/plain'); + $text_attachment->method('getBody')->willReturn('添付テキストの中身'); + + // メッセージのモック(本文 + テキスト添付) + $message = $this->createMock(Swift_Mime_SimpleMessage::class); + $message->method('getBody')->willReturn('デフォルト本文'); + $message->method('getChildren')->willReturn([$html_part, $text_attachment]); + + $reflection = new \ReflectionClass($this->transport); + $method = $reflection->getMethod('getBody'); + $method->setAccessible(true); + + $body = $method->invoke($this->transport, $message); + + // テキスト添付の中身ではなく、本文パートのHTMLが返ること + $this->assertEquals('

HTML本文

', $body); + } + + /** + * 本文取得テスト:children が添付ファイルのみの場合はデフォルト本文を返す + */ + public function testGetBodyReturnsDefaultWhenOnlyAttachments(): void + { + // 添付ファイル1(text/html) + $html_attachment = $this->createMock(\Swift_Attachment::class); + $html_attachment->method('getContentType')->willReturn('text/html'); + $html_attachment->method('getBody')->willReturn('添付HTML'); + + // 添付ファイル2(text/plain) + $text_attachment = $this->createMock(\Swift_Attachment::class); + $text_attachment->method('getContentType')->willReturn('text/plain'); + $text_attachment->method('getBody')->willReturn('添付テキスト'); + + // メッセージのモック(本文 MimePart なし、添付のみ) + $message = $this->createMock(Swift_Mime_SimpleMessage::class); + $message->method('getBody')->willReturn('シングルパート本文'); + $message->method('getChildren')->willReturn([$html_attachment, $text_attachment]); + + $reflection = new \ReflectionClass($this->transport); + $method = $reflection->getMethod('getBody'); + $method->setAccessible(true); + + $body = $method->invoke($this->transport, $message); + + // 添付の中身ではなく、メッセージ本体(デフォルト本文)が返ること + $this->assertEquals('シングルパート本文', $body); + } } From 894cef76418a33ff8426f76e681c14aa59bd9998 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Wed, 20 May 2026 17:34:29 +0900 Subject: [PATCH 20/49] feat(calendars): add recurring event registration --- app/Models/User/Calendars/CalendarPost.php | 1 + .../User/Calendars/CalendarsPlugin.php | 299 +++++++++++++-- ..._add_repeat_group_id_to_calendar_posts.php | 34 ++ .../user/calendars/default/edit.blade.php | 77 ++++ .../CalendarsRepeatPostsFeatureTest.php | 359 ++++++++++++++++++ 5 files changed, 745 insertions(+), 25 deletions(-) create mode 100644 database/migrations/2026_05_20_010000_add_repeat_group_id_to_calendar_posts.php create mode 100644 tests/Feature/Plugins/User/Calendars/CalendarsRepeatPostsFeatureTest.php diff --git a/app/Models/User/Calendars/CalendarPost.php b/app/Models/User/Calendars/CalendarPost.php index a04d74b7c..ea340403d 100644 --- a/app/Models/User/Calendars/CalendarPost.php +++ b/app/Models/User/Calendars/CalendarPost.php @@ -36,6 +36,7 @@ class CalendarPost extends Model 'body', 'location', 'contact', + 'repeat_group_id', ]; /** diff --git a/app/Plugins/User/Calendars/CalendarsPlugin.php b/app/Plugins/User/Calendars/CalendarsPlugin.php index 8f91b5118..b6b1e0db0 100644 --- a/app/Plugins/User/Calendars/CalendarsPlugin.php +++ b/app/Plugins/User/Calendars/CalendarsPlugin.php @@ -6,6 +6,7 @@ use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Validator; +use Illuminate\Support\Str; use App\Enums\StatusType; @@ -37,6 +38,9 @@ */ class CalendarsPlugin extends UserPluginBase { + /** 繰り返し予定の最大登録件数 */ + private const REPEAT_MAX_OCCURRENCES = 200; + /* オブジェクト変数 */ /** @@ -374,6 +378,9 @@ public function edit($request, $page_id, $frame_id, $post_id = null) */ public function save($request, $page_id, $frame_id, $post_id = null) { + $repeat_type = $request->get('repeat_type') ?: 'none'; + $request->merge(['repeat_type' => $repeat_type]); + // 項目のエラーチェック $validator = Validator::make($request->all(), [ 'title' => ['required', 'max:191'], @@ -381,6 +388,9 @@ public function save($request, $page_id, $frame_id, $post_id = null) 'location' => ['nullable', 'max:191'], 'contact' => ['nullable', 'max:191'], 'start_date' => ['required', 'date'], + 'repeat_type' => ['nullable', 'in:none,weekly,monthly_date,monthly_weekday'], + 'repeat_until' => ['nullable', 'required_unless:repeat_type,none', 'date'], + 'repeat_edit_type' => ['nullable', 'in:only,after,all'], ]); $validator->setAttributeNames([ 'title' => 'タイトル', @@ -388,6 +398,9 @@ public function save($request, $page_id, $frame_id, $post_id = null) 'location' => '場所', 'contact' => '連絡先', 'start_date' => '開始日時', + 'repeat_type' => '繰り返し', + 'repeat_until' => '繰り返し終了日', + 'repeat_edit_type' => '変更範囲', ]); // エラーがあった場合は入力画面に戻る。 if ($validator->fails()) { @@ -410,48 +423,250 @@ public function save($request, $page_id, $frame_id, $post_id = null) } } - // POSTデータのモデル取得 - $post = CalendarPost::firstOrNew(['id' => $post_id]); + $base_post = null; + if (!empty($post_id)) { + $base_post = $this->getPost($post_id); + if (empty($base_post->id)) { + return; + } + } + + if ($repeat_type !== 'none' && !empty($post_id)) { + $validator = Validator::make($request->all(), []); + $validator->errors()->add('repeat_type', '繰り返し予定は新規登録時のみ設定できます。'); + return back()->withErrors($validator)->withInput(); + } + + $repeat_dates = [$request->start_date]; + if ($repeat_type !== 'none') { + if ($request->repeat_until < $request->start_date) { + $validator = Validator::make($request->all(), []); + $validator->errors()->add('repeat_until', '繰り返し終了日が開始日の前は設定できません。'); + return back()->withErrors($validator)->withInput(); + } + + $repeat_dates = $this->getRepeatStartDates($request->start_date, $request->repeat_until, $repeat_type); + if (count($repeat_dates) > self::REPEAT_MAX_OCCURRENCES) { + $validator = Validator::make($request->all(), []); + $validator->errors()->add('repeat_until', '繰り返し予定は一度に' . self::REPEAT_MAX_OCCURRENCES . '件まで登録できます。'); + return back()->withErrors($validator)->withInput(); + } + } // フレームから calendar_id 取得 $calendar_frame = $this->getPluginFrame($frame_id); - // 値のセット - $post->calendar_id = $calendar_frame->calendar_id; - $post->allday_flag = $request->get('allday_flag'); - $post->start_date = $request->start_date; - $post->start_time = $request->start_time; - $post->end_date = $request->end_date; - $post->end_time = $request->end_time; - $post->title = $request->title; - $post->body = $this->clean($request->body); // wysiwygのXSS対応のJavaScript等の制限 - $post->location = $request->location; - $post->contact = $request->contact; - - // bugfix: 【カレンダー】承認機能ONで一般が書き込んだ内容を、管理者が編集すると、以後その予定が一般で編集できなくなるバグ修正. created_idは UserableNohistory で自動セットするよう修正 - // 投稿者をセット - // if (Auth::check()) { - // $post->created_id = Auth::user()->id; - // } - // 承認の要否確認とステータス処理 if ($request->status == StatusType::temporary) { - $post->status = StatusType::temporary; // 一時保存 + $status = StatusType::temporary; // 一時保存 // } elseif ($this->buckets->needApprovalUser(Auth::user())) { } elseif ($this->isApproval()) { - $post->status = StatusType::approval_pending; // 承認待ち + $status = StatusType::approval_pending; // 承認待ち } else { - $post->status = StatusType::active; // 公開 + $status = StatusType::active; // 公開 } // 保存 - $post->save(); + if (!empty($base_post)) { + DB::transaction(function () use ($request, $base_post, $calendar_frame, $status) { + $posts = $this->getRepeatEditPosts($base_post, $request->get('repeat_edit_type', 'only')); + foreach ($posts as $post) { + $start_date = $this->getShiftedDate($post->start_date, $base_post->start_date, $request->start_date); + $end_date = $this->getShiftedEndDate($post, $base_post, $request, $start_date); + $this->setPostValues($post, $request, $calendar_frame->calendar_id, $status, $start_date, null, $end_date); + $post->save(); + } + }); + } else { + $repeat_group_id = count($repeat_dates) > 1 ? (string)Str::uuid() : null; + DB::transaction(function () use ($request, $calendar_frame, $status, $repeat_dates, $repeat_group_id) { + foreach ($repeat_dates as $repeat_date) { + $post = new CalendarPost(); + $this->setPostValues($post, $request, $calendar_frame->calendar_id, $status, $repeat_date, $repeat_group_id); + $post->save(); + } + }); + } // 登録後は初期表示へ // return new Collection(['redirect_path' => url('/') . "/plugin/calendars/edit/" . $page_id . "/" . $frame_id . "/" . $post->id . "#frame-" . $frame_id]); return collect(['redirect_path' => url($this->page->permanent_link) . "#frame-{$frame_id}"]); } + /** + * 繰り返し予定の編集対象を取得する。 + */ + private function getRepeatEditPosts(CalendarPost $post, string $repeat_edit_type): Collection + { + if (empty($post->repeat_group_id) || $repeat_edit_type === 'only') { + return new Collection([$post]); + } + + $query = CalendarPost::where('calendar_id', $post->calendar_id) + ->where('repeat_group_id', $post->repeat_group_id) + ->orderBy('start_date') + ->orderBy('id'); + + if ($repeat_edit_type === 'after') { + $query->where(function ($query) use ($post) { + $query->where('start_date', '>', $post->start_date) + ->orWhere(function ($query) use ($post) { + $query->where('start_date', $post->start_date) + ->where('id', '>=', $post->id); + }); + }); + } elseif ($repeat_edit_type !== 'all') { + return new Collection([$post]); + } + + return $query->get(); + } + + /** + * 基準予定からの差分で日付をずらす。 + */ + private function getShiftedDate(string $target_date, string $base_date, string $new_base_date): string + { + $diff_days = CarbonImmutable::parse($base_date)->diffInDays(CarbonImmutable::parse($new_base_date), false); + return CarbonImmutable::parse($target_date)->addDays($diff_days)->format('Y-m-d'); + } + + /** + * 編集対象の終了日を取得する。 + */ + private function getShiftedEndDate(CalendarPost $post, CalendarPost $base_post, $request, string $start_date): string + { + if (empty($request->end_date)) { + return $start_date; + } + + $base_end_date = empty($base_post->end_date) ? $base_post->start_date : $base_post->end_date; + $post_end_date = empty($post->end_date) ? $post->start_date : $post->end_date; + return $this->getShiftedDate($post_end_date, $base_end_date, $request->end_date); + } + + /** + * 登録する予定の値をセットする。 + */ + private function setPostValues( + CalendarPost $post, + $request, + int $calendar_id, + int $status, + string $start_date, + ?string $repeat_group_id, + ?string $end_date = null + ): void { + $post->calendar_id = $calendar_id; + $post->allday_flag = $request->get('allday_flag'); + $post->start_date = $start_date; + $post->start_time = $request->start_time; + $post->end_date = $end_date ?? $this->getRepeatedEndDate($request->start_date, $request->end_date, $start_date); + $post->end_time = $request->end_time; + $post->title = $request->title; + $post->body = $this->clean($request->body); // wysiwygのXSS対応のJavaScript等の制限 + $post->location = $request->location; + $post->contact = $request->contact; + if (empty($post->id) || !empty($repeat_group_id)) { + $post->repeat_group_id = $repeat_group_id; + } + $post->status = $status; + } + + /** + * 繰り返し予定の開始日一覧を取得する。 + */ + private function getRepeatStartDates(string $start_date, string $repeat_until, string $repeat_type): array + { + $start = CarbonImmutable::parse($start_date); + $until = CarbonImmutable::parse($repeat_until); + + if ($repeat_type === 'weekly') { + return $this->getWeeklyRepeatStartDates($start, $until); + } + if ($repeat_type === 'monthly_date') { + return $this->getMonthlyDateRepeatStartDates($start, $until); + } + if ($repeat_type === 'monthly_weekday') { + return $this->getMonthlyWeekdayRepeatStartDates($start, $until); + } + + return [$start->format('Y-m-d')]; + } + + /** + * 毎週の開始日一覧を取得する。 + */ + private function getWeeklyRepeatStartDates(CarbonImmutable $start, CarbonImmutable $until): array + { + $dates = []; + for ($date = $start; $date->lte($until); $date = $date->addWeek()) { + $dates[] = $date->format('Y-m-d'); + } + return $dates; + } + + /** + * 毎月同日の開始日一覧を取得する。存在しない日付の月は登録しない。 + */ + private function getMonthlyDateRepeatStartDates(CarbonImmutable $start, CarbonImmutable $until): array + { + $dates = []; + $day = $start->day; + + for ($date = $start->startOfMonth(); $date->lte($until); $date = $date->addMonthNoOverflow()) { + if (!checkdate($date->month, $day, $date->year)) { + continue; + } + + $repeat_date = $date->setDay($day); + if ($repeat_date->lt($start) || $repeat_date->gt($until)) { + continue; + } + + $dates[] = $repeat_date->format('Y-m-d'); + } + + return $dates; + } + + /** + * 毎月第n曜日の開始日一覧を取得する。該当する第n曜日がない月は登録しない。 + */ + private function getMonthlyWeekdayRepeatStartDates(CarbonImmutable $start, CarbonImmutable $until): array + { + $dates = []; + $week_number = (int)ceil($start->day / 7); + $day_of_week = $start->dayOfWeek; + + for ($date = $start->startOfMonth(); $date->lte($until); $date = $date->addMonthNoOverflow()) { + $repeat_date = $date->firstOfMonth($day_of_week)->addWeeks($week_number - 1); + if ($repeat_date->month !== $date->month || $repeat_date->lt($start) || $repeat_date->gt($until)) { + continue; + } + + $dates[] = $repeat_date->format('Y-m-d'); + } + + return $dates; + } + + /** + * 繰り返し後の終了日を取得する。 + */ + private function getRepeatedEndDate(string $base_start_date, ?string $base_end_date, string $repeated_start_date): string + { + if (empty($base_end_date)) { + return $repeated_start_date; + } + + $base_start = CarbonImmutable::parse($base_start_date); + $base_end = CarbonImmutable::parse($base_end_date); + $repeated_start = CarbonImmutable::parse($repeated_start_date); + + return $repeated_start->addDays($base_start->diffInDays($base_end))->format('Y-m-d'); + } + /** * 承認処理 */ @@ -481,8 +696,15 @@ public function delete($request, $page_id, $frame_id, $post_id) { // id がある場合、データを削除 if ($post_id) { + $post = $this->getPost($post_id); + if (empty($post->id)) { + return; + } + + $delete_post_ids = $this->getDeletePostIds($post, $request->get('repeat_delete_type', 'only')); + // データを削除する。(論理削除で削除日、ID などを残すためにupdate) - CalendarPost::where('id', $post_id)->update([ + CalendarPost::whereIn('id', $delete_post_ids)->update([ 'deleted_at' => date('Y-m-d H:i:s'), 'deleted_id' => Auth::user()->id, 'deleted_name' => Auth::user()->name, @@ -491,6 +713,33 @@ public function delete($request, $page_id, $frame_id, $post_id) return; } + /** + * 削除対象の予定IDを取得する。 + */ + private function getDeletePostIds(CalendarPost $post, string $repeat_delete_type): array + { + if (empty($post->repeat_group_id) || $repeat_delete_type === 'only') { + return [$post->id]; + } + + $query = CalendarPost::where('calendar_id', $post->calendar_id) + ->where('repeat_group_id', $post->repeat_group_id); + + if ($repeat_delete_type === 'after') { + $query->where(function ($query) use ($post) { + $query->where('start_date', '>', $post->start_date) + ->orWhere(function ($query) use ($post) { + $query->where('start_date', $post->start_date) + ->where('id', '>=', $post->id); + }); + }); + } elseif ($repeat_delete_type !== 'all') { + return [$post->id]; + } + + return $query->pluck('id')->all(); + } + /** * プラグインのバケツ選択表示関数 * diff --git a/database/migrations/2026_05_20_010000_add_repeat_group_id_to_calendar_posts.php b/database/migrations/2026_05_20_010000_add_repeat_group_id_to_calendar_posts.php new file mode 100644 index 000000000..79de63542 --- /dev/null +++ b/database/migrations/2026_05_20_010000_add_repeat_group_id_to_calendar_posts.php @@ -0,0 +1,34 @@ +string('repeat_group_id', 36)->nullable()->after('contact')->comment('繰り返し予定グループID'); + $table->index('repeat_group_id'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('calendar_posts', function (Blueprint $table) { + $table->dropIndex(['repeat_group_id']); + $table->dropColumn('repeat_group_id'); + }); + } +} diff --git a/resources/views/plugins/user/calendars/default/edit.blade.php b/resources/views/plugins/user/calendars/default/edit.blade.php index 6a3b1224b..72a29fc80 100644 --- a/resources/views/plugins/user/calendars/default/edit.blade.php +++ b/resources/views/plugins/user/calendars/default/edit.blade.php @@ -40,6 +40,18 @@ function check_allday() { } +{{-- 繰り返し予定の終了日を制御 --}} + + @if ($errors && $errors->has('reply_role_error'))
{{$errors->first('reply_role_error')}} @@ -177,6 +189,55 @@ function check_allday() { @include('plugins.common.errors_inline', ['name' => 'end_date', 'class' => $errors_div_class])
+ @if (empty($post->id)) +
+ +
+ + @include('plugins.common.errors_inline', ['name' => 'repeat_type']) +
+
+
+ +
+
+
+
+ @include('plugins.common.datetimepicker', ['element_id' => 'repeat_until' . $frame_id, 'format' => 'yyyy-MM-dd', 'clock_icon' => false]) +
+
+ 指定日まで同じ予定を登録します。 +
+
+
+ @include('plugins.common.errors_inline', ['name' => 'repeat_until', 'class' => $errors_div_class]) +
+ @elseif (!empty($post->repeat_group_id)) +
+ +
+
+ + +
+
+ + +
+
+ + +
+ @include('plugins.common.errors_inline', ['name' => 'repeat_edit_type']) +
+
+ @endif +
@@ -254,6 +315,22 @@ function check_allday() { {{csrf_field()}} + @if (!empty($post->repeat_group_id)) +
+
+ + +
+
+ + +
+
+ + +
+
+ @endif
diff --git a/tests/Feature/Plugins/User/Calendars/CalendarsRepeatPostsFeatureTest.php b/tests/Feature/Plugins/User/Calendars/CalendarsRepeatPostsFeatureTest.php new file mode 100644 index 000000000..14a540834 --- /dev/null +++ b/tests/Feature/Plugins/User/Calendars/CalendarsRepeatPostsFeatureTest.php @@ -0,0 +1,359 @@ +seed(); + } + + /** + * 毎週の繰り返し指定では、開始日と同じ曜日の予定が終了日まで作成されること。 + */ + public function testSaveCreatesWeeklyRepeatPosts(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame, $calendar] = $this->createCalendarFrame(); + + $response = $this->actingAs($admin)->post( + "/redirect/plugin/calendars/save/{$page->id}/{$frame->id}", + $this->makePayload([ + 'title' => '毎週の定例会', + 'start_date' => '2026-06-01', + 'start_time' => '10:00', + 'end_date' => '2026-06-01', + 'end_time' => '11:00', + 'repeat_type' => 'weekly', + 'repeat_until' => '2026-06-22', + ]) + ); + + $this->assertContains($response->getStatusCode(), [200, 302]); + + foreach (['2026-06-01', '2026-06-08', '2026-06-15', '2026-06-22'] as $date) { + $this->assertDatabaseHas('calendar_posts', [ + 'calendar_id' => $calendar->id, + 'title' => '毎週の定例会', + 'start_date' => $date, + 'end_date' => $date, + 'status' => StatusType::active, + ]); + } + + $this->assertSame(4, CalendarPost::where('calendar_id', $calendar->id)->count()); + $this->assertSame(1, CalendarPost::where('calendar_id', $calendar->id)->distinct()->count('repeat_group_id')); + } + + /** + * 毎月第n曜日の繰り返し指定では、開始日と同じ第n曜日だけが作成されること。 + */ + public function testSaveCreatesMonthlyWeekdayRepeatPosts(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame, $calendar] = $this->createCalendarFrame(); + + $response = $this->actingAs($admin)->post( + "/redirect/plugin/calendars/save/{$page->id}/{$frame->id}", + $this->makePayload([ + 'title' => '毎月第2火曜の定例会', + 'start_date' => '2026-05-12', + 'start_time' => '13:00', + 'end_date' => '2026-05-12', + 'end_time' => '14:00', + 'repeat_type' => 'monthly_weekday', + 'repeat_until' => '2026-08-31', + ]) + ); + + $this->assertContains($response->getStatusCode(), [200, 302]); + + foreach (['2026-05-12', '2026-06-09', '2026-07-14', '2026-08-11'] as $date) { + $this->assertDatabaseHas('calendar_posts', [ + 'calendar_id' => $calendar->id, + 'title' => '毎月第2火曜の定例会', + 'start_date' => $date, + 'end_date' => $date, + 'status' => StatusType::active, + ]); + } + + $this->assertSame(4, CalendarPost::where('calendar_id', $calendar->id)->count()); + $this->assertSame(1, CalendarPost::where('calendar_id', $calendar->id)->distinct()->count('repeat_group_id')); + } + + /** + * 繰り返し予定の「これ以降」削除では、選択した予定より前の予定が残ること。 + */ + public function testDeleteRepeatPostsAfterSelectedDate(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame, $calendar] = $this->createCalendarFrame(); + $this->createWeeklyRepeatPosts($admin, $page, $frame); + + $target = CalendarPost::where('calendar_id', $calendar->id) + ->where('start_date', '2026-06-15') + ->firstOrFail(); + + $response = $this->actingAs($admin)->post( + "/redirect/plugin/calendars/delete/{$page->id}/{$frame->id}/{$target->id}", + [ + 'redirect_path' => '/', + 'repeat_delete_type' => 'after', + ] + ); + + $this->assertContains($response->getStatusCode(), [200, 302]); + $this->assertSame( + ['2026-06-01', '2026-06-08'], + CalendarPost::where('calendar_id', $calendar->id)->orderBy('start_date')->pluck('start_date')->all() + ); + $this->assertSoftDeleted('calendar_posts', ['id' => $target->id]); + } + + /** + * 繰り返し予定の1件を編集しても、同じ繰り返しグループとして削除できる状態が残ること。 + */ + public function testUpdateRepeatPostKeepsRepeatGroup(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame, $calendar] = $this->createCalendarFrame(); + $this->createWeeklyRepeatPosts($admin, $page, $frame); + + $target = CalendarPost::where('calendar_id', $calendar->id) + ->where('start_date', '2026-06-08') + ->firstOrFail(); + $repeat_group_id = $target->repeat_group_id; + + $response = $this->actingAs($admin)->post( + "/redirect/plugin/calendars/save/{$page->id}/{$frame->id}/{$target->id}", + [ + 'redirect_path' => '/', + 'status' => StatusType::active, + 'allday_flag' => 0, + 'title' => '編集後の定例会', + 'start_date' => '2026-06-08', + 'start_time' => '10:30', + 'end_date' => '2026-06-08', + 'end_time' => '11:30', + 'body' => '', + 'location' => '', + 'contact' => '', + ] + ); + + $this->assertContains($response->getStatusCode(), [200, 302]); + $this->assertDatabaseHas('calendar_posts', [ + 'id' => $target->id, + 'title' => '編集後の定例会', + 'repeat_group_id' => $repeat_group_id, + ]); + $this->assertSame(4, CalendarPost::where('repeat_group_id', $repeat_group_id)->count()); + $this->assertSame(1, CalendarPost::where('repeat_group_id', $repeat_group_id)->where('title', '編集後の定例会')->count()); + $this->assertSame(3, CalendarPost::where('repeat_group_id', $repeat_group_id)->where('title', '毎週の定例会')->count()); + } + + /** + * 繰り返し予定の「これ以降」編集では、選択した予定以降へ同じ差分が反映されること。 + */ + public function testUpdateRepeatPostsAfterSelectedDate(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame, $calendar] = $this->createCalendarFrame(); + $this->createWeeklyRepeatPosts($admin, $page, $frame); + + $target = CalendarPost::where('calendar_id', $calendar->id) + ->where('start_date', '2026-06-08') + ->firstOrFail(); + + $response = $this->actingAs($admin)->post( + "/redirect/plugin/calendars/save/{$page->id}/{$frame->id}/{$target->id}", + [ + 'redirect_path' => '/', + 'status' => StatusType::active, + 'allday_flag' => 0, + 'title' => '以降の定例会', + 'start_date' => '2026-06-09', + 'start_time' => '11:00', + 'end_date' => '2026-06-09', + 'end_time' => '12:00', + 'body' => '', + 'location' => '', + 'contact' => '', + 'repeat_edit_type' => 'after', + ] + ); + + $this->assertContains($response->getStatusCode(), [200, 302]); + $this->assertSame( + ['2026-06-01', '2026-06-09', '2026-06-16', '2026-06-23'], + CalendarPost::where('calendar_id', $calendar->id)->orderBy('start_date')->pluck('start_date')->all() + ); + $this->assertDatabaseHas('calendar_posts', [ + 'calendar_id' => $calendar->id, + 'start_date' => '2026-06-01', + 'title' => '毎週の定例会', + 'start_time' => '10:00:00', + ]); + $this->assertSame(3, CalendarPost::where('calendar_id', $calendar->id)->where('title', '以降の定例会')->count()); + } + + /** + * 繰り返し予定の「すべて」編集では、同じ繰り返しグループの予定がすべて更新されること。 + */ + public function testUpdateAllRepeatPosts(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame, $calendar] = $this->createCalendarFrame(); + $this->createWeeklyRepeatPosts($admin, $page, $frame); + + $target = CalendarPost::where('calendar_id', $calendar->id) + ->where('start_date', '2026-06-08') + ->firstOrFail(); + $repeat_group_id = $target->repeat_group_id; + + $response = $this->actingAs($admin)->post( + "/redirect/plugin/calendars/save/{$page->id}/{$frame->id}/{$target->id}", + [ + 'redirect_path' => '/', + 'status' => StatusType::active, + 'allday_flag' => 0, + 'title' => '全体変更後の定例会', + 'start_date' => '2026-06-08', + 'start_time' => '10:30', + 'end_date' => '2026-06-08', + 'end_time' => '11:30', + 'body' => '全体変更', + 'location' => '会議室A', + 'contact' => '担当者', + 'repeat_edit_type' => 'all', + ] + ); + + $this->assertContains($response->getStatusCode(), [200, 302]); + $this->assertSame(4, CalendarPost::where('repeat_group_id', $repeat_group_id)->count()); + $this->assertSame(4, CalendarPost::where('repeat_group_id', $repeat_group_id)->where('title', '全体変更後の定例会')->count()); + $this->assertSame(4, CalendarPost::where('repeat_group_id', $repeat_group_id)->where('location', '会議室A')->count()); + } + + /** + * 繰り返し予定の「すべて」削除では、同じ繰り返しグループの予定がすべて消えること。 + */ + public function testDeleteAllRepeatPosts(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame, $calendar] = $this->createCalendarFrame(); + $this->createWeeklyRepeatPosts($admin, $page, $frame); + + $target = CalendarPost::where('calendar_id', $calendar->id) + ->where('start_date', '2026-06-08') + ->firstOrFail(); + $repeat_group_id = $target->repeat_group_id; + + $response = $this->actingAs($admin)->post( + "/redirect/plugin/calendars/delete/{$page->id}/{$frame->id}/{$target->id}", + [ + 'redirect_path' => '/', + 'repeat_delete_type' => 'all', + ] + ); + + $this->assertContains($response->getStatusCode(), [200, 302]); + $this->assertSame(0, CalendarPost::where('calendar_id', $calendar->id)->count()); + $this->assertSame( + 4, + CalendarPost::onlyTrashed()->where('repeat_group_id', $repeat_group_id)->count() + ); + } + + /** + * 指定フレームに紐づくカレンダーを作成する。 + */ + private function createCalendarFrame(): array + { + $page = Page::factory()->create(); + $bucket = Buckets::factory()->create([ + 'bucket_name' => '繰り返し予定テスト', + 'plugin_name' => 'calendars', + ]); + $calendar = Calendar::create([ + 'bucket_id' => $bucket->id, + 'name' => '繰り返し予定テスト', + ]); + $frame = Frame::create([ + 'page_id' => $page->id, + 'area_id' => 2, + 'plugin_name' => 'calendars', + 'bucket_id' => $bucket->id, + 'template' => 'default', + 'display_sequence' => 1, + ]); + CalendarFrame::create([ + 'calendar_id' => $calendar->id, + 'frame_id' => $frame->id, + ]); + + return [$page, $frame, $calendar]; + } + + /** + * 毎週の繰り返し予定を削除テスト用に作成する。 + */ + private function createWeeklyRepeatPosts($admin, Page $page, Frame $frame): void + { + $this->actingAs($admin)->post( + "/redirect/plugin/calendars/save/{$page->id}/{$frame->id}", + $this->makePayload([ + 'title' => '毎週の定例会', + 'start_date' => '2026-06-01', + 'start_time' => '10:00', + 'end_date' => '2026-06-01', + 'end_time' => '11:00', + 'repeat_type' => 'weekly', + 'repeat_until' => '2026-06-22', + ]) + ); + } + + /** + * 予定登録に必要な標準入力を作成する。 + */ + private function makePayload(array $overrides): array + { + return array_merge([ + 'redirect_path' => '/', + 'status' => StatusType::active, + 'allday_flag' => 0, + 'body' => '', + 'location' => '', + 'contact' => '', + 'repeat_type' => 'none', + ], $overrides); + } +} From 844348ae45d56f2db8a97a86ca47e4ae9f3a5eb6 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Wed, 20 May 2026 18:23:24 +0900 Subject: [PATCH 21/49] =?UTF-8?q?fix(uploadfile):=20=E3=82=B5=E3=83=A0?= =?UTF-8?q?=E3=83=8D=E3=82=A4=E3=83=AB=E3=81=AE=E6=8B=A1=E5=A4=A7=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/css/app.css | 2 +- public/mix-manifest.json | 2 +- resources/sass/app.scss | 1 + resources/sass/manage/_uploadfile.scss | 63 +++++++++++++++++++ .../plugins/manage/uploadfile/index.blade.php | 25 +++++--- .../uploadfile/upload_thumbnail.blade.php | 26 ++++++++ .../UploadfileManageThumbnailViewTest.php | 54 ++++++++++++++++ 7 files changed, 163 insertions(+), 10 deletions(-) create mode 100644 resources/sass/manage/_uploadfile.scss create mode 100644 resources/views/plugins/manage/uploadfile/upload_thumbnail.blade.php create mode 100644 tests/Unit/Plugins/Manage/UploadfileManage/UploadfileManageThumbnailViewTest.php diff --git a/public/css/app.css b/public/css/app.css index 3a0c9a0e4..7d24d42c6 100644 --- a/public/css/app.css +++ b/public/css/app.css @@ -27,4 +27,4 @@ * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) * Copyright 2024 Fonticons, Inc. - */:host,:root{--fa-style-family-brands:"Font Awesome 6 Brands";--fa-font-brands:normal 400 1em/1 "Font Awesome 6 Brands"}@font-face{font-display:swap;font-family:Font Awesome\ 6 Brands;font-style:normal;font-weight:400;src:url(../fonts/vendor/@fortawesome/fontawesome-free/webfa-brands-400.woff2?c210719e60948b211a1260f79812efe5) format("woff2"),url(../fonts/vendor/@fortawesome/fontawesome-free/webfa-brands-400.ttf?1815e00441357e01619e5793e1caa78a) format("truetype")}.fa-brands,.fab{font-weight:400}.fa-monero{--fa:"\f3d0"}.fa-hooli{--fa:"\f427"}.fa-yelp{--fa:"\f1e9"}.fa-cc-visa{--fa:"\f1f0"}.fa-lastfm{--fa:"\f202"}.fa-shopware{--fa:"\f5b5"}.fa-creative-commons-nc{--fa:"\f4e8"}.fa-aws{--fa:"\f375"}.fa-redhat{--fa:"\f7bc"}.fa-yoast{--fa:"\f2b1"}.fa-cloudflare{--fa:"\e07d"}.fa-ups{--fa:"\f7e0"}.fa-pixiv{--fa:"\e640"}.fa-wpexplorer{--fa:"\f2de"}.fa-dyalog{--fa:"\f399"}.fa-bity{--fa:"\f37a"}.fa-stackpath{--fa:"\f842"}.fa-buysellads{--fa:"\f20d"}.fa-first-order{--fa:"\f2b0"}.fa-modx{--fa:"\f285"}.fa-guilded{--fa:"\e07e"}.fa-vnv{--fa:"\f40b"}.fa-js-square,.fa-square-js{--fa:"\f3b9"}.fa-microsoft{--fa:"\f3ca"}.fa-qq{--fa:"\f1d6"}.fa-orcid{--fa:"\f8d2"}.fa-java{--fa:"\f4e4"}.fa-invision{--fa:"\f7b0"}.fa-creative-commons-pd-alt{--fa:"\f4ed"}.fa-centercode{--fa:"\f380"}.fa-glide-g{--fa:"\f2a6"}.fa-drupal{--fa:"\f1a9"}.fa-jxl{--fa:"\e67b"}.fa-dart-lang{--fa:"\e693"}.fa-hire-a-helper{--fa:"\f3b0"}.fa-creative-commons-by{--fa:"\f4e7"}.fa-unity{--fa:"\e049"}.fa-whmcs{--fa:"\f40d"}.fa-rocketchat{--fa:"\f3e8"}.fa-vk{--fa:"\f189"}.fa-untappd{--fa:"\f405"}.fa-mailchimp{--fa:"\f59e"}.fa-css3-alt{--fa:"\f38b"}.fa-reddit-square,.fa-square-reddit{--fa:"\f1a2"}.fa-vimeo-v{--fa:"\f27d"}.fa-contao{--fa:"\f26d"}.fa-square-font-awesome{--fa:"\e5ad"}.fa-deskpro{--fa:"\f38f"}.fa-brave{--fa:"\e63c"}.fa-sistrix{--fa:"\f3ee"}.fa-instagram-square,.fa-square-instagram{--fa:"\e055"}.fa-battle-net{--fa:"\f835"}.fa-the-red-yeti{--fa:"\f69d"}.fa-hacker-news-square,.fa-square-hacker-news{--fa:"\f3af"}.fa-edge{--fa:"\f282"}.fa-threads{--fa:"\e618"}.fa-napster{--fa:"\f3d2"}.fa-snapchat-square,.fa-square-snapchat{--fa:"\f2ad"}.fa-google-plus-g{--fa:"\f0d5"}.fa-artstation{--fa:"\f77a"}.fa-markdown{--fa:"\f60f"}.fa-sourcetree{--fa:"\f7d3"}.fa-google-plus{--fa:"\f2b3"}.fa-diaspora{--fa:"\f791"}.fa-foursquare{--fa:"\f180"}.fa-stack-overflow{--fa:"\f16c"}.fa-github-alt{--fa:"\f113"}.fa-phoenix-squadron{--fa:"\f511"}.fa-pagelines{--fa:"\f18c"}.fa-algolia{--fa:"\f36c"}.fa-red-river{--fa:"\f3e3"}.fa-creative-commons-sa{--fa:"\f4ef"}.fa-safari{--fa:"\f267"}.fa-google{--fa:"\f1a0"}.fa-font-awesome-alt,.fa-square-font-awesome-stroke{--fa:"\f35c"}.fa-atlassian{--fa:"\f77b"}.fa-linkedin-in{--fa:"\f0e1"}.fa-digital-ocean{--fa:"\f391"}.fa-nimblr{--fa:"\f5a8"}.fa-chromecast{--fa:"\f838"}.fa-evernote{--fa:"\f839"}.fa-hacker-news{--fa:"\f1d4"}.fa-creative-commons-sampling{--fa:"\f4f0"}.fa-adversal{--fa:"\f36a"}.fa-creative-commons{--fa:"\f25e"}.fa-watchman-monitoring{--fa:"\e087"}.fa-fonticons{--fa:"\f280"}.fa-weixin{--fa:"\f1d7"}.fa-shirtsinbulk{--fa:"\f214"}.fa-codepen{--fa:"\f1cb"}.fa-git-alt{--fa:"\f841"}.fa-lyft{--fa:"\f3c3"}.fa-rev{--fa:"\f5b2"}.fa-windows{--fa:"\f17a"}.fa-wizards-of-the-coast{--fa:"\f730"}.fa-square-viadeo,.fa-viadeo-square{--fa:"\f2aa"}.fa-meetup{--fa:"\f2e0"}.fa-centos{--fa:"\f789"}.fa-adn{--fa:"\f170"}.fa-cloudsmith{--fa:"\f384"}.fa-opensuse{--fa:"\e62b"}.fa-pied-piper-alt{--fa:"\f1a8"}.fa-dribbble-square,.fa-square-dribbble{--fa:"\f397"}.fa-codiepie{--fa:"\f284"}.fa-node{--fa:"\f419"}.fa-mix{--fa:"\f3cb"}.fa-steam{--fa:"\f1b6"}.fa-cc-apple-pay{--fa:"\f416"}.fa-scribd{--fa:"\f28a"}.fa-debian{--fa:"\e60b"}.fa-openid{--fa:"\f19b"}.fa-instalod{--fa:"\e081"}.fa-files-pinwheel{--fa:"\e69f"}.fa-expeditedssl{--fa:"\f23e"}.fa-sellcast{--fa:"\f2da"}.fa-square-twitter,.fa-twitter-square{--fa:"\f081"}.fa-r-project{--fa:"\f4f7"}.fa-delicious{--fa:"\f1a5"}.fa-freebsd{--fa:"\f3a4"}.fa-vuejs{--fa:"\f41f"}.fa-accusoft{--fa:"\f369"}.fa-ioxhost{--fa:"\f208"}.fa-fonticons-fi{--fa:"\f3a2"}.fa-app-store{--fa:"\f36f"}.fa-cc-mastercard{--fa:"\f1f1"}.fa-itunes-note{--fa:"\f3b5"}.fa-golang{--fa:"\e40f"}.fa-kickstarter,.fa-square-kickstarter{--fa:"\f3bb"}.fa-grav{--fa:"\f2d6"}.fa-weibo{--fa:"\f18a"}.fa-uncharted{--fa:"\e084"}.fa-firstdraft{--fa:"\f3a1"}.fa-square-youtube,.fa-youtube-square{--fa:"\f431"}.fa-wikipedia-w{--fa:"\f266"}.fa-rendact,.fa-wpressr{--fa:"\f3e4"}.fa-angellist{--fa:"\f209"}.fa-galactic-republic{--fa:"\f50c"}.fa-nfc-directional{--fa:"\e530"}.fa-skype{--fa:"\f17e"}.fa-joget{--fa:"\f3b7"}.fa-fedora{--fa:"\f798"}.fa-stripe-s{--fa:"\f42a"}.fa-meta{--fa:"\e49b"}.fa-laravel{--fa:"\f3bd"}.fa-hotjar{--fa:"\f3b1"}.fa-bluetooth-b{--fa:"\f294"}.fa-square-letterboxd{--fa:"\e62e"}.fa-sticker-mule{--fa:"\f3f7"}.fa-creative-commons-zero{--fa:"\f4f3"}.fa-hips{--fa:"\f452"}.fa-css{--fa:"\e6a2"}.fa-behance{--fa:"\f1b4"}.fa-reddit{--fa:"\f1a1"}.fa-discord{--fa:"\f392"}.fa-chrome{--fa:"\f268"}.fa-app-store-ios{--fa:"\f370"}.fa-cc-discover{--fa:"\f1f2"}.fa-wpbeginner{--fa:"\f297"}.fa-confluence{--fa:"\f78d"}.fa-shoelace{--fa:"\e60c"}.fa-mdb{--fa:"\f8ca"}.fa-dochub{--fa:"\f394"}.fa-accessible-icon{--fa:"\f368"}.fa-ebay{--fa:"\f4f4"}.fa-amazon{--fa:"\f270"}.fa-unsplash{--fa:"\e07c"}.fa-yarn{--fa:"\f7e3"}.fa-square-steam,.fa-steam-square{--fa:"\f1b7"}.fa-500px{--fa:"\f26e"}.fa-square-vimeo,.fa-vimeo-square{--fa:"\f194"}.fa-asymmetrik{--fa:"\f372"}.fa-font-awesome,.fa-font-awesome-flag,.fa-font-awesome-logo-full{--fa:"\f2b4"}.fa-gratipay{--fa:"\f184"}.fa-apple{--fa:"\f179"}.fa-hive{--fa:"\e07f"}.fa-gitkraken{--fa:"\f3a6"}.fa-keybase{--fa:"\f4f5"}.fa-apple-pay{--fa:"\f415"}.fa-padlet{--fa:"\e4a0"}.fa-amazon-pay{--fa:"\f42c"}.fa-github-square,.fa-square-github{--fa:"\f092"}.fa-stumbleupon{--fa:"\f1a4"}.fa-fedex{--fa:"\f797"}.fa-phoenix-framework{--fa:"\f3dc"}.fa-shopify{--fa:"\e057"}.fa-neos{--fa:"\f612"}.fa-square-threads{--fa:"\e619"}.fa-hackerrank{--fa:"\f5f7"}.fa-researchgate{--fa:"\f4f8"}.fa-swift{--fa:"\f8e1"}.fa-angular{--fa:"\f420"}.fa-speakap{--fa:"\f3f3"}.fa-angrycreative{--fa:"\f36e"}.fa-y-combinator{--fa:"\f23b"}.fa-empire{--fa:"\f1d1"}.fa-envira{--fa:"\f299"}.fa-google-scholar{--fa:"\e63b"}.fa-gitlab-square,.fa-square-gitlab{--fa:"\e5ae"}.fa-studiovinari{--fa:"\f3f8"}.fa-pied-piper{--fa:"\f2ae"}.fa-wordpress{--fa:"\f19a"}.fa-product-hunt{--fa:"\f288"}.fa-firefox{--fa:"\f269"}.fa-linode{--fa:"\f2b8"}.fa-goodreads{--fa:"\f3a8"}.fa-odnoklassniki-square,.fa-square-odnoklassniki{--fa:"\f264"}.fa-jsfiddle{--fa:"\f1cc"}.fa-sith{--fa:"\f512"}.fa-themeisle{--fa:"\f2b2"}.fa-page4{--fa:"\f3d7"}.fa-hashnode{--fa:"\e499"}.fa-react{--fa:"\f41b"}.fa-cc-paypal{--fa:"\f1f4"}.fa-squarespace{--fa:"\f5be"}.fa-cc-stripe{--fa:"\f1f5"}.fa-creative-commons-share{--fa:"\f4f2"}.fa-bitcoin{--fa:"\f379"}.fa-keycdn{--fa:"\f3ba"}.fa-opera{--fa:"\f26a"}.fa-itch-io{--fa:"\f83a"}.fa-umbraco{--fa:"\f8e8"}.fa-galactic-senate{--fa:"\f50d"}.fa-ubuntu{--fa:"\f7df"}.fa-draft2digital{--fa:"\f396"}.fa-stripe{--fa:"\f429"}.fa-houzz{--fa:"\f27c"}.fa-gg{--fa:"\f260"}.fa-dhl{--fa:"\f790"}.fa-pinterest-square,.fa-square-pinterest{--fa:"\f0d3"}.fa-xing{--fa:"\f168"}.fa-blackberry{--fa:"\f37b"}.fa-creative-commons-pd{--fa:"\f4ec"}.fa-playstation{--fa:"\f3df"}.fa-quinscape{--fa:"\f459"}.fa-less{--fa:"\f41d"}.fa-blogger-b{--fa:"\f37d"}.fa-opencart{--fa:"\f23d"}.fa-vine{--fa:"\f1ca"}.fa-signal-messenger{--fa:"\e663"}.fa-paypal{--fa:"\f1ed"}.fa-gitlab{--fa:"\f296"}.fa-typo3{--fa:"\f42b"}.fa-reddit-alien{--fa:"\f281"}.fa-yahoo{--fa:"\f19e"}.fa-dailymotion{--fa:"\e052"}.fa-affiliatetheme{--fa:"\f36b"}.fa-pied-piper-pp{--fa:"\f1a7"}.fa-bootstrap{--fa:"\f836"}.fa-odnoklassniki{--fa:"\f263"}.fa-nfc-symbol{--fa:"\e531"}.fa-mintbit{--fa:"\e62f"}.fa-ethereum{--fa:"\f42e"}.fa-speaker-deck{--fa:"\f83c"}.fa-creative-commons-nc-eu{--fa:"\f4e9"}.fa-patreon{--fa:"\f3d9"}.fa-avianex{--fa:"\f374"}.fa-ello{--fa:"\f5f1"}.fa-gofore{--fa:"\f3a7"}.fa-bimobject{--fa:"\f378"}.fa-brave-reverse{--fa:"\e63d"}.fa-facebook-f{--fa:"\f39e"}.fa-google-plus-square,.fa-square-google-plus{--fa:"\f0d4"}.fa-web-awesome{--fa:"\e682"}.fa-mandalorian{--fa:"\f50f"}.fa-first-order-alt{--fa:"\f50a"}.fa-osi{--fa:"\f41a"}.fa-google-wallet{--fa:"\f1ee"}.fa-d-and-d-beyond{--fa:"\f6ca"}.fa-periscope{--fa:"\f3da"}.fa-fulcrum{--fa:"\f50b"}.fa-cloudscale{--fa:"\f383"}.fa-forumbee{--fa:"\f211"}.fa-mizuni{--fa:"\f3cc"}.fa-schlix{--fa:"\f3ea"}.fa-square-xing,.fa-xing-square{--fa:"\f169"}.fa-bandcamp{--fa:"\f2d5"}.fa-wpforms{--fa:"\f298"}.fa-cloudversify{--fa:"\f385"}.fa-usps{--fa:"\f7e1"}.fa-megaport{--fa:"\f5a3"}.fa-magento{--fa:"\f3c4"}.fa-spotify{--fa:"\f1bc"}.fa-optin-monster{--fa:"\f23c"}.fa-fly{--fa:"\f417"}.fa-square-bluesky{--fa:"\e6a3"}.fa-aviato{--fa:"\f421"}.fa-itunes{--fa:"\f3b4"}.fa-cuttlefish{--fa:"\f38c"}.fa-blogger{--fa:"\f37c"}.fa-flickr{--fa:"\f16e"}.fa-viber{--fa:"\f409"}.fa-soundcloud{--fa:"\f1be"}.fa-digg{--fa:"\f1a6"}.fa-tencent-weibo{--fa:"\f1d5"}.fa-letterboxd{--fa:"\e62d"}.fa-symfony{--fa:"\f83d"}.fa-maxcdn{--fa:"\f136"}.fa-etsy{--fa:"\f2d7"}.fa-facebook-messenger{--fa:"\f39f"}.fa-audible{--fa:"\f373"}.fa-think-peaks{--fa:"\f731"}.fa-bilibili{--fa:"\e3d9"}.fa-erlang{--fa:"\f39d"}.fa-x-twitter{--fa:"\e61b"}.fa-cotton-bureau{--fa:"\f89e"}.fa-dashcube{--fa:"\f210"}.fa-42-group,.fa-innosoft{--fa:"\e080"}.fa-stack-exchange{--fa:"\f18d"}.fa-elementor{--fa:"\f430"}.fa-pied-piper-square,.fa-square-pied-piper{--fa:"\e01e"}.fa-creative-commons-nd{--fa:"\f4eb"}.fa-palfed{--fa:"\f3d8"}.fa-superpowers{--fa:"\f2dd"}.fa-resolving{--fa:"\f3e7"}.fa-xbox{--fa:"\f412"}.fa-square-web-awesome-stroke{--fa:"\e684"}.fa-searchengin{--fa:"\f3eb"}.fa-tiktok{--fa:"\e07b"}.fa-facebook-square,.fa-square-facebook{--fa:"\f082"}.fa-renren{--fa:"\f18b"}.fa-linux{--fa:"\f17c"}.fa-glide{--fa:"\f2a5"}.fa-linkedin{--fa:"\f08c"}.fa-hubspot{--fa:"\f3b2"}.fa-deploydog{--fa:"\f38e"}.fa-twitch{--fa:"\f1e8"}.fa-flutter{--fa:"\e694"}.fa-ravelry{--fa:"\f2d9"}.fa-mixer{--fa:"\e056"}.fa-lastfm-square,.fa-square-lastfm{--fa:"\f203"}.fa-vimeo{--fa:"\f40a"}.fa-mendeley{--fa:"\f7b3"}.fa-uniregistry{--fa:"\f404"}.fa-figma{--fa:"\f799"}.fa-creative-commons-remix{--fa:"\f4ee"}.fa-cc-amazon-pay{--fa:"\f42d"}.fa-dropbox{--fa:"\f16b"}.fa-instagram{--fa:"\f16d"}.fa-cmplid{--fa:"\e360"}.fa-upwork{--fa:"\e641"}.fa-facebook{--fa:"\f09a"}.fa-gripfire{--fa:"\f3ac"}.fa-jedi-order{--fa:"\f50e"}.fa-uikit{--fa:"\f403"}.fa-fort-awesome-alt{--fa:"\f3a3"}.fa-phabricator{--fa:"\f3db"}.fa-ussunnah{--fa:"\f407"}.fa-earlybirds{--fa:"\f39a"}.fa-trade-federation{--fa:"\f513"}.fa-autoprefixer{--fa:"\f41c"}.fa-whatsapp{--fa:"\f232"}.fa-square-upwork{--fa:"\e67c"}.fa-slideshare{--fa:"\f1e7"}.fa-google-play{--fa:"\f3ab"}.fa-viadeo{--fa:"\f2a9"}.fa-line{--fa:"\f3c0"}.fa-google-drive{--fa:"\f3aa"}.fa-servicestack{--fa:"\f3ec"}.fa-simplybuilt{--fa:"\f215"}.fa-bitbucket{--fa:"\f171"}.fa-imdb{--fa:"\f2d8"}.fa-deezer{--fa:"\e077"}.fa-raspberry-pi{--fa:"\f7bb"}.fa-jira{--fa:"\f7b1"}.fa-docker{--fa:"\f395"}.fa-screenpal{--fa:"\e570"}.fa-bluetooth{--fa:"\f293"}.fa-gitter{--fa:"\f426"}.fa-d-and-d{--fa:"\f38d"}.fa-microblog{--fa:"\e01a"}.fa-cc-diners-club{--fa:"\f24c"}.fa-gg-circle{--fa:"\f261"}.fa-pied-piper-hat{--fa:"\f4e5"}.fa-kickstarter-k{--fa:"\f3bc"}.fa-yandex{--fa:"\f413"}.fa-readme{--fa:"\f4d5"}.fa-html5{--fa:"\f13b"}.fa-sellsy{--fa:"\f213"}.fa-square-web-awesome{--fa:"\e683"}.fa-sass{--fa:"\f41e"}.fa-wirsindhandwerk,.fa-wsh{--fa:"\e2d0"}.fa-buromobelexperte{--fa:"\f37f"}.fa-salesforce{--fa:"\f83b"}.fa-octopus-deploy{--fa:"\e082"}.fa-medapps{--fa:"\f3c6"}.fa-ns8{--fa:"\f3d5"}.fa-pinterest-p{--fa:"\f231"}.fa-apper{--fa:"\f371"}.fa-fort-awesome{--fa:"\f286"}.fa-waze{--fa:"\f83f"}.fa-bluesky{--fa:"\e671"}.fa-cc-jcb{--fa:"\f24b"}.fa-snapchat,.fa-snapchat-ghost{--fa:"\f2ab"}.fa-fantasy-flight-games{--fa:"\f6dc"}.fa-rust{--fa:"\e07a"}.fa-wix{--fa:"\f5cf"}.fa-behance-square,.fa-square-behance{--fa:"\f1b5"}.fa-supple{--fa:"\f3f9"}.fa-webflow{--fa:"\e65c"}.fa-rebel{--fa:"\f1d0"}.fa-css3{--fa:"\f13c"}.fa-staylinked{--fa:"\f3f5"}.fa-kaggle{--fa:"\f5fa"}.fa-space-awesome{--fa:"\e5ac"}.fa-deviantart{--fa:"\f1bd"}.fa-cpanel{--fa:"\f388"}.fa-goodreads-g{--fa:"\f3a9"}.fa-git-square,.fa-square-git{--fa:"\f1d2"}.fa-square-tumblr,.fa-tumblr-square{--fa:"\f174"}.fa-trello{--fa:"\f181"}.fa-creative-commons-nc-jp{--fa:"\f4ea"}.fa-get-pocket{--fa:"\f265"}.fa-perbyte{--fa:"\e083"}.fa-grunt{--fa:"\f3ad"}.fa-weebly{--fa:"\f5cc"}.fa-connectdevelop{--fa:"\f20e"}.fa-leanpub{--fa:"\f212"}.fa-black-tie{--fa:"\f27e"}.fa-themeco{--fa:"\f5c6"}.fa-python{--fa:"\f3e2"}.fa-android{--fa:"\f17b"}.fa-bots{--fa:"\e340"}.fa-free-code-camp{--fa:"\f2c5"}.fa-hornbill{--fa:"\f592"}.fa-js{--fa:"\f3b8"}.fa-ideal{--fa:"\e013"}.fa-git{--fa:"\f1d3"}.fa-dev{--fa:"\f6cc"}.fa-sketch{--fa:"\f7c6"}.fa-yandex-international{--fa:"\f414"}.fa-cc-amex{--fa:"\f1f3"}.fa-uber{--fa:"\f402"}.fa-github{--fa:"\f09b"}.fa-php{--fa:"\f457"}.fa-alipay{--fa:"\f642"}.fa-youtube{--fa:"\f167"}.fa-skyatlas{--fa:"\f216"}.fa-firefox-browser{--fa:"\e007"}.fa-replyd{--fa:"\f3e6"}.fa-suse{--fa:"\f7d6"}.fa-jenkins{--fa:"\f3b6"}.fa-twitter{--fa:"\f099"}.fa-rockrms{--fa:"\f3e9"}.fa-pinterest{--fa:"\f0d2"}.fa-buffer{--fa:"\f837"}.fa-npm{--fa:"\f3d4"}.fa-yammer{--fa:"\f840"}.fa-btc{--fa:"\f15a"}.fa-dribbble{--fa:"\f17d"}.fa-stumbleupon-circle{--fa:"\f1a3"}.fa-internet-explorer{--fa:"\f26b"}.fa-stubber{--fa:"\e5c7"}.fa-telegram,.fa-telegram-plane{--fa:"\f2c6"}.fa-old-republic{--fa:"\f510"}.fa-odysee{--fa:"\e5c6"}.fa-square-whatsapp,.fa-whatsapp-square{--fa:"\f40c"}.fa-node-js{--fa:"\f3d3"}.fa-edge-legacy{--fa:"\e078"}.fa-slack,.fa-slack-hash{--fa:"\f198"}.fa-medrt{--fa:"\f3c8"}.fa-usb{--fa:"\f287"}.fa-tumblr{--fa:"\f173"}.fa-vaadin{--fa:"\f408"}.fa-quora{--fa:"\f2c4"}.fa-square-x-twitter{--fa:"\e61a"}.fa-reacteurope{--fa:"\f75d"}.fa-medium,.fa-medium-m{--fa:"\f23a"}.fa-amilia{--fa:"\f36d"}.fa-mixcloud{--fa:"\f289"}.fa-flipboard{--fa:"\f44d"}.fa-viacoin{--fa:"\f237"}.fa-critical-role{--fa:"\f6c9"}.fa-sitrox{--fa:"\e44a"}.fa-discourse{--fa:"\f393"}.fa-joomla{--fa:"\f1aa"}.fa-mastodon{--fa:"\f4f6"}.fa-airbnb{--fa:"\f834"}.fa-wolf-pack-battalion{--fa:"\f514"}.fa-buy-n-large{--fa:"\f8a6"}.fa-gulp{--fa:"\f3ae"}.fa-creative-commons-sampling-plus{--fa:"\f4f1"}.fa-strava{--fa:"\f428"}.fa-ember{--fa:"\f423"}.fa-canadian-maple-leaf{--fa:"\f785"}.fa-teamspeak{--fa:"\f4f9"}.fa-pushed{--fa:"\f3e1"}.fa-wordpress-simple{--fa:"\f411"}.fa-nutritionix{--fa:"\f3d6"}.fa-wodu{--fa:"\e088"}.fa-google-pay{--fa:"\e079"}.fa-intercom{--fa:"\f7af"}.fa-zhihu{--fa:"\f63f"}.fa-korvue{--fa:"\f42f"}.fa-pix{--fa:"\e43a"}.fa-steam-symbol{--fa:"\f3f6"}:root{--td-light:#fff;--td-widget-background:#fff;--td-font-color:#000;--td-timepicker-font-size:1.2em;--td-active-bg:#0d6efd;--td-range-bg:#01419e;--td-active-color:#fff;--td-active-border-color:#fff;--td-border-radius:999px;--td-btn-hover-bg:#e9ecef;--td-disabled-color:#6c757d;--td-alternate-color:rgba(0,0,0,.38);--td-secondary-border-color:#ccc;--td-secondary-border-color-rgba:rgba(0,0,0,.2);--td-primary-border-color:#fff;--td-text-shadow:0 -1px 0 rgba(0,0,0,.25);--td-dow-color:rgba(0,0,0,.5);--td-dark:#1b1b1b;--td-dark-widget-background:#1b1b1b;--td-dark-font-color:#e3e3e3;--td-dark-active-bg:#4db2ff;--td-dark-range-bg:#0071c7;--td-dark-active-color:#fff;--td-dark-active-border-color:#1b1b1b;--td-dark-btn-hover-bg:#232627;--td-dark-disabled-color:#6c757d;--td-dark-alternate-color:hsla(36,10%,90%,.38);--td-dark-secondary-border-color:#ccc;--td-dark-secondary-border-color-rgba:hsla(36,10%,90%,.2);--td-dark-primary-border-color:#1b1b1b;--td-dark-text-shadow:0 -1px 0 hsla(36,10%,90%,.25);--td-dark-dow-color:hsla(36,10%,90%,.5);--td-widget-z-index:9999}.tempus-dominus-widget [data-action]:after,.visually-hidden{clip:rect(0,0,0,0)!important;border:0!important;height:1px!important;margin:-1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;white-space:nowrap!important;width:1px!important}.tempus-dominus-widget{border-radius:4px;box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12);display:none;list-style:none;padding:4px;width:19rem;z-index:var(--td-widget-z-index)}.tempus-dominus-widget :focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.25);outline:0}.tempus-dominus-widget.calendarWeeks{width:21rem}.tempus-dominus-widget.calendarWeeks .date-container-days{grid-auto-columns:12.5%;grid-template-areas:"a a a a a a a a"}.tempus-dominus-widget [data-action]{cursor:pointer}.tempus-dominus-widget [data-action]:after{content:attr(title)}.tempus-dominus-widget [data-action].disabled,.tempus-dominus-widget [data-action].disabled:hover{background:none;cursor:not-allowed}.tempus-dominus-widget .arrow{display:none}.tempus-dominus-widget.show{display:block}.tempus-dominus-widget.show.date-container{min-height:315px}.tempus-dominus-widget.show.time-container{min-height:217px}.tempus-dominus-widget .td-collapse:not(.show){display:none}.tempus-dominus-widget .td-collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (min-width:576px){.tempus-dominus-widget.timepicker-sbs{width:38em}}@media (min-width:768px){.tempus-dominus-widget.timepicker-sbs{width:38em}}@media (min-width:992px){.tempus-dominus-widget.timepicker-sbs{width:38em}}.tempus-dominus-widget.timepicker-sbs .td-row{display:flex}.tempus-dominus-widget.timepicker-sbs .td-row .td-half{flex:0 0 auto;width:50%}.tempus-dominus-widget div[data-action]:active{box-shadow:none}.tempus-dominus-widget .timepicker-hour,.tempus-dominus-widget .timepicker-minute,.tempus-dominus-widget .timepicker-second{font-size:1.2em;font-weight:700;margin:0;width:54px}.tempus-dominus-widget button[data-action]{padding:6px}.tempus-dominus-widget .toggleMeridiem{height:38px;text-align:center}.tempus-dominus-widget .calendar-header{display:grid;font-weight:700;grid-template-areas:"a a a";margin-bottom:10px}.tempus-dominus-widget .calendar-header .next{padding-right:10px;text-align:right}.tempus-dominus-widget .calendar-header .previous{padding-left:10px;text-align:left}.tempus-dominus-widget .calendar-header .picker-switch{text-align:center}.tempus-dominus-widget .toolbar{display:grid;grid-auto-flow:column;grid-auto-rows:40px}.tempus-dominus-widget .toolbar div{align-items:center;border-radius:var(--td-border-radius);box-sizing:border-box;display:flex;justify-content:center}.tempus-dominus-widget .date-container-days{display:grid;grid-auto-columns:14.2857142857%;grid-auto-rows:40px;grid-template-areas:"a a a a a a a"}.tempus-dominus-widget .date-container-days .range-in{background-color:var(--td-range-bg)!important;border:none;border-radius:0!important;box-shadow:-5px 0 0 var(--td-range-bg),5px 0 0 var(--td-range-bg)}.tempus-dominus-widget .date-container-days .range-end{border-radius:0 50px 50px 0!important}.tempus-dominus-widget .date-container-days .range-start{border-radius:50px 0 0 50px!important}.tempus-dominus-widget .date-container-days .dow{align-items:center;justify-content:center;text-align:center}.tempus-dominus-widget .date-container-days .cw{align-items:center;cursor:default;display:flex;font-size:.8em;height:90%;justify-content:center;line-height:20px;width:90%}.tempus-dominus-widget .date-container-decades,.tempus-dominus-widget .date-container-months,.tempus-dominus-widget .date-container-years{display:grid;grid-auto-rows:calc(2.71429rem - 1.14286px);grid-template-areas:"a a a"}.tempus-dominus-widget .time-container-hour,.tempus-dominus-widget .time-container-minute,.tempus-dominus-widget .time-container-second{display:grid;grid-auto-rows:calc(2.71429rem - 1.14286px);grid-template-areas:"a a a a"}.tempus-dominus-widget .time-container-clock{display:grid;grid-auto-rows:calc(2.71429rem - 1.14286px)}.tempus-dominus-widget .time-container-clock .no-highlight{align-items:center;display:flex;height:90%;justify-content:center;width:90%}.tempus-dominus-widget .date-container-days div:not(.no-highlight),.tempus-dominus-widget .date-container-decades div:not(.no-highlight),.tempus-dominus-widget .date-container-months div:not(.no-highlight),.tempus-dominus-widget .date-container-years div:not(.no-highlight),.tempus-dominus-widget .time-container-clock div:not(.no-highlight),.tempus-dominus-widget .time-container-hour div:not(.no-highlight),.tempus-dominus-widget .time-container-minute div:not(.no-highlight),.tempus-dominus-widget .time-container-second div:not(.no-highlight){align-items:center;border-radius:var(--td-border-radius);box-sizing:border-box;display:flex;height:90%;justify-content:center;width:90%}.tempus-dominus-widget .date-container-days div:not(.no-highlight).disabled,.tempus-dominus-widget .date-container-days div:not(.no-highlight).disabled:hover,.tempus-dominus-widget .date-container-decades div:not(.no-highlight).disabled,.tempus-dominus-widget .date-container-decades div:not(.no-highlight).disabled:hover,.tempus-dominus-widget .date-container-months div:not(.no-highlight).disabled,.tempus-dominus-widget .date-container-months div:not(.no-highlight).disabled:hover,.tempus-dominus-widget .date-container-years div:not(.no-highlight).disabled,.tempus-dominus-widget .date-container-years div:not(.no-highlight).disabled:hover,.tempus-dominus-widget .time-container-clock div:not(.no-highlight).disabled,.tempus-dominus-widget .time-container-clock div:not(.no-highlight).disabled:hover,.tempus-dominus-widget .time-container-hour div:not(.no-highlight).disabled,.tempus-dominus-widget .time-container-hour div:not(.no-highlight).disabled:hover,.tempus-dominus-widget .time-container-minute div:not(.no-highlight).disabled,.tempus-dominus-widget .time-container-minute div:not(.no-highlight).disabled:hover,.tempus-dominus-widget .time-container-second div:not(.no-highlight).disabled,.tempus-dominus-widget .time-container-second div:not(.no-highlight).disabled:hover{background:none;cursor:not-allowed}.tempus-dominus-widget .date-container-days div:not(.no-highlight).today,.tempus-dominus-widget .date-container-decades div:not(.no-highlight).today,.tempus-dominus-widget .date-container-months div:not(.no-highlight).today,.tempus-dominus-widget .date-container-years div:not(.no-highlight).today,.tempus-dominus-widget .time-container-clock div:not(.no-highlight).today,.tempus-dominus-widget .time-container-hour div:not(.no-highlight).today,.tempus-dominus-widget .time-container-minute div:not(.no-highlight).today,.tempus-dominus-widget .time-container-second div:not(.no-highlight).today{position:relative}.tempus-dominus-widget .date-container-days div:not(.no-highlight).today:before,.tempus-dominus-widget .date-container-decades div:not(.no-highlight).today:before,.tempus-dominus-widget .date-container-months div:not(.no-highlight).today:before,.tempus-dominus-widget .date-container-years div:not(.no-highlight).today:before,.tempus-dominus-widget .time-container-clock div:not(.no-highlight).today:before,.tempus-dominus-widget .time-container-hour div:not(.no-highlight).today:before,.tempus-dominus-widget .time-container-minute div:not(.no-highlight).today:before,.tempus-dominus-widget .time-container-second div:not(.no-highlight).today:before{border:solid transparent;border-width:0 0 7px 7px;bottom:6px;content:"";display:inline-block;position:absolute;right:6px}.tempus-dominus-widget .time-container{margin-bottom:.5rem}.tempus-dominus-widget button{border-radius:.25rem;cursor:pointer;display:inline-block;font-size:1rem;font-weight:400;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:middle}.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=decrementHours],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=decrementMinutes],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=decrementSeconds],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=incrementHours],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=incrementMinutes],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=incrementSeconds],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=showHours],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=showMinutes],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=showSeconds],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=togglePeriod],.tempus-dominus-widget.tempus-dominus-widget-readonly table td.day,.tempus-dominus-widget.tempus-dominus-widget-readonly table td.hour,.tempus-dominus-widget.tempus-dominus-widget-readonly table td.minute,.tempus-dominus-widget.tempus-dominus-widget-readonly table td.second{cursor:default;pointer-events:none}.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=decrementHours]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=decrementMinutes]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=decrementSeconds]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=incrementHours]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=incrementMinutes]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=incrementSeconds]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=showHours]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=showMinutes]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=showSeconds]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=togglePeriod]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td.day:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td.hour:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td.minute:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td.second:hover{background:none}.tempus-dominus-widget.light{background-color:var(--td-widget-background);color:var(--td-font-color)}.tempus-dominus-widget.light [data-action].disabled,.tempus-dominus-widget.light [data-action].disabled:hover{color:var(--td-disabled-color)}.tempus-dominus-widget.light .toolbar div:hover{background:var(--td-btn-hover-bg)}.tempus-dominus-widget.light .date-container-days .dow{color:var(--td-dow-color)}.tempus-dominus-widget.light .date-container-days .cw{color:var(--td-alternate-color)}.tempus-dominus-widget.light .date-container-days div:not(.no-highlight):hover,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight):hover,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight):hover,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight):hover,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight):hover,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight):hover,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight):hover,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight):hover{background:var(--td-btn-hover-bg)}.tempus-dominus-widget.light .date-container-days div.range-end:not(.no-highlight),.tempus-dominus-widget.light .date-container-days div.range-in:not(.no-highlight),.tempus-dominus-widget.light .date-container-days div.range-start:not(.no-highlight),.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).active,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).active,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).active,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).active,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).active,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).active,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).active,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).active{background-color:var(--td-active-bg);color:var(--td-active-color);text-shadow:var(--td-text-shadow)}.tempus-dominus-widget.light .date-container-days .date-container-decades div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-decades div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-decades div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-decades div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-decades div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-decades div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-months div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-months div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-months div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-months div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-months div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-months div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-years div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-years div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-years div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-years div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-years div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-years div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-clock div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-clock div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-clock div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-clock div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-clock div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-clock div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-hour div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-hour div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-hour div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-hour div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-hour div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-hour div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-minute div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-minute div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-minute div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-minute div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-minute div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-minute div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-second div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-second div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-second div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-second div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-second div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-second div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).active.new,.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).active.old,.tempus-dominus-widget.light .date-container-decades .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-decades .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-decades .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-decades .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-decades .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-decades .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).active.new,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).active.old,.tempus-dominus-widget.light .date-container-months .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-months .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-months .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-months .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-months .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-months .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).active.new,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).active.old,.tempus-dominus-widget.light .date-container-years .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-years .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-years .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-years .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-years .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-years .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).active.new,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).active.old,.tempus-dominus-widget.light .time-container-clock .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-clock .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-clock .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-clock .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-clock .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-clock .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).active.new,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).active.old,.tempus-dominus-widget.light .time-container-hour .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-hour .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-hour .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-hour .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-hour .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-hour .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).active.new,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).active.old,.tempus-dominus-widget.light .time-container-minute .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-minute .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-minute .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-minute .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-minute .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-minute .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).active.new,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).active.old,.tempus-dominus-widget.light .time-container-second .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-second .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-second .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-second .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-second .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-second .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).active.new,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).active.old{color:var(--td-active-color)}.tempus-dominus-widget.light .date-container-days div.range-end:not(.no-highlight).today:before,.tempus-dominus-widget.light .date-container-days div.range-in:not(.no-highlight).today:before,.tempus-dominus-widget.light .date-container-days div.range-start:not(.no-highlight).today:before,.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).active.today:before,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).active.today:before,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).active.today:before,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).active.today:before,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).active.today:before,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).active.today:before,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).active.today:before,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).active.today:before{border-bottom-color:var(--td-active-border-color)}.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).old{color:var(--td-alternate-color)}.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).disabled,.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).disabled,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).disabled,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).disabled,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).disabled,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).disabled,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).disabled,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).disabled,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).disabled:hover{color:var(--td-disabled-color)}.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).today:before,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).today:before,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).today:before,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).today:before,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).today:before,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).today:before,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).today:before,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).today:before{border-bottom-color:var(--td-active-bg);border-top-color:var(--td-secondary-border-color-rgba)}.tempus-dominus-widget.light button{background-color:var(--td-active-bg);border-color:var(--td-active-bg);color:var(--td-active-color)}.tempus-dominus-widget.dark{background-color:var(--td-dark-widget-background);color:var(--td-dark-font-color)}.tempus-dominus-widget.dark [data-action].disabled,.tempus-dominus-widget.dark [data-action].disabled:hover{color:var(--td-dark-disabled-color)}.tempus-dominus-widget.dark .toolbar div:hover{background:var(--td-dark-btn-hover-bg)}.tempus-dominus-widget.dark .date-container-days .dow{color:var(--td-dark-dow-color)}.tempus-dominus-widget.dark .date-container-days .range-in{background-color:var(--td-dark-range-bg)!important;box-shadow:-5px 0 0 var(--td-dark-range-bg),5px 0 0 var(--td-dark-range-bg)}.tempus-dominus-widget.dark .date-container-days .cw{color:var(--td-dark-alternate-color)}.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight):hover,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight):hover,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight):hover,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight):hover,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight):hover,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight):hover,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight):hover,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight):hover{background:var(--td-dark-btn-hover-bg)}.tempus-dominus-widget.dark .date-container-days div.range-end:not(.no-highlight),.tempus-dominus-widget.dark .date-container-days div.range-in:not(.no-highlight),.tempus-dominus-widget.dark .date-container-days div.range-start:not(.no-highlight),.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).active,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).active,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).active,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).active,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).active,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).active,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).active,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).active{background-color:var(--td-dark-active-bg);color:var(--td-dark-active-color);text-shadow:var(--td-dark-text-shadow)}.tempus-dominus-widget.dark .date-container-days .date-container-decades div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-decades div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-decades div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-decades div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-decades div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-decades div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-months div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-months div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-months div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-months div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-months div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-months div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-years div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-years div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-years div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-years div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-years div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-years div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-clock div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-clock div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-clock div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-clock div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-clock div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-clock div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-hour div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-hour div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-hour div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-hour div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-hour div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-hour div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-minute div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-minute div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-minute div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-minute div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-minute div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-minute div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-second div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-second div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-second div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-second div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-second div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-second div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).active.old,.tempus-dominus-widget.dark .date-container-decades .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-decades .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-decades .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-decades .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-decades .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-decades .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).active.old,.tempus-dominus-widget.dark .date-container-months .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-months .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-months .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-months .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-months .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-months .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).active.old,.tempus-dominus-widget.dark .date-container-years .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-years .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-years .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-years .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-years .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-years .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).active.old,.tempus-dominus-widget.dark .time-container-clock .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-clock .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-clock .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-clock .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-clock .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-clock .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).active.old,.tempus-dominus-widget.dark .time-container-hour .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-hour .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-hour .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-hour .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-hour .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-hour .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).active.old,.tempus-dominus-widget.dark .time-container-minute .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-minute .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-minute .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-minute .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-minute .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-minute .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).active.old,.tempus-dominus-widget.dark .time-container-second .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-second .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-second .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-second .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-second .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-second .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).active.old{color:var(--td-dark-active-color)}.tempus-dominus-widget.dark .date-container-days div.range-end:not(.no-highlight).today:before,.tempus-dominus-widget.dark .date-container-days div.range-in:not(.no-highlight).today:before,.tempus-dominus-widget.dark .date-container-days div.range-start:not(.no-highlight).today:before,.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).active.today:before,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).active.today:before,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).active.today:before,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).active.today:before,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).active.today:before,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).active.today:before,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).active.today:before,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).active.today:before{border-bottom-color:var(--td-dark-active-border-color)}.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).old{color:var(--td-dark-alternate-color)}.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).disabled:hover{color:var(--td-dark-disabled-color)}.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).today:before,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).today:before,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).today:before,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).today:before,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).today:before,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).today:before,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).today:before,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).today:before{border-bottom-color:var(--td-dark-active-bg);border-top-color:var(--td-dark-secondary-border-color-rgba)}.tempus-dominus-widget.dark button{background-color:var(--td-dark-active-bg);border-color:var(--td-dark-active-bg);color:var(--td-dark-active-color)}#ccHeaderArea.with-border{min-height:2.2em;position:relative}#ccHeaderArea.with-border:after{border:1px dashed #17a2b8;bottom:0;content:"";left:0;pointer-events:none;position:absolute;right:0;top:0;z-index:2}#ccHeaderArea.with-border:before{background-color:hsla(0,0%,100%,.9);border-radius:.2em;color:#17a2b8;content:"ヘッダー";left:.5em;padding:0 .4em;pointer-events:none;position:absolute;top:.5em;z-index:3}#ccFooterArea.with-border{min-height:2.2em;position:relative}#ccFooterArea.with-border:after{border:1px dashed #17a2b8;bottom:0;content:"";left:0;pointer-events:none;position:absolute;right:0;top:0;z-index:2}#ccFooterArea.with-border:before{background-color:hsla(0,0%,100%,.9);border-radius:.2em;color:#17a2b8;content:"フッター";left:.5em;padding:0 .4em;pointer-events:none;position:absolute;top:.5em;z-index:3}#ccMainArea.with-border{min-height:2.2em;position:relative}#ccMainArea.with-border:after{border:1px dashed #17a2b8;bottom:0;content:"";left:0;pointer-events:none;position:absolute;right:0;top:0;z-index:2}#ccMainArea.with-border:before{background-color:hsla(0,0%,100%,.9);border-radius:.2em;color:#17a2b8;content:"メイン";left:.5em;padding:0 .4em;pointer-events:none;position:absolute;top:.5em;z-index:3}#ccLeftArea.with-border{min-height:2.2em;position:relative}#ccLeftArea.with-border:after{border:1px dashed #17a2b8;bottom:0;content:"";left:0;pointer-events:none;position:absolute;right:0;top:0;z-index:2}#ccLeftArea.with-border:before{background-color:hsla(0,0%,100%,.9);border-radius:.2em;color:#17a2b8;content:"左";left:.5em;padding:0 .4em;pointer-events:none;position:absolute;top:.5em;z-index:3}#ccRightArea.with-border{min-height:2.2em;position:relative}#ccRightArea.with-border:after{border:1px dashed #17a2b8;bottom:0;content:"";left:0;pointer-events:none;position:absolute;right:0;top:0;z-index:2}#ccRightArea.with-border:before{background-color:hsla(0,0%,100%,.9);border-radius:.2em;color:#17a2b8;content:"右";left:.5em;padding:0 .4em;pointer-events:none;position:absolute;top:.5em;z-index:3}.cc-table-scroll{--cc-table-sticky-offset:0px;--cc-table-header-height:0px;--cc-table-sticky-viewport-offset:0px}.cc-table-scroll__sticky{background-color:#fff;position:sticky;top:var(--cc-table-sticky-viewport-offset,0);z-index:5}.cc-table-scroll__top{display:none;height:16px;margin-bottom:.25rem;overflow-x:auto;overflow-y:hidden}.cc-table-scroll.is-cc-scrollable .cc-table-scroll__top{display:block}.cc-table-scroll__top-inner{height:1px}.cc-table-scroll__header,.cc-table-scroll__header-inner{overflow:hidden}.cc-table-scroll__header-table{margin:0}.cc-table-scroll__header-table thead th{position:static;z-index:auto}.cc-table-scroll.is-cc-header-cloned .cc-table-scroll__body thead{opacity:0;pointer-events:none}.cc-table-scroll.is-cc-header-cloned .cc-table-scroll__body table{margin-top:calc(var(--cc-table-header-height, 0px)*-1)}.cc-table-scroll__body{overflow-x:auto;overflow-y:visible}.cc-table-sticky-header thead th{background-color:#fff;position:sticky;top:0;z-index:3}.cc-table-sticky-header thead.thead-light th{background-color:#f8f9fa}.cc-table-sticky-header-2 thead tr:first-child th{background-color:#fff;position:sticky;top:0;z-index:3}.cc-table-sticky-header-2 thead tr:nth-child(2) th{background-color:#fff;position:sticky;top:var(--cc-table-sticky-offset,0);z-index:3}.cc-table-sticky-first-col tbody tr{--cc-table-sticky-bg:#fff}.cc-table-sticky-first-col.table-striped tbody tr:nth-of-type(odd){--cc-table-sticky-bg:#f2f2f2}.cc-table-sticky-first-col .cc-sticky-col{background-clip:padding-box;background-color:var(--cc-table-sticky-bg);box-shadow:2px 0 0 #dee2e6;left:0;position:sticky;z-index:2}.cc-table-sticky-first-col thead th{position:relative;z-index:1}.cc-table-sticky-first-col thead .cc-sticky-col{background-clip:padding-box;background-color:#fff;box-shadow:2px 0 0 #dee2e6;z-index:10}.cc-table-sticky-first-col thead.thead-light .cc-sticky-col{background-color:#f8f9fa}.cc-table-scroll__header-table .cc-sticky-col{left:0;position:sticky!important;z-index:20!important}.manage-page-tree{--cc-page-tree-depth:0;align-items:center;display:flex;gap:.35rem;min-width:14rem}.manage-page-tree__indent{flex:0 0 calc(var(--cc-page-tree-depth, 0)*1rem);max-width:calc(var(--cc-page-tree-depth, 0)*1rem)}.manage-page-tree__toggle,.manage-page-tree__toggle-placeholder{align-items:center;display:inline-flex;flex:0 0 1.25rem;height:1.25rem;justify-content:center;width:1.25rem}.manage-page-tree__toggle{background-color:transparent;border:0;border-radius:999px;color:#495057;cursor:pointer;padding:0}.manage-page-tree__toggle:hover{background-color:#e9ecef;color:#212529}.manage-page-tree__toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.25);outline:0}.manage-page-tree__toggle-icon{transition:transform .15s ease}.manage-page-tree__toggle[aria-expanded=false] .manage-page-tree__toggle-icon{transform:rotate(-90deg)}.manage-page-tree__label{min-width:0;word-break:break-word}.manage-page-tree__label--parent{color:#212529;font-weight:600}#cc-tui-actual-editor .tui-image-editor-header-buttons,#cc-tui-actual-editor .tui-image-editor-header-logo{display:none!important}.mce-content-body{margin:revert}.mce-text{color:#000!important}.mce-active .mce-text,.mce-text{background-color:transparent!important}.mce-active{background-color:#ededee!important}.embed-responsive span.mce-preview-object{position:static}.cc-column{background-color:#f2f2f2;border-radius:7px;margin:15px 0;padding:25px}.cc-exclamation{padding-left:1.1rem;text-indent:-1.2rem}.cc-exclamation:before{background:url(../images/acc_exclamation.png?337f20c894645de99ffc0ea9f1cfea67) no-repeat;background-size:contain;content:"";display:inline-block;height:1rem;margin:0 5px 3px 0;vertical-align:middle;width:1rem}.cc-note{padding-left:.8rem;text-indent:-.8rem}.cc-note:before{background:url(../images/acc_note.png?991226f05685a2d9d7f75a5348359153) no-repeat;background-size:contain;content:"";display:inline-block;height:.8rem;margin:0 3px 2px 0;vertical-align:middle;width:.8rem}.cc-note+.cc-note{margin-top:-10px}a.cc-icon-pdf:after{background:url(../images/icon_pdf.png?7cfbb334a509ddf1dc22044fa7557f4d) no-repeat;background-size:contain}a.cc-icon-excel:after,a.cc-icon-pdf:after{content:"";display:inline-block;height:1.25rem;margin:0 0 3px 5px;vertical-align:middle;width:1.25rem}a.cc-icon-excel:after{background:url(../images/icon_excel.png?37ecf7f67956f42395945014cddae393) no-repeat;background-size:contain}a.cc-icon-word:after{background:url(../images/icon_word.png?623f8b7fc1b3e9c8ff69f33176f28133) no-repeat;background-size:contain;height:1.25rem;width:1.25rem}a.cc-icon-external:after,a.cc-icon-word:after{content:"";display:inline-block;margin:0 0 3px 5px;vertical-align:middle}a.cc-icon-external:after{background:url(../images/icon_external.png?a6c57082171ba4ca205358df7ddda13f) no-repeat;background-size:contain;height:1rem;width:1rem}.cc-menu-select-locked{opacity:.6}.cc-menu-select-locked #page-select-list{background-color:#f1f3f5;border:1px solid #e2e3e5;border-radius:.25rem;padding:.5rem .75rem}.cc-menu-select-locked .custom-control-input,.cc-menu-select-locked .custom-control-label{cursor:not-allowed}.cc-menu-page-conditions i{margin-right:.25rem}.cc-menu-page-conditions i:last-child{margin-right:0}.photoalbum-manual-sort__thumb{align-items:center;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;display:inline-flex;height:64px;justify-content:center;overflow:hidden;width:64px}.photoalbum-manual-sort__thumb-image{height:100%;-o-object-fit:cover;object-fit:cover;width:100%}.photoalbum-manual-sort__thumb--video{background-color:#f8f9fa;color:#6c757d}.photoalbum-manual-sort__thumb--video i{font-size:24px}.photoalbum-manual-sort__toggle{align-items:center;color:inherit;display:inline-flex;text-decoration:none}.photoalbum-manual-sort__toggle:focus,.photoalbum-manual-sort__toggle:hover{text-decoration:none}.photoalbum-manual-sort__toggle-icon{transition:transform .2s ease}.photoalbum-manual-sort__toggle[aria-expanded=true] .photoalbum-manual-sort__toggle-icon{transform:rotate(90deg)}.photoalbum-manual-sort__item{scroll-margin-top:120px}.photoalbum-manual-sort__item--hidden{background-color:#f8f9fa}.photoalbum-manual-sort__item--pending-hidden{background-color:#e9ecef;background-image:repeating-linear-gradient(135deg,#e9ecef,#e9ecef 6px,#dee2e6 0,#dee2e6 12px)}.photoalbum-manual-sort__item--pending-show{background-color:#ffe083;background-image:repeating-linear-gradient(135deg,#ffe083,#ffe083 6px,#ffe69c 0,#ffe69c 12px)}.photoalbum-manual-sort__item--active{animation:photoalbum-highlight 1.5s ease}@keyframes photoalbum-highlight{0%{background-color:#fff3cd}to{background-color:transparent}}.photoalbum-preview__card{border-color:#17a2b8}.photoalbum-preview__card .card-header{background-color:#e8f6f8;color:#128293}.photoalbum-manual-sort__badge{background-color:#17a2b8;border-radius:.25rem;color:#fff;font-size:.75rem;padding:.2rem .45rem}.photoalbum-visibility-toggle{align-items:center;display:inline-flex;position:relative}.photoalbum-visibility-toggle__input{height:1px;opacity:0;position:absolute;width:1px}.photoalbum-visibility-toggle__label{align-items:center;border:1px solid transparent;border-radius:.25rem;color:#6c757d;cursor:pointer;display:inline-flex;height:1.75rem;justify-content:center;margin-bottom:0;min-width:2rem;padding:.15rem .35rem;transition:background-color .15s ease,border-color .15s ease,box-shadow .15s ease,color .15s ease}.photoalbum-visibility-toggle__icon{font-size:.95rem;line-height:1}.photoalbum-visibility-toggle__icon--off{display:none}.photoalbum-visibility-toggle__label:hover{background-color:#f8f9fa;border-color:#dee2e6;box-shadow:0 1px 2px rgba(0,0,0,.08);color:#343a40}.photoalbum-visibility-toggle__input:focus-visible+.photoalbum-visibility-toggle__label{background-color:#f8f9fa;border-color:#ced4da;box-shadow:0 0 0 .15rem rgba(23,162,184,.25);color:#343a40}.photoalbum-visibility-toggle__input:disabled+.photoalbum-visibility-toggle__label{box-shadow:none;cursor:not-allowed;opacity:.6}.photoalbum-visibility-toggle__input:checked+.photoalbum-visibility-toggle__label{background-color:#e9ecef;border-color:#ced4da;color:#495057}.photoalbum-visibility-toggle__input:checked+.photoalbum-visibility-toggle__label .photoalbum-visibility-toggle__icon--on{display:none}.photoalbum-visibility-toggle__input:checked+.photoalbum-visibility-toggle__label .photoalbum-visibility-toggle__icon--off{display:inline-flex} + */:host,:root{--fa-style-family-brands:"Font Awesome 6 Brands";--fa-font-brands:normal 400 1em/1 "Font Awesome 6 Brands"}@font-face{font-display:swap;font-family:Font Awesome\ 6 Brands;font-style:normal;font-weight:400;src:url(../fonts/vendor/@fortawesome/fontawesome-free/webfa-brands-400.woff2?c210719e60948b211a1260f79812efe5) format("woff2"),url(../fonts/vendor/@fortawesome/fontawesome-free/webfa-brands-400.ttf?1815e00441357e01619e5793e1caa78a) format("truetype")}.fa-brands,.fab{font-weight:400}.fa-monero{--fa:"\f3d0"}.fa-hooli{--fa:"\f427"}.fa-yelp{--fa:"\f1e9"}.fa-cc-visa{--fa:"\f1f0"}.fa-lastfm{--fa:"\f202"}.fa-shopware{--fa:"\f5b5"}.fa-creative-commons-nc{--fa:"\f4e8"}.fa-aws{--fa:"\f375"}.fa-redhat{--fa:"\f7bc"}.fa-yoast{--fa:"\f2b1"}.fa-cloudflare{--fa:"\e07d"}.fa-ups{--fa:"\f7e0"}.fa-pixiv{--fa:"\e640"}.fa-wpexplorer{--fa:"\f2de"}.fa-dyalog{--fa:"\f399"}.fa-bity{--fa:"\f37a"}.fa-stackpath{--fa:"\f842"}.fa-buysellads{--fa:"\f20d"}.fa-first-order{--fa:"\f2b0"}.fa-modx{--fa:"\f285"}.fa-guilded{--fa:"\e07e"}.fa-vnv{--fa:"\f40b"}.fa-js-square,.fa-square-js{--fa:"\f3b9"}.fa-microsoft{--fa:"\f3ca"}.fa-qq{--fa:"\f1d6"}.fa-orcid{--fa:"\f8d2"}.fa-java{--fa:"\f4e4"}.fa-invision{--fa:"\f7b0"}.fa-creative-commons-pd-alt{--fa:"\f4ed"}.fa-centercode{--fa:"\f380"}.fa-glide-g{--fa:"\f2a6"}.fa-drupal{--fa:"\f1a9"}.fa-jxl{--fa:"\e67b"}.fa-dart-lang{--fa:"\e693"}.fa-hire-a-helper{--fa:"\f3b0"}.fa-creative-commons-by{--fa:"\f4e7"}.fa-unity{--fa:"\e049"}.fa-whmcs{--fa:"\f40d"}.fa-rocketchat{--fa:"\f3e8"}.fa-vk{--fa:"\f189"}.fa-untappd{--fa:"\f405"}.fa-mailchimp{--fa:"\f59e"}.fa-css3-alt{--fa:"\f38b"}.fa-reddit-square,.fa-square-reddit{--fa:"\f1a2"}.fa-vimeo-v{--fa:"\f27d"}.fa-contao{--fa:"\f26d"}.fa-square-font-awesome{--fa:"\e5ad"}.fa-deskpro{--fa:"\f38f"}.fa-brave{--fa:"\e63c"}.fa-sistrix{--fa:"\f3ee"}.fa-instagram-square,.fa-square-instagram{--fa:"\e055"}.fa-battle-net{--fa:"\f835"}.fa-the-red-yeti{--fa:"\f69d"}.fa-hacker-news-square,.fa-square-hacker-news{--fa:"\f3af"}.fa-edge{--fa:"\f282"}.fa-threads{--fa:"\e618"}.fa-napster{--fa:"\f3d2"}.fa-snapchat-square,.fa-square-snapchat{--fa:"\f2ad"}.fa-google-plus-g{--fa:"\f0d5"}.fa-artstation{--fa:"\f77a"}.fa-markdown{--fa:"\f60f"}.fa-sourcetree{--fa:"\f7d3"}.fa-google-plus{--fa:"\f2b3"}.fa-diaspora{--fa:"\f791"}.fa-foursquare{--fa:"\f180"}.fa-stack-overflow{--fa:"\f16c"}.fa-github-alt{--fa:"\f113"}.fa-phoenix-squadron{--fa:"\f511"}.fa-pagelines{--fa:"\f18c"}.fa-algolia{--fa:"\f36c"}.fa-red-river{--fa:"\f3e3"}.fa-creative-commons-sa{--fa:"\f4ef"}.fa-safari{--fa:"\f267"}.fa-google{--fa:"\f1a0"}.fa-font-awesome-alt,.fa-square-font-awesome-stroke{--fa:"\f35c"}.fa-atlassian{--fa:"\f77b"}.fa-linkedin-in{--fa:"\f0e1"}.fa-digital-ocean{--fa:"\f391"}.fa-nimblr{--fa:"\f5a8"}.fa-chromecast{--fa:"\f838"}.fa-evernote{--fa:"\f839"}.fa-hacker-news{--fa:"\f1d4"}.fa-creative-commons-sampling{--fa:"\f4f0"}.fa-adversal{--fa:"\f36a"}.fa-creative-commons{--fa:"\f25e"}.fa-watchman-monitoring{--fa:"\e087"}.fa-fonticons{--fa:"\f280"}.fa-weixin{--fa:"\f1d7"}.fa-shirtsinbulk{--fa:"\f214"}.fa-codepen{--fa:"\f1cb"}.fa-git-alt{--fa:"\f841"}.fa-lyft{--fa:"\f3c3"}.fa-rev{--fa:"\f5b2"}.fa-windows{--fa:"\f17a"}.fa-wizards-of-the-coast{--fa:"\f730"}.fa-square-viadeo,.fa-viadeo-square{--fa:"\f2aa"}.fa-meetup{--fa:"\f2e0"}.fa-centos{--fa:"\f789"}.fa-adn{--fa:"\f170"}.fa-cloudsmith{--fa:"\f384"}.fa-opensuse{--fa:"\e62b"}.fa-pied-piper-alt{--fa:"\f1a8"}.fa-dribbble-square,.fa-square-dribbble{--fa:"\f397"}.fa-codiepie{--fa:"\f284"}.fa-node{--fa:"\f419"}.fa-mix{--fa:"\f3cb"}.fa-steam{--fa:"\f1b6"}.fa-cc-apple-pay{--fa:"\f416"}.fa-scribd{--fa:"\f28a"}.fa-debian{--fa:"\e60b"}.fa-openid{--fa:"\f19b"}.fa-instalod{--fa:"\e081"}.fa-files-pinwheel{--fa:"\e69f"}.fa-expeditedssl{--fa:"\f23e"}.fa-sellcast{--fa:"\f2da"}.fa-square-twitter,.fa-twitter-square{--fa:"\f081"}.fa-r-project{--fa:"\f4f7"}.fa-delicious{--fa:"\f1a5"}.fa-freebsd{--fa:"\f3a4"}.fa-vuejs{--fa:"\f41f"}.fa-accusoft{--fa:"\f369"}.fa-ioxhost{--fa:"\f208"}.fa-fonticons-fi{--fa:"\f3a2"}.fa-app-store{--fa:"\f36f"}.fa-cc-mastercard{--fa:"\f1f1"}.fa-itunes-note{--fa:"\f3b5"}.fa-golang{--fa:"\e40f"}.fa-kickstarter,.fa-square-kickstarter{--fa:"\f3bb"}.fa-grav{--fa:"\f2d6"}.fa-weibo{--fa:"\f18a"}.fa-uncharted{--fa:"\e084"}.fa-firstdraft{--fa:"\f3a1"}.fa-square-youtube,.fa-youtube-square{--fa:"\f431"}.fa-wikipedia-w{--fa:"\f266"}.fa-rendact,.fa-wpressr{--fa:"\f3e4"}.fa-angellist{--fa:"\f209"}.fa-galactic-republic{--fa:"\f50c"}.fa-nfc-directional{--fa:"\e530"}.fa-skype{--fa:"\f17e"}.fa-joget{--fa:"\f3b7"}.fa-fedora{--fa:"\f798"}.fa-stripe-s{--fa:"\f42a"}.fa-meta{--fa:"\e49b"}.fa-laravel{--fa:"\f3bd"}.fa-hotjar{--fa:"\f3b1"}.fa-bluetooth-b{--fa:"\f294"}.fa-square-letterboxd{--fa:"\e62e"}.fa-sticker-mule{--fa:"\f3f7"}.fa-creative-commons-zero{--fa:"\f4f3"}.fa-hips{--fa:"\f452"}.fa-css{--fa:"\e6a2"}.fa-behance{--fa:"\f1b4"}.fa-reddit{--fa:"\f1a1"}.fa-discord{--fa:"\f392"}.fa-chrome{--fa:"\f268"}.fa-app-store-ios{--fa:"\f370"}.fa-cc-discover{--fa:"\f1f2"}.fa-wpbeginner{--fa:"\f297"}.fa-confluence{--fa:"\f78d"}.fa-shoelace{--fa:"\e60c"}.fa-mdb{--fa:"\f8ca"}.fa-dochub{--fa:"\f394"}.fa-accessible-icon{--fa:"\f368"}.fa-ebay{--fa:"\f4f4"}.fa-amazon{--fa:"\f270"}.fa-unsplash{--fa:"\e07c"}.fa-yarn{--fa:"\f7e3"}.fa-square-steam,.fa-steam-square{--fa:"\f1b7"}.fa-500px{--fa:"\f26e"}.fa-square-vimeo,.fa-vimeo-square{--fa:"\f194"}.fa-asymmetrik{--fa:"\f372"}.fa-font-awesome,.fa-font-awesome-flag,.fa-font-awesome-logo-full{--fa:"\f2b4"}.fa-gratipay{--fa:"\f184"}.fa-apple{--fa:"\f179"}.fa-hive{--fa:"\e07f"}.fa-gitkraken{--fa:"\f3a6"}.fa-keybase{--fa:"\f4f5"}.fa-apple-pay{--fa:"\f415"}.fa-padlet{--fa:"\e4a0"}.fa-amazon-pay{--fa:"\f42c"}.fa-github-square,.fa-square-github{--fa:"\f092"}.fa-stumbleupon{--fa:"\f1a4"}.fa-fedex{--fa:"\f797"}.fa-phoenix-framework{--fa:"\f3dc"}.fa-shopify{--fa:"\e057"}.fa-neos{--fa:"\f612"}.fa-square-threads{--fa:"\e619"}.fa-hackerrank{--fa:"\f5f7"}.fa-researchgate{--fa:"\f4f8"}.fa-swift{--fa:"\f8e1"}.fa-angular{--fa:"\f420"}.fa-speakap{--fa:"\f3f3"}.fa-angrycreative{--fa:"\f36e"}.fa-y-combinator{--fa:"\f23b"}.fa-empire{--fa:"\f1d1"}.fa-envira{--fa:"\f299"}.fa-google-scholar{--fa:"\e63b"}.fa-gitlab-square,.fa-square-gitlab{--fa:"\e5ae"}.fa-studiovinari{--fa:"\f3f8"}.fa-pied-piper{--fa:"\f2ae"}.fa-wordpress{--fa:"\f19a"}.fa-product-hunt{--fa:"\f288"}.fa-firefox{--fa:"\f269"}.fa-linode{--fa:"\f2b8"}.fa-goodreads{--fa:"\f3a8"}.fa-odnoklassniki-square,.fa-square-odnoklassniki{--fa:"\f264"}.fa-jsfiddle{--fa:"\f1cc"}.fa-sith{--fa:"\f512"}.fa-themeisle{--fa:"\f2b2"}.fa-page4{--fa:"\f3d7"}.fa-hashnode{--fa:"\e499"}.fa-react{--fa:"\f41b"}.fa-cc-paypal{--fa:"\f1f4"}.fa-squarespace{--fa:"\f5be"}.fa-cc-stripe{--fa:"\f1f5"}.fa-creative-commons-share{--fa:"\f4f2"}.fa-bitcoin{--fa:"\f379"}.fa-keycdn{--fa:"\f3ba"}.fa-opera{--fa:"\f26a"}.fa-itch-io{--fa:"\f83a"}.fa-umbraco{--fa:"\f8e8"}.fa-galactic-senate{--fa:"\f50d"}.fa-ubuntu{--fa:"\f7df"}.fa-draft2digital{--fa:"\f396"}.fa-stripe{--fa:"\f429"}.fa-houzz{--fa:"\f27c"}.fa-gg{--fa:"\f260"}.fa-dhl{--fa:"\f790"}.fa-pinterest-square,.fa-square-pinterest{--fa:"\f0d3"}.fa-xing{--fa:"\f168"}.fa-blackberry{--fa:"\f37b"}.fa-creative-commons-pd{--fa:"\f4ec"}.fa-playstation{--fa:"\f3df"}.fa-quinscape{--fa:"\f459"}.fa-less{--fa:"\f41d"}.fa-blogger-b{--fa:"\f37d"}.fa-opencart{--fa:"\f23d"}.fa-vine{--fa:"\f1ca"}.fa-signal-messenger{--fa:"\e663"}.fa-paypal{--fa:"\f1ed"}.fa-gitlab{--fa:"\f296"}.fa-typo3{--fa:"\f42b"}.fa-reddit-alien{--fa:"\f281"}.fa-yahoo{--fa:"\f19e"}.fa-dailymotion{--fa:"\e052"}.fa-affiliatetheme{--fa:"\f36b"}.fa-pied-piper-pp{--fa:"\f1a7"}.fa-bootstrap{--fa:"\f836"}.fa-odnoklassniki{--fa:"\f263"}.fa-nfc-symbol{--fa:"\e531"}.fa-mintbit{--fa:"\e62f"}.fa-ethereum{--fa:"\f42e"}.fa-speaker-deck{--fa:"\f83c"}.fa-creative-commons-nc-eu{--fa:"\f4e9"}.fa-patreon{--fa:"\f3d9"}.fa-avianex{--fa:"\f374"}.fa-ello{--fa:"\f5f1"}.fa-gofore{--fa:"\f3a7"}.fa-bimobject{--fa:"\f378"}.fa-brave-reverse{--fa:"\e63d"}.fa-facebook-f{--fa:"\f39e"}.fa-google-plus-square,.fa-square-google-plus{--fa:"\f0d4"}.fa-web-awesome{--fa:"\e682"}.fa-mandalorian{--fa:"\f50f"}.fa-first-order-alt{--fa:"\f50a"}.fa-osi{--fa:"\f41a"}.fa-google-wallet{--fa:"\f1ee"}.fa-d-and-d-beyond{--fa:"\f6ca"}.fa-periscope{--fa:"\f3da"}.fa-fulcrum{--fa:"\f50b"}.fa-cloudscale{--fa:"\f383"}.fa-forumbee{--fa:"\f211"}.fa-mizuni{--fa:"\f3cc"}.fa-schlix{--fa:"\f3ea"}.fa-square-xing,.fa-xing-square{--fa:"\f169"}.fa-bandcamp{--fa:"\f2d5"}.fa-wpforms{--fa:"\f298"}.fa-cloudversify{--fa:"\f385"}.fa-usps{--fa:"\f7e1"}.fa-megaport{--fa:"\f5a3"}.fa-magento{--fa:"\f3c4"}.fa-spotify{--fa:"\f1bc"}.fa-optin-monster{--fa:"\f23c"}.fa-fly{--fa:"\f417"}.fa-square-bluesky{--fa:"\e6a3"}.fa-aviato{--fa:"\f421"}.fa-itunes{--fa:"\f3b4"}.fa-cuttlefish{--fa:"\f38c"}.fa-blogger{--fa:"\f37c"}.fa-flickr{--fa:"\f16e"}.fa-viber{--fa:"\f409"}.fa-soundcloud{--fa:"\f1be"}.fa-digg{--fa:"\f1a6"}.fa-tencent-weibo{--fa:"\f1d5"}.fa-letterboxd{--fa:"\e62d"}.fa-symfony{--fa:"\f83d"}.fa-maxcdn{--fa:"\f136"}.fa-etsy{--fa:"\f2d7"}.fa-facebook-messenger{--fa:"\f39f"}.fa-audible{--fa:"\f373"}.fa-think-peaks{--fa:"\f731"}.fa-bilibili{--fa:"\e3d9"}.fa-erlang{--fa:"\f39d"}.fa-x-twitter{--fa:"\e61b"}.fa-cotton-bureau{--fa:"\f89e"}.fa-dashcube{--fa:"\f210"}.fa-42-group,.fa-innosoft{--fa:"\e080"}.fa-stack-exchange{--fa:"\f18d"}.fa-elementor{--fa:"\f430"}.fa-pied-piper-square,.fa-square-pied-piper{--fa:"\e01e"}.fa-creative-commons-nd{--fa:"\f4eb"}.fa-palfed{--fa:"\f3d8"}.fa-superpowers{--fa:"\f2dd"}.fa-resolving{--fa:"\f3e7"}.fa-xbox{--fa:"\f412"}.fa-square-web-awesome-stroke{--fa:"\e684"}.fa-searchengin{--fa:"\f3eb"}.fa-tiktok{--fa:"\e07b"}.fa-facebook-square,.fa-square-facebook{--fa:"\f082"}.fa-renren{--fa:"\f18b"}.fa-linux{--fa:"\f17c"}.fa-glide{--fa:"\f2a5"}.fa-linkedin{--fa:"\f08c"}.fa-hubspot{--fa:"\f3b2"}.fa-deploydog{--fa:"\f38e"}.fa-twitch{--fa:"\f1e8"}.fa-flutter{--fa:"\e694"}.fa-ravelry{--fa:"\f2d9"}.fa-mixer{--fa:"\e056"}.fa-lastfm-square,.fa-square-lastfm{--fa:"\f203"}.fa-vimeo{--fa:"\f40a"}.fa-mendeley{--fa:"\f7b3"}.fa-uniregistry{--fa:"\f404"}.fa-figma{--fa:"\f799"}.fa-creative-commons-remix{--fa:"\f4ee"}.fa-cc-amazon-pay{--fa:"\f42d"}.fa-dropbox{--fa:"\f16b"}.fa-instagram{--fa:"\f16d"}.fa-cmplid{--fa:"\e360"}.fa-upwork{--fa:"\e641"}.fa-facebook{--fa:"\f09a"}.fa-gripfire{--fa:"\f3ac"}.fa-jedi-order{--fa:"\f50e"}.fa-uikit{--fa:"\f403"}.fa-fort-awesome-alt{--fa:"\f3a3"}.fa-phabricator{--fa:"\f3db"}.fa-ussunnah{--fa:"\f407"}.fa-earlybirds{--fa:"\f39a"}.fa-trade-federation{--fa:"\f513"}.fa-autoprefixer{--fa:"\f41c"}.fa-whatsapp{--fa:"\f232"}.fa-square-upwork{--fa:"\e67c"}.fa-slideshare{--fa:"\f1e7"}.fa-google-play{--fa:"\f3ab"}.fa-viadeo{--fa:"\f2a9"}.fa-line{--fa:"\f3c0"}.fa-google-drive{--fa:"\f3aa"}.fa-servicestack{--fa:"\f3ec"}.fa-simplybuilt{--fa:"\f215"}.fa-bitbucket{--fa:"\f171"}.fa-imdb{--fa:"\f2d8"}.fa-deezer{--fa:"\e077"}.fa-raspberry-pi{--fa:"\f7bb"}.fa-jira{--fa:"\f7b1"}.fa-docker{--fa:"\f395"}.fa-screenpal{--fa:"\e570"}.fa-bluetooth{--fa:"\f293"}.fa-gitter{--fa:"\f426"}.fa-d-and-d{--fa:"\f38d"}.fa-microblog{--fa:"\e01a"}.fa-cc-diners-club{--fa:"\f24c"}.fa-gg-circle{--fa:"\f261"}.fa-pied-piper-hat{--fa:"\f4e5"}.fa-kickstarter-k{--fa:"\f3bc"}.fa-yandex{--fa:"\f413"}.fa-readme{--fa:"\f4d5"}.fa-html5{--fa:"\f13b"}.fa-sellsy{--fa:"\f213"}.fa-square-web-awesome{--fa:"\e683"}.fa-sass{--fa:"\f41e"}.fa-wirsindhandwerk,.fa-wsh{--fa:"\e2d0"}.fa-buromobelexperte{--fa:"\f37f"}.fa-salesforce{--fa:"\f83b"}.fa-octopus-deploy{--fa:"\e082"}.fa-medapps{--fa:"\f3c6"}.fa-ns8{--fa:"\f3d5"}.fa-pinterest-p{--fa:"\f231"}.fa-apper{--fa:"\f371"}.fa-fort-awesome{--fa:"\f286"}.fa-waze{--fa:"\f83f"}.fa-bluesky{--fa:"\e671"}.fa-cc-jcb{--fa:"\f24b"}.fa-snapchat,.fa-snapchat-ghost{--fa:"\f2ab"}.fa-fantasy-flight-games{--fa:"\f6dc"}.fa-rust{--fa:"\e07a"}.fa-wix{--fa:"\f5cf"}.fa-behance-square,.fa-square-behance{--fa:"\f1b5"}.fa-supple{--fa:"\f3f9"}.fa-webflow{--fa:"\e65c"}.fa-rebel{--fa:"\f1d0"}.fa-css3{--fa:"\f13c"}.fa-staylinked{--fa:"\f3f5"}.fa-kaggle{--fa:"\f5fa"}.fa-space-awesome{--fa:"\e5ac"}.fa-deviantart{--fa:"\f1bd"}.fa-cpanel{--fa:"\f388"}.fa-goodreads-g{--fa:"\f3a9"}.fa-git-square,.fa-square-git{--fa:"\f1d2"}.fa-square-tumblr,.fa-tumblr-square{--fa:"\f174"}.fa-trello{--fa:"\f181"}.fa-creative-commons-nc-jp{--fa:"\f4ea"}.fa-get-pocket{--fa:"\f265"}.fa-perbyte{--fa:"\e083"}.fa-grunt{--fa:"\f3ad"}.fa-weebly{--fa:"\f5cc"}.fa-connectdevelop{--fa:"\f20e"}.fa-leanpub{--fa:"\f212"}.fa-black-tie{--fa:"\f27e"}.fa-themeco{--fa:"\f5c6"}.fa-python{--fa:"\f3e2"}.fa-android{--fa:"\f17b"}.fa-bots{--fa:"\e340"}.fa-free-code-camp{--fa:"\f2c5"}.fa-hornbill{--fa:"\f592"}.fa-js{--fa:"\f3b8"}.fa-ideal{--fa:"\e013"}.fa-git{--fa:"\f1d3"}.fa-dev{--fa:"\f6cc"}.fa-sketch{--fa:"\f7c6"}.fa-yandex-international{--fa:"\f414"}.fa-cc-amex{--fa:"\f1f3"}.fa-uber{--fa:"\f402"}.fa-github{--fa:"\f09b"}.fa-php{--fa:"\f457"}.fa-alipay{--fa:"\f642"}.fa-youtube{--fa:"\f167"}.fa-skyatlas{--fa:"\f216"}.fa-firefox-browser{--fa:"\e007"}.fa-replyd{--fa:"\f3e6"}.fa-suse{--fa:"\f7d6"}.fa-jenkins{--fa:"\f3b6"}.fa-twitter{--fa:"\f099"}.fa-rockrms{--fa:"\f3e9"}.fa-pinterest{--fa:"\f0d2"}.fa-buffer{--fa:"\f837"}.fa-npm{--fa:"\f3d4"}.fa-yammer{--fa:"\f840"}.fa-btc{--fa:"\f15a"}.fa-dribbble{--fa:"\f17d"}.fa-stumbleupon-circle{--fa:"\f1a3"}.fa-internet-explorer{--fa:"\f26b"}.fa-stubber{--fa:"\e5c7"}.fa-telegram,.fa-telegram-plane{--fa:"\f2c6"}.fa-old-republic{--fa:"\f510"}.fa-odysee{--fa:"\e5c6"}.fa-square-whatsapp,.fa-whatsapp-square{--fa:"\f40c"}.fa-node-js{--fa:"\f3d3"}.fa-edge-legacy{--fa:"\e078"}.fa-slack,.fa-slack-hash{--fa:"\f198"}.fa-medrt{--fa:"\f3c8"}.fa-usb{--fa:"\f287"}.fa-tumblr{--fa:"\f173"}.fa-vaadin{--fa:"\f408"}.fa-quora{--fa:"\f2c4"}.fa-square-x-twitter{--fa:"\e61a"}.fa-reacteurope{--fa:"\f75d"}.fa-medium,.fa-medium-m{--fa:"\f23a"}.fa-amilia{--fa:"\f36d"}.fa-mixcloud{--fa:"\f289"}.fa-flipboard{--fa:"\f44d"}.fa-viacoin{--fa:"\f237"}.fa-critical-role{--fa:"\f6c9"}.fa-sitrox{--fa:"\e44a"}.fa-discourse{--fa:"\f393"}.fa-joomla{--fa:"\f1aa"}.fa-mastodon{--fa:"\f4f6"}.fa-airbnb{--fa:"\f834"}.fa-wolf-pack-battalion{--fa:"\f514"}.fa-buy-n-large{--fa:"\f8a6"}.fa-gulp{--fa:"\f3ae"}.fa-creative-commons-sampling-plus{--fa:"\f4f1"}.fa-strava{--fa:"\f428"}.fa-ember{--fa:"\f423"}.fa-canadian-maple-leaf{--fa:"\f785"}.fa-teamspeak{--fa:"\f4f9"}.fa-pushed{--fa:"\f3e1"}.fa-wordpress-simple{--fa:"\f411"}.fa-nutritionix{--fa:"\f3d6"}.fa-wodu{--fa:"\e088"}.fa-google-pay{--fa:"\e079"}.fa-intercom{--fa:"\f7af"}.fa-zhihu{--fa:"\f63f"}.fa-korvue{--fa:"\f42f"}.fa-pix{--fa:"\e43a"}.fa-steam-symbol{--fa:"\f3f6"}:root{--td-light:#fff;--td-widget-background:#fff;--td-font-color:#000;--td-timepicker-font-size:1.2em;--td-active-bg:#0d6efd;--td-range-bg:#01419e;--td-active-color:#fff;--td-active-border-color:#fff;--td-border-radius:999px;--td-btn-hover-bg:#e9ecef;--td-disabled-color:#6c757d;--td-alternate-color:rgba(0,0,0,.38);--td-secondary-border-color:#ccc;--td-secondary-border-color-rgba:rgba(0,0,0,.2);--td-primary-border-color:#fff;--td-text-shadow:0 -1px 0 rgba(0,0,0,.25);--td-dow-color:rgba(0,0,0,.5);--td-dark:#1b1b1b;--td-dark-widget-background:#1b1b1b;--td-dark-font-color:#e3e3e3;--td-dark-active-bg:#4db2ff;--td-dark-range-bg:#0071c7;--td-dark-active-color:#fff;--td-dark-active-border-color:#1b1b1b;--td-dark-btn-hover-bg:#232627;--td-dark-disabled-color:#6c757d;--td-dark-alternate-color:hsla(36,10%,90%,.38);--td-dark-secondary-border-color:#ccc;--td-dark-secondary-border-color-rgba:hsla(36,10%,90%,.2);--td-dark-primary-border-color:#1b1b1b;--td-dark-text-shadow:0 -1px 0 hsla(36,10%,90%,.25);--td-dark-dow-color:hsla(36,10%,90%,.5);--td-widget-z-index:9999}.tempus-dominus-widget [data-action]:after,.visually-hidden{clip:rect(0,0,0,0)!important;border:0!important;height:1px!important;margin:-1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;white-space:nowrap!important;width:1px!important}.tempus-dominus-widget{border-radius:4px;box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12);display:none;list-style:none;padding:4px;width:19rem;z-index:var(--td-widget-z-index)}.tempus-dominus-widget :focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.25);outline:0}.tempus-dominus-widget.calendarWeeks{width:21rem}.tempus-dominus-widget.calendarWeeks .date-container-days{grid-auto-columns:12.5%;grid-template-areas:"a a a a a a a a"}.tempus-dominus-widget [data-action]{cursor:pointer}.tempus-dominus-widget [data-action]:after{content:attr(title)}.tempus-dominus-widget [data-action].disabled,.tempus-dominus-widget [data-action].disabled:hover{background:none;cursor:not-allowed}.tempus-dominus-widget .arrow{display:none}.tempus-dominus-widget.show{display:block}.tempus-dominus-widget.show.date-container{min-height:315px}.tempus-dominus-widget.show.time-container{min-height:217px}.tempus-dominus-widget .td-collapse:not(.show){display:none}.tempus-dominus-widget .td-collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (min-width:576px){.tempus-dominus-widget.timepicker-sbs{width:38em}}@media (min-width:768px){.tempus-dominus-widget.timepicker-sbs{width:38em}}@media (min-width:992px){.tempus-dominus-widget.timepicker-sbs{width:38em}}.tempus-dominus-widget.timepicker-sbs .td-row{display:flex}.tempus-dominus-widget.timepicker-sbs .td-row .td-half{flex:0 0 auto;width:50%}.tempus-dominus-widget div[data-action]:active{box-shadow:none}.tempus-dominus-widget .timepicker-hour,.tempus-dominus-widget .timepicker-minute,.tempus-dominus-widget .timepicker-second{font-size:1.2em;font-weight:700;margin:0;width:54px}.tempus-dominus-widget button[data-action]{padding:6px}.tempus-dominus-widget .toggleMeridiem{height:38px;text-align:center}.tempus-dominus-widget .calendar-header{display:grid;font-weight:700;grid-template-areas:"a a a";margin-bottom:10px}.tempus-dominus-widget .calendar-header .next{padding-right:10px;text-align:right}.tempus-dominus-widget .calendar-header .previous{padding-left:10px;text-align:left}.tempus-dominus-widget .calendar-header .picker-switch{text-align:center}.tempus-dominus-widget .toolbar{display:grid;grid-auto-flow:column;grid-auto-rows:40px}.tempus-dominus-widget .toolbar div{align-items:center;border-radius:var(--td-border-radius);box-sizing:border-box;display:flex;justify-content:center}.tempus-dominus-widget .date-container-days{display:grid;grid-auto-columns:14.2857142857%;grid-auto-rows:40px;grid-template-areas:"a a a a a a a"}.tempus-dominus-widget .date-container-days .range-in{background-color:var(--td-range-bg)!important;border:none;border-radius:0!important;box-shadow:-5px 0 0 var(--td-range-bg),5px 0 0 var(--td-range-bg)}.tempus-dominus-widget .date-container-days .range-end{border-radius:0 50px 50px 0!important}.tempus-dominus-widget .date-container-days .range-start{border-radius:50px 0 0 50px!important}.tempus-dominus-widget .date-container-days .dow{align-items:center;justify-content:center;text-align:center}.tempus-dominus-widget .date-container-days .cw{align-items:center;cursor:default;display:flex;font-size:.8em;height:90%;justify-content:center;line-height:20px;width:90%}.tempus-dominus-widget .date-container-decades,.tempus-dominus-widget .date-container-months,.tempus-dominus-widget .date-container-years{display:grid;grid-auto-rows:calc(2.71429rem - 1.14286px);grid-template-areas:"a a a"}.tempus-dominus-widget .time-container-hour,.tempus-dominus-widget .time-container-minute,.tempus-dominus-widget .time-container-second{display:grid;grid-auto-rows:calc(2.71429rem - 1.14286px);grid-template-areas:"a a a a"}.tempus-dominus-widget .time-container-clock{display:grid;grid-auto-rows:calc(2.71429rem - 1.14286px)}.tempus-dominus-widget .time-container-clock .no-highlight{align-items:center;display:flex;height:90%;justify-content:center;width:90%}.tempus-dominus-widget .date-container-days div:not(.no-highlight),.tempus-dominus-widget .date-container-decades div:not(.no-highlight),.tempus-dominus-widget .date-container-months div:not(.no-highlight),.tempus-dominus-widget .date-container-years div:not(.no-highlight),.tempus-dominus-widget .time-container-clock div:not(.no-highlight),.tempus-dominus-widget .time-container-hour div:not(.no-highlight),.tempus-dominus-widget .time-container-minute div:not(.no-highlight),.tempus-dominus-widget .time-container-second div:not(.no-highlight){align-items:center;border-radius:var(--td-border-radius);box-sizing:border-box;display:flex;height:90%;justify-content:center;width:90%}.tempus-dominus-widget .date-container-days div:not(.no-highlight).disabled,.tempus-dominus-widget .date-container-days div:not(.no-highlight).disabled:hover,.tempus-dominus-widget .date-container-decades div:not(.no-highlight).disabled,.tempus-dominus-widget .date-container-decades div:not(.no-highlight).disabled:hover,.tempus-dominus-widget .date-container-months div:not(.no-highlight).disabled,.tempus-dominus-widget .date-container-months div:not(.no-highlight).disabled:hover,.tempus-dominus-widget .date-container-years div:not(.no-highlight).disabled,.tempus-dominus-widget .date-container-years div:not(.no-highlight).disabled:hover,.tempus-dominus-widget .time-container-clock div:not(.no-highlight).disabled,.tempus-dominus-widget .time-container-clock div:not(.no-highlight).disabled:hover,.tempus-dominus-widget .time-container-hour div:not(.no-highlight).disabled,.tempus-dominus-widget .time-container-hour div:not(.no-highlight).disabled:hover,.tempus-dominus-widget .time-container-minute div:not(.no-highlight).disabled,.tempus-dominus-widget .time-container-minute div:not(.no-highlight).disabled:hover,.tempus-dominus-widget .time-container-second div:not(.no-highlight).disabled,.tempus-dominus-widget .time-container-second div:not(.no-highlight).disabled:hover{background:none;cursor:not-allowed}.tempus-dominus-widget .date-container-days div:not(.no-highlight).today,.tempus-dominus-widget .date-container-decades div:not(.no-highlight).today,.tempus-dominus-widget .date-container-months div:not(.no-highlight).today,.tempus-dominus-widget .date-container-years div:not(.no-highlight).today,.tempus-dominus-widget .time-container-clock div:not(.no-highlight).today,.tempus-dominus-widget .time-container-hour div:not(.no-highlight).today,.tempus-dominus-widget .time-container-minute div:not(.no-highlight).today,.tempus-dominus-widget .time-container-second div:not(.no-highlight).today{position:relative}.tempus-dominus-widget .date-container-days div:not(.no-highlight).today:before,.tempus-dominus-widget .date-container-decades div:not(.no-highlight).today:before,.tempus-dominus-widget .date-container-months div:not(.no-highlight).today:before,.tempus-dominus-widget .date-container-years div:not(.no-highlight).today:before,.tempus-dominus-widget .time-container-clock div:not(.no-highlight).today:before,.tempus-dominus-widget .time-container-hour div:not(.no-highlight).today:before,.tempus-dominus-widget .time-container-minute div:not(.no-highlight).today:before,.tempus-dominus-widget .time-container-second div:not(.no-highlight).today:before{border:solid transparent;border-width:0 0 7px 7px;bottom:6px;content:"";display:inline-block;position:absolute;right:6px}.tempus-dominus-widget .time-container{margin-bottom:.5rem}.tempus-dominus-widget button{border-radius:.25rem;cursor:pointer;display:inline-block;font-size:1rem;font-weight:400;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:middle}.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=decrementHours],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=decrementMinutes],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=decrementSeconds],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=incrementHours],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=incrementMinutes],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=incrementSeconds],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=showHours],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=showMinutes],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=showSeconds],.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=togglePeriod],.tempus-dominus-widget.tempus-dominus-widget-readonly table td.day,.tempus-dominus-widget.tempus-dominus-widget-readonly table td.hour,.tempus-dominus-widget.tempus-dominus-widget-readonly table td.minute,.tempus-dominus-widget.tempus-dominus-widget-readonly table td.second{cursor:default;pointer-events:none}.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=decrementHours]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=decrementMinutes]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=decrementSeconds]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=incrementHours]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=incrementMinutes]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=incrementSeconds]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=showHours]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=showMinutes]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=showSeconds]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td [data-action=togglePeriod]:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td.day:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td.hour:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td.minute:hover,.tempus-dominus-widget.tempus-dominus-widget-readonly table td.second:hover{background:none}.tempus-dominus-widget.light{background-color:var(--td-widget-background);color:var(--td-font-color)}.tempus-dominus-widget.light [data-action].disabled,.tempus-dominus-widget.light [data-action].disabled:hover{color:var(--td-disabled-color)}.tempus-dominus-widget.light .toolbar div:hover{background:var(--td-btn-hover-bg)}.tempus-dominus-widget.light .date-container-days .dow{color:var(--td-dow-color)}.tempus-dominus-widget.light .date-container-days .cw{color:var(--td-alternate-color)}.tempus-dominus-widget.light .date-container-days div:not(.no-highlight):hover,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight):hover,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight):hover,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight):hover,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight):hover,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight):hover,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight):hover,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight):hover{background:var(--td-btn-hover-bg)}.tempus-dominus-widget.light .date-container-days div.range-end:not(.no-highlight),.tempus-dominus-widget.light .date-container-days div.range-in:not(.no-highlight),.tempus-dominus-widget.light .date-container-days div.range-start:not(.no-highlight),.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).active,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).active,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).active,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).active,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).active,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).active,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).active,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).active{background-color:var(--td-active-bg);color:var(--td-active-color);text-shadow:var(--td-text-shadow)}.tempus-dominus-widget.light .date-container-days .date-container-decades div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-decades div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-decades div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-decades div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-decades div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-decades div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-months div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-months div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-months div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-months div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-months div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-months div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-years div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-years div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-years div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-years div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .date-container-years div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .date-container-years div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-clock div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-clock div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-clock div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-clock div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-clock div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-clock div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-hour div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-hour div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-hour div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-hour div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-hour div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-hour div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-minute div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-minute div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-minute div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-minute div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-minute div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-minute div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-second div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-second div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-second div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-second div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days .time-container-second div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days .time-container-second div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).active.new,.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).active.old,.tempus-dominus-widget.light .date-container-decades .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-decades .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-decades .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-decades .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-decades .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-decades .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).active.new,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).active.old,.tempus-dominus-widget.light .date-container-months .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-months .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-months .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-months .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-months .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-months .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).active.new,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).active.old,.tempus-dominus-widget.light .date-container-years .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-years .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-years .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-years .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-years .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-years .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).active.new,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).active.old,.tempus-dominus-widget.light .time-container-clock .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-clock .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-clock .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-clock .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-clock .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-clock .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).active.new,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).active.old,.tempus-dominus-widget.light .time-container-hour .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-hour .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-hour .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-hour .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-hour .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-hour .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).active.new,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).active.old,.tempus-dominus-widget.light .time-container-minute .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-minute .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-minute .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-minute .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-minute .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-minute .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).active.new,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).active.old,.tempus-dominus-widget.light .time-container-second .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-second .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-second .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-second .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-second .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-second .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).active.new,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).active.old{color:var(--td-active-color)}.tempus-dominus-widget.light .date-container-days div.range-end:not(.no-highlight).today:before,.tempus-dominus-widget.light .date-container-days div.range-in:not(.no-highlight).today:before,.tempus-dominus-widget.light .date-container-days div.range-start:not(.no-highlight).today:before,.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).active.today:before,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).active.today:before,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).active.today:before,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).active.today:before,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).active.today:before,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).active.today:before,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).active.today:before,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).active.today:before{border-bottom-color:var(--td-active-border-color)}.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).old,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).new,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).old,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).new,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).old{color:var(--td-alternate-color)}.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).disabled,.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).disabled,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).disabled,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).disabled,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).disabled,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).disabled,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).disabled,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).disabled,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).disabled:hover{color:var(--td-disabled-color)}.tempus-dominus-widget.light .date-container-days div:not(.no-highlight).today:before,.tempus-dominus-widget.light .date-container-decades div:not(.no-highlight).today:before,.tempus-dominus-widget.light .date-container-months div:not(.no-highlight).today:before,.tempus-dominus-widget.light .date-container-years div:not(.no-highlight).today:before,.tempus-dominus-widget.light .time-container-clock div:not(.no-highlight).today:before,.tempus-dominus-widget.light .time-container-hour div:not(.no-highlight).today:before,.tempus-dominus-widget.light .time-container-minute div:not(.no-highlight).today:before,.tempus-dominus-widget.light .time-container-second div:not(.no-highlight).today:before{border-bottom-color:var(--td-active-bg);border-top-color:var(--td-secondary-border-color-rgba)}.tempus-dominus-widget.light button{background-color:var(--td-active-bg);border-color:var(--td-active-bg);color:var(--td-active-color)}.tempus-dominus-widget.dark{background-color:var(--td-dark-widget-background);color:var(--td-dark-font-color)}.tempus-dominus-widget.dark [data-action].disabled,.tempus-dominus-widget.dark [data-action].disabled:hover{color:var(--td-dark-disabled-color)}.tempus-dominus-widget.dark .toolbar div:hover{background:var(--td-dark-btn-hover-bg)}.tempus-dominus-widget.dark .date-container-days .dow{color:var(--td-dark-dow-color)}.tempus-dominus-widget.dark .date-container-days .range-in{background-color:var(--td-dark-range-bg)!important;box-shadow:-5px 0 0 var(--td-dark-range-bg),5px 0 0 var(--td-dark-range-bg)}.tempus-dominus-widget.dark .date-container-days .cw{color:var(--td-dark-alternate-color)}.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight):hover,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight):hover,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight):hover,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight):hover,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight):hover,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight):hover,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight):hover,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight):hover{background:var(--td-dark-btn-hover-bg)}.tempus-dominus-widget.dark .date-container-days div.range-end:not(.no-highlight),.tempus-dominus-widget.dark .date-container-days div.range-in:not(.no-highlight),.tempus-dominus-widget.dark .date-container-days div.range-start:not(.no-highlight),.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).active,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).active,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).active,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).active,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).active,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).active,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).active,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).active{background-color:var(--td-dark-active-bg);color:var(--td-dark-active-color);text-shadow:var(--td-dark-text-shadow)}.tempus-dominus-widget.dark .date-container-days .date-container-decades div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-decades div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-decades div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-decades div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-decades div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-decades div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-months div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-months div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-months div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-months div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-months div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-months div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-years div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-years div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-years div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-years div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .date-container-years div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .date-container-years div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-clock div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-clock div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-clock div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-clock div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-clock div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-clock div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-hour div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-hour div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-hour div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-hour div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-hour div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-hour div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-minute div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-minute div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-minute div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-minute div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-minute div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-minute div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-second div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-second div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-second div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-second div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days .time-container-second div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days .time-container-second div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).active.old,.tempus-dominus-widget.dark .date-container-decades .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-decades .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-decades .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-decades .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-decades .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-decades .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).active.old,.tempus-dominus-widget.dark .date-container-months .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-months .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-months .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-months .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-months .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-months .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).active.old,.tempus-dominus-widget.dark .date-container-years .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-years .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-years .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-years .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-years .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-years .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).active.old,.tempus-dominus-widget.dark .time-container-clock .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-clock .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-clock .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-clock .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-clock .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-clock .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).active.old,.tempus-dominus-widget.dark .time-container-hour .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-hour .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-hour .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-hour .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-hour .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-hour .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).active.old,.tempus-dominus-widget.dark .time-container-minute .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-minute .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-minute .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-minute .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-minute .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-minute .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).active.old,.tempus-dominus-widget.dark .time-container-second .date-container-days div.range-end:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-second .date-container-days div.range-end:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-second .date-container-days div.range-in:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-second .date-container-days div.range-in:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-second .date-container-days div.range-start:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-second .date-container-days div.range-start:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).active.new,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).active.old{color:var(--td-dark-active-color)}.tempus-dominus-widget.dark .date-container-days div.range-end:not(.no-highlight).today:before,.tempus-dominus-widget.dark .date-container-days div.range-in:not(.no-highlight).today:before,.tempus-dominus-widget.dark .date-container-days div.range-start:not(.no-highlight).today:before,.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).active.today:before,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).active.today:before,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).active.today:before,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).active.today:before,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).active.today:before,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).active.today:before,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).active.today:before,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).active.today:before{border-bottom-color:var(--td-dark-active-border-color)}.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).old,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).new,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).old,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).new,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).old{color:var(--td-dark-alternate-color)}.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).disabled:hover,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).disabled,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).disabled:hover{color:var(--td-dark-disabled-color)}.tempus-dominus-widget.dark .date-container-days div:not(.no-highlight).today:before,.tempus-dominus-widget.dark .date-container-decades div:not(.no-highlight).today:before,.tempus-dominus-widget.dark .date-container-months div:not(.no-highlight).today:before,.tempus-dominus-widget.dark .date-container-years div:not(.no-highlight).today:before,.tempus-dominus-widget.dark .time-container-clock div:not(.no-highlight).today:before,.tempus-dominus-widget.dark .time-container-hour div:not(.no-highlight).today:before,.tempus-dominus-widget.dark .time-container-minute div:not(.no-highlight).today:before,.tempus-dominus-widget.dark .time-container-second div:not(.no-highlight).today:before{border-bottom-color:var(--td-dark-active-bg);border-top-color:var(--td-dark-secondary-border-color-rgba)}.tempus-dominus-widget.dark button{background-color:var(--td-dark-active-bg);border-color:var(--td-dark-active-bg);color:var(--td-dark-active-color)}#ccHeaderArea.with-border{min-height:2.2em;position:relative}#ccHeaderArea.with-border:after{border:1px dashed #17a2b8;bottom:0;content:"";left:0;pointer-events:none;position:absolute;right:0;top:0;z-index:2}#ccHeaderArea.with-border:before{background-color:hsla(0,0%,100%,.9);border-radius:.2em;color:#17a2b8;content:"ヘッダー";left:.5em;padding:0 .4em;pointer-events:none;position:absolute;top:.5em;z-index:3}#ccFooterArea.with-border{min-height:2.2em;position:relative}#ccFooterArea.with-border:after{border:1px dashed #17a2b8;bottom:0;content:"";left:0;pointer-events:none;position:absolute;right:0;top:0;z-index:2}#ccFooterArea.with-border:before{background-color:hsla(0,0%,100%,.9);border-radius:.2em;color:#17a2b8;content:"フッター";left:.5em;padding:0 .4em;pointer-events:none;position:absolute;top:.5em;z-index:3}#ccMainArea.with-border{min-height:2.2em;position:relative}#ccMainArea.with-border:after{border:1px dashed #17a2b8;bottom:0;content:"";left:0;pointer-events:none;position:absolute;right:0;top:0;z-index:2}#ccMainArea.with-border:before{background-color:hsla(0,0%,100%,.9);border-radius:.2em;color:#17a2b8;content:"メイン";left:.5em;padding:0 .4em;pointer-events:none;position:absolute;top:.5em;z-index:3}#ccLeftArea.with-border{min-height:2.2em;position:relative}#ccLeftArea.with-border:after{border:1px dashed #17a2b8;bottom:0;content:"";left:0;pointer-events:none;position:absolute;right:0;top:0;z-index:2}#ccLeftArea.with-border:before{background-color:hsla(0,0%,100%,.9);border-radius:.2em;color:#17a2b8;content:"左";left:.5em;padding:0 .4em;pointer-events:none;position:absolute;top:.5em;z-index:3}#ccRightArea.with-border{min-height:2.2em;position:relative}#ccRightArea.with-border:after{border:1px dashed #17a2b8;bottom:0;content:"";left:0;pointer-events:none;position:absolute;right:0;top:0;z-index:2}#ccRightArea.with-border:before{background-color:hsla(0,0%,100%,.9);border-radius:.2em;color:#17a2b8;content:"右";left:.5em;padding:0 .4em;pointer-events:none;position:absolute;top:.5em;z-index:3}.cc-table-scroll{--cc-table-sticky-offset:0px;--cc-table-header-height:0px;--cc-table-sticky-viewport-offset:0px}.cc-table-scroll__sticky{background-color:#fff;position:sticky;top:var(--cc-table-sticky-viewport-offset,0);z-index:5}.cc-table-scroll__top{display:none;height:16px;margin-bottom:.25rem;overflow-x:auto;overflow-y:hidden}.cc-table-scroll.is-cc-scrollable .cc-table-scroll__top{display:block}.cc-table-scroll__top-inner{height:1px}.cc-table-scroll__header,.cc-table-scroll__header-inner{overflow:hidden}.cc-table-scroll__header-table{margin:0}.cc-table-scroll__header-table thead th{position:static;z-index:auto}.cc-table-scroll.is-cc-header-cloned .cc-table-scroll__body thead{opacity:0;pointer-events:none}.cc-table-scroll.is-cc-header-cloned .cc-table-scroll__body table{margin-top:calc(var(--cc-table-header-height, 0px)*-1)}.cc-table-scroll__body{overflow-x:auto;overflow-y:visible}.cc-table-sticky-header thead th{background-color:#fff;position:sticky;top:0;z-index:3}.cc-table-sticky-header thead.thead-light th{background-color:#f8f9fa}.cc-table-sticky-header-2 thead tr:first-child th{background-color:#fff;position:sticky;top:0;z-index:3}.cc-table-sticky-header-2 thead tr:nth-child(2) th{background-color:#fff;position:sticky;top:var(--cc-table-sticky-offset,0);z-index:3}.cc-table-sticky-first-col tbody tr{--cc-table-sticky-bg:#fff}.cc-table-sticky-first-col.table-striped tbody tr:nth-of-type(odd){--cc-table-sticky-bg:#f2f2f2}.cc-table-sticky-first-col .cc-sticky-col{background-clip:padding-box;background-color:var(--cc-table-sticky-bg);box-shadow:2px 0 0 #dee2e6;left:0;position:sticky;z-index:2}.cc-table-sticky-first-col thead th{position:relative;z-index:1}.cc-table-sticky-first-col thead .cc-sticky-col{background-clip:padding-box;background-color:#fff;box-shadow:2px 0 0 #dee2e6;z-index:10}.cc-table-sticky-first-col thead.thead-light .cc-sticky-col{background-color:#f8f9fa}.cc-table-scroll__header-table .cc-sticky-col{left:0;position:sticky!important;z-index:20!important}.manage-page-tree{--cc-page-tree-depth:0;align-items:center;display:flex;gap:.35rem;min-width:14rem}.manage-page-tree__indent{flex:0 0 calc(var(--cc-page-tree-depth, 0)*1rem);max-width:calc(var(--cc-page-tree-depth, 0)*1rem)}.manage-page-tree__toggle,.manage-page-tree__toggle-placeholder{align-items:center;display:inline-flex;flex:0 0 1.25rem;height:1.25rem;justify-content:center;width:1.25rem}.manage-page-tree__toggle{background-color:transparent;border:0;border-radius:999px;color:#495057;cursor:pointer;padding:0}.manage-page-tree__toggle:hover{background-color:#e9ecef;color:#212529}.manage-page-tree__toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.25);outline:0}.manage-page-tree__toggle-icon{transition:transform .15s ease}.manage-page-tree__toggle[aria-expanded=false] .manage-page-tree__toggle-icon{transform:rotate(-90deg)}.manage-page-tree__label{min-width:0;word-break:break-word}.manage-page-tree__label--parent{color:#212529;font-weight:600}.uploadfile-file-cell{min-width:18rem;white-space:normal}.uploadfile-file-content{align-items:center;display:flex;gap:.5rem}.uploadfile-file-name{word-break:break-word}.uploadfile-thumbnail-link{align-items:center;background:#f8f9fa;border:1px solid #dee2e6;border-radius:.25rem;display:inline-flex;flex:0 0 auto;height:80px;justify-content:center;padding:2px;width:80px}.uploadfile-thumbnail-link:focus,.uploadfile-thumbnail-link:hover{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25);outline:0}.uploadfile-thumbnail{max-height:100%;max-width:100%;-o-object-fit:contain;object-fit:contain}.popover.uploadfile-image-popover{max-width:340px}.uploadfile-popover-image{display:block;max-height:240px;max-width:320px;-o-object-fit:contain;object-fit:contain}@media (max-width:575.98px){.uploadfile-file-content{align-items:flex-start;flex-direction:column}.uploadfile-thumbnail-link{height:72px;width:72px}}#cc-tui-actual-editor .tui-image-editor-header-buttons,#cc-tui-actual-editor .tui-image-editor-header-logo{display:none!important}.mce-content-body{margin:revert}.mce-text{color:#000!important}.mce-active .mce-text,.mce-text{background-color:transparent!important}.mce-active{background-color:#ededee!important}.embed-responsive span.mce-preview-object{position:static}.cc-column{background-color:#f2f2f2;border-radius:7px;margin:15px 0;padding:25px}.cc-exclamation{padding-left:1.1rem;text-indent:-1.2rem}.cc-exclamation:before{background:url(../images/acc_exclamation.png?337f20c894645de99ffc0ea9f1cfea67) no-repeat;background-size:contain;content:"";display:inline-block;height:1rem;margin:0 5px 3px 0;vertical-align:middle;width:1rem}.cc-note{padding-left:.8rem;text-indent:-.8rem}.cc-note:before{background:url(../images/acc_note.png?991226f05685a2d9d7f75a5348359153) no-repeat;background-size:contain;content:"";display:inline-block;height:.8rem;margin:0 3px 2px 0;vertical-align:middle;width:.8rem}.cc-note+.cc-note{margin-top:-10px}a.cc-icon-pdf:after{background:url(../images/icon_pdf.png?7cfbb334a509ddf1dc22044fa7557f4d) no-repeat;background-size:contain}a.cc-icon-excel:after,a.cc-icon-pdf:after{content:"";display:inline-block;height:1.25rem;margin:0 0 3px 5px;vertical-align:middle;width:1.25rem}a.cc-icon-excel:after{background:url(../images/icon_excel.png?37ecf7f67956f42395945014cddae393) no-repeat;background-size:contain}a.cc-icon-word:after{background:url(../images/icon_word.png?623f8b7fc1b3e9c8ff69f33176f28133) no-repeat;background-size:contain;height:1.25rem;width:1.25rem}a.cc-icon-external:after,a.cc-icon-word:after{content:"";display:inline-block;margin:0 0 3px 5px;vertical-align:middle}a.cc-icon-external:after{background:url(../images/icon_external.png?a6c57082171ba4ca205358df7ddda13f) no-repeat;background-size:contain;height:1rem;width:1rem}.cc-menu-select-locked{opacity:.6}.cc-menu-select-locked #page-select-list{background-color:#f1f3f5;border:1px solid #e2e3e5;border-radius:.25rem;padding:.5rem .75rem}.cc-menu-select-locked .custom-control-input,.cc-menu-select-locked .custom-control-label{cursor:not-allowed}.cc-menu-page-conditions i{margin-right:.25rem}.cc-menu-page-conditions i:last-child{margin-right:0}.photoalbum-manual-sort__thumb{align-items:center;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;display:inline-flex;height:64px;justify-content:center;overflow:hidden;width:64px}.photoalbum-manual-sort__thumb-image{height:100%;-o-object-fit:cover;object-fit:cover;width:100%}.photoalbum-manual-sort__thumb--video{background-color:#f8f9fa;color:#6c757d}.photoalbum-manual-sort__thumb--video i{font-size:24px}.photoalbum-manual-sort__toggle{align-items:center;color:inherit;display:inline-flex;text-decoration:none}.photoalbum-manual-sort__toggle:focus,.photoalbum-manual-sort__toggle:hover{text-decoration:none}.photoalbum-manual-sort__toggle-icon{transition:transform .2s ease}.photoalbum-manual-sort__toggle[aria-expanded=true] .photoalbum-manual-sort__toggle-icon{transform:rotate(90deg)}.photoalbum-manual-sort__item{scroll-margin-top:120px}.photoalbum-manual-sort__item--hidden{background-color:#f8f9fa}.photoalbum-manual-sort__item--pending-hidden{background-color:#e9ecef;background-image:repeating-linear-gradient(135deg,#e9ecef,#e9ecef 6px,#dee2e6 0,#dee2e6 12px)}.photoalbum-manual-sort__item--pending-show{background-color:#ffe083;background-image:repeating-linear-gradient(135deg,#ffe083,#ffe083 6px,#ffe69c 0,#ffe69c 12px)}.photoalbum-manual-sort__item--active{animation:photoalbum-highlight 1.5s ease}@keyframes photoalbum-highlight{0%{background-color:#fff3cd}to{background-color:transparent}}.photoalbum-preview__card{border-color:#17a2b8}.photoalbum-preview__card .card-header{background-color:#e8f6f8;color:#128293}.photoalbum-manual-sort__badge{background-color:#17a2b8;border-radius:.25rem;color:#fff;font-size:.75rem;padding:.2rem .45rem}.photoalbum-visibility-toggle{align-items:center;display:inline-flex;position:relative}.photoalbum-visibility-toggle__input{height:1px;opacity:0;position:absolute;width:1px}.photoalbum-visibility-toggle__label{align-items:center;border:1px solid transparent;border-radius:.25rem;color:#6c757d;cursor:pointer;display:inline-flex;height:1.75rem;justify-content:center;margin-bottom:0;min-width:2rem;padding:.15rem .35rem;transition:background-color .15s ease,border-color .15s ease,box-shadow .15s ease,color .15s ease}.photoalbum-visibility-toggle__icon{font-size:.95rem;line-height:1}.photoalbum-visibility-toggle__icon--off{display:none}.photoalbum-visibility-toggle__label:hover{background-color:#f8f9fa;border-color:#dee2e6;box-shadow:0 1px 2px rgba(0,0,0,.08);color:#343a40}.photoalbum-visibility-toggle__input:focus-visible+.photoalbum-visibility-toggle__label{background-color:#f8f9fa;border-color:#ced4da;box-shadow:0 0 0 .15rem rgba(23,162,184,.25);color:#343a40}.photoalbum-visibility-toggle__input:disabled+.photoalbum-visibility-toggle__label{box-shadow:none;cursor:not-allowed;opacity:.6}.photoalbum-visibility-toggle__input:checked+.photoalbum-visibility-toggle__label{background-color:#e9ecef;border-color:#ced4da;color:#495057}.photoalbum-visibility-toggle__input:checked+.photoalbum-visibility-toggle__label .photoalbum-visibility-toggle__icon--on{display:none}.photoalbum-visibility-toggle__input:checked+.photoalbum-visibility-toggle__label .photoalbum-visibility-toggle__icon--off{display:inline-flex} diff --git a/public/mix-manifest.json b/public/mix-manifest.json index d7bff064d..a5d16104b 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -3,7 +3,7 @@ "/js/wysiwyg.js": "/js/wysiwyg.js?id=f569deb3cc4d3022c22b689b766be44c", "/js/codemirror.js": "/js/codemirror.js?id=1648b8c7831f2474820107a74359317f", "/js/manage/page/index.js": "/js/manage/page/index.js?id=0baec4e0bdc17faa6677a2d9c0bed29b", - "/css/app.css": "/css/app.css?id=1d1b5dd28223d82e3e4049fafbfaabef", + "/css/app.css": "/css/app.css?id=d6fb0b661b1f484b915a1dd7c5d5f57c", "/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff2?2463b90d9a316e4e5294e6706b6a7a72": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff2?2463b90d9a316e4e5294e6706b6a7a72?id=109ad919b74a62a8a223361da1651bbc", "/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.ttf?2582b0e4bcf85eceead0de3fd9035c90": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.ttf?2582b0e4bcf85eceead0de3fd9035c90?id=8218477819a31609afa351933eebcdb4", "/fonts/vendor/@fortawesome/fontawesome-free/webfa-regular-400.woff2?89999bdf5d835c0120257222e5568fec": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-regular-400.woff2?89999bdf5d835c0120257222e5568fec?id=25bde24dc00e5dce8f1bfa8164b3b7b1", diff --git a/resources/sass/app.scss b/resources/sass/app.scss index bf986eaa3..7eea0b2b7 100644 --- a/resources/sass/app.scss +++ b/resources/sass/app.scss @@ -27,6 +27,7 @@ // Manage styles @import 'manage/page'; +@import 'manage/uploadfile'; // Toast UI ImageEditor UI styles @import 'toast-ui-image-editor/ui'; diff --git a/resources/sass/manage/_uploadfile.scss b/resources/sass/manage/_uploadfile.scss new file mode 100644 index 000000000..820bad038 --- /dev/null +++ b/resources/sass/manage/_uploadfile.scss @@ -0,0 +1,63 @@ +.uploadfile-file-cell { + min-width: 18rem; + white-space: normal; +} + +.uploadfile-file-content { + align-items: center; + display: flex; + gap: 0.5rem; +} + +.uploadfile-file-name { + word-break: break-word; +} + +.uploadfile-thumbnail-link { + align-items: center; + background: #f8f9fa; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + display: inline-flex; + flex: 0 0 auto; + height: 80px; + justify-content: center; + padding: 2px; + width: 80px; +} + +.uploadfile-thumbnail-link:hover, +.uploadfile-thumbnail-link:focus { + border-color: #80bdff; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); + outline: 0; +} + +.uploadfile-thumbnail { + max-height: 100%; + max-width: 100%; + object-fit: contain; +} + +.popover.uploadfile-image-popover { + max-width: 340px; +} + +.uploadfile-popover-image { + display: block; + max-height: 240px; + max-width: 320px; + object-fit: contain; +} + +@media (max-width: 575.98px) { + .uploadfile-file-content { + align-items: flex-start; + flex-direction: column; + } + + .uploadfile-thumbnail-link { + height: 72px; + width: 72px; + } +} diff --git a/resources/views/plugins/manage/uploadfile/index.blade.php b/resources/views/plugins/manage/uploadfile/index.blade.php index 5d4cf1a89..d5bc4a253 100644 --- a/resources/views/plugins/manage/uploadfile/index.blade.php +++ b/resources/views/plugins/manage/uploadfile/index.blade.php @@ -308,14 +308,8 @@ {{$upload->id}} - - - {{$upload->client_original_name}} - @if ($upload->is_image) - {{-- 画像ファイルの場合、サムネイル画像を表示 --}} - - @endif - + + @include('plugins.manage.uploadfile.upload_thumbnail', ['upload' => $upload]) {{$upload->getFormatSize()}} {{$upload->created_at}} @@ -433,6 +427,21 @@ function updateBulkDeleteButton() { // ツールチップの初期化 $('[data-toggle="tooltip"]').tooltip(); + + $('.uploadfile-thumbnail-link[data-toggle="popover"]').popover({ + html: true, + trigger: 'hover focus', + container: 'body', + placement: 'auto', + template: '', + content: function() { + return $('', { + src: $(this).data('preview-src'), + alt: $(this).data('preview-alt'), + class: 'uploadfile-popover-image', + }).prop('outerHTML'); + }, + }); }); @endsection diff --git a/resources/views/plugins/manage/uploadfile/upload_thumbnail.blade.php b/resources/views/plugins/manage/uploadfile/upload_thumbnail.blade.php new file mode 100644 index 000000000..6e5ba0c82 --- /dev/null +++ b/resources/views/plugins/manage/uploadfile/upload_thumbnail.blade.php @@ -0,0 +1,26 @@ +{{-- + * アップロードファイル管理のサムネイル表示テンプレート + * + * @author OpenSource-WorkShop Co.,Ltd. + * @copyright OpenSource-WorkShop Co.,Ltd. All Rights Reserved + * @category アップロードファイル管理 + --}} +
+ {{$upload->client_original_name}} + @if ($upload->is_image) + {{-- 画像ファイルの場合、サムネイル画像を表示 --}} + + {{$upload->client_original_name}} のサムネイル + + @endif +
diff --git a/tests/Unit/Plugins/Manage/UploadfileManage/UploadfileManageThumbnailViewTest.php b/tests/Unit/Plugins/Manage/UploadfileManage/UploadfileManageThumbnailViewTest.php new file mode 100644 index 000000000..0ebdee4eb --- /dev/null +++ b/tests/Unit/Plugins/Manage/UploadfileManage/UploadfileManageThumbnailViewTest.php @@ -0,0 +1,54 @@ + 'preview-target.jpg', + 'mimetype' => 'image/jpeg', + 'extension' => 'jpg', + ]); + $upload->id = 123; + + $html = view('plugins.manage.uploadfile.upload_thumbnail', ['upload' => $upload])->render(); + + $this->assertStringContainsString('class="uploadfile-thumbnail-link"', $html); + $this->assertStringContainsString('data-toggle="popover"', $html); + $this->assertStringContainsString('data-preview-src="' . url('/file/123') . '"', $html); + $this->assertStringContainsString('class="uploadfile-thumbnail"', $html); + $this->assertStringContainsString('preview-target.jpg のサムネイル', $html); + } + + /** + * 画像以外のファイルには画像プレビューを出さず、通常のファイルリンクだけを表示すること。 + */ + public function testNonImageFileDoesNotShowThumbnailPreview(): void + { + $upload = new Uploads([ + 'client_original_name' => 'document.pdf', + 'mimetype' => 'application/pdf', + 'extension' => 'pdf', + ]); + $upload->id = 456; + + $html = view('plugins.manage.uploadfile.upload_thumbnail', ['upload' => $upload])->render(); + + $this->assertStringContainsString('document.pdf', $html); + $this->assertStringNotContainsString('uploadfile-thumbnail-link', $html); + $this->assertStringNotContainsString('data-toggle="popover"', $html); + } +} From 0004d41f64e0daaf064ede3e58b3bf1983d654c6 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Wed, 20 May 2026 18:54:54 +0900 Subject: [PATCH 22/49] =?UTF-8?q?feat(blogs):=20=E6=8A=95=E7=A8=BF?= =?UTF-8?q?=E6=97=A5=E6=99=82=E3=81=AE=E8=A1=A8=E7=A4=BA=E5=BD=A2=E5=BC=8F?= =?UTF-8?q?=E8=A8=AD=E5=AE=9A=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Enums/BlogFrameConfig.php | 4 + app/Enums/BlogPostedAtFormat.php | 122 ++++++++++++++++++ app/Plugins/User/Blogs/BlogsPlugin.php | 7 + config/app.php | 1 + .../user/blogs/default/blogs.blade.php | 8 +- .../default/blogs_setting_frame.blade.php | 31 +++++ .../user/blogs/default/blogs_show.blade.php | 8 +- .../blogs/default/include_posted_at.blade.php | 14 ++ .../user/blogs/designbase/blogs.blade.php | 2 +- .../blogs/designbase/blogs_show.blade.php | 2 +- .../User/Blogs/BlogPostedAtFormatTest.php | 114 ++++++++++++++++ 11 files changed, 303 insertions(+), 10 deletions(-) create mode 100644 app/Enums/BlogPostedAtFormat.php create mode 100644 resources/views/plugins/user/blogs/default/include_posted_at.blade.php create mode 100644 tests/Unit/Plugins/User/Blogs/BlogPostedAtFormatTest.php diff --git a/app/Enums/BlogFrameConfig.php b/app/Enums/BlogFrameConfig.php index e43a7e06c..7fb8b3ab5 100644 --- a/app/Enums/BlogFrameConfig.php +++ b/app/Enums/BlogFrameConfig.php @@ -11,6 +11,8 @@ final class BlogFrameConfig extends EnumsBase { // 定数メンバ const blog_display_created_name = 'blog_display_created_name'; + const blog_display_posted_time = 'blog_display_posted_time'; + const blog_posted_at_format = 'blog_posted_at_format'; const blog_display_twitter_button = 'blog_display_twitter_button'; const blog_display_facebook_button = 'blog_display_facebook_button'; const blog_view_count = 'blog_view_count'; @@ -18,6 +20,8 @@ final class BlogFrameConfig extends EnumsBase // key/valueの連想配列 const enum = [ self::blog_display_created_name => '投稿者名', + self::blog_display_posted_time => '投稿日時の時刻表示', + self::blog_posted_at_format => '投稿日時表示形式', self::blog_display_twitter_button => 'Twitterアイコン表示', self::blog_display_facebook_button => 'Facebookアイコン表示', self::blog_view_count => '表示件数', diff --git a/app/Enums/BlogPostedAtFormat.php b/app/Enums/BlogPostedAtFormat.php new file mode 100644 index 000000000..0a4fc2990 --- /dev/null +++ b/app/Enums/BlogPostedAtFormat.php @@ -0,0 +1,122 @@ + 'yyyy年m月d日 hh時mm分', + self::slash => 'yyyy/mm/dd hh:mm', + self::hyphen => 'yyyy-mm-dd hh:mm', + self::dot => 'yyyy.mm.dd hh:mm', + self::japanese_era => '和暦(元号年m月d日 hh時mm分)', + ]; + + const date_formats = [ + self::japanese => 'Y年n月j日', + self::slash => 'Y/m/d', + self::hyphen => 'Y-m-d', + self::dot => 'Y.m.d', + self::japanese_era => '', + ]; + + const time_formats = [ + self::japanese => 'H時i分', + self::slash => 'H:i', + self::hyphen => 'H:i', + self::dot => 'H:i', + self::japanese_era => 'H時i分', + ]; + + /** + * key/valueの連想配列を返す。 + */ + public static function getMembers() + { + $members = parent::getMembers(); + if (!self::canUseJapaneseEra()) { + unset($members[self::japanese_era]); + } + + return $members; + } + + /** + * key配列を返す。 + */ + public static function getMemberKeys() + { + return array_keys(self::getMembers()); + } + + /** + * 日付部分を表示形式に応じて返す。 + */ + public static function formatDate(CarbonInterface $date, ?string $key): string + { + if ($key === self::japanese_era) { + if (self::canUseJapaneseEra()) { + return self::formatJapaneseEraDate($date); + } + + return $date->format(self::date_formats[self::japanese]); + } + + return $date->format(self::getDateFormat($key)); + } + + /** + * 和暦表示が利用できるかを返す。 + */ + private static function canUseJapaneseEra(): bool + { + return class_exists(\IntlDateFormatter::class); + } + + /** + * 日付部分の表示形式を返す。 + */ + public static function getDateFormat(?string $key): string + { + return self::date_formats[$key] ?? self::date_formats[self::japanese]; + } + + /** + * 時刻部分の表示形式を返す。 + */ + public static function getTimeFormat(?string $key): string + { + return self::time_formats[$key] ?? self::time_formats[self::japanese]; + } + + /** + * 日付を和暦で返す。 + */ + private static function formatJapaneseEraDate(CarbonInterface $date): string + { + $formatter = new \IntlDateFormatter( + 'ja_JP@calendar=japanese', + \IntlDateFormatter::NONE, + \IntlDateFormatter::NONE, + $date->getTimezone()->getName(), + \IntlDateFormatter::TRADITIONAL, + 'Gy年M月d日' + ); + + return $formatter->format($date->getTimestamp()); + } +} diff --git a/app/Plugins/User/Blogs/BlogsPlugin.php b/app/Plugins/User/Blogs/BlogsPlugin.php index a6ba8e584..993845b14 100644 --- a/app/Plugins/User/Blogs/BlogsPlugin.php +++ b/app/Plugins/User/Blogs/BlogsPlugin.php @@ -6,6 +6,7 @@ use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\DB; +use Illuminate\Validation\Rule; use App\Models\Core\Configs; use App\Models\Core\FrameConfig; @@ -27,8 +28,10 @@ use App\Enums\BlogFrameScope; use App\Enums\BlogNarrowingDownTypeForCreatedId; use App\Enums\BlogNarrowingDownTypeForPostedMonth; +use App\Enums\BlogPostedAtFormat; use App\Enums\BlogNoticeEmbeddedTag; use App\Enums\NoticeEmbeddedTag; +use App\Enums\ShowType; use App\Enums\StatusType; use App\Rules\CustomValiWysiwygMax; @@ -1645,11 +1648,15 @@ public function saveBlogFrame($request, $page_id, $frame_id) // 項目のエラーチェック $validator_values['scope_value'] = ['nullable', 'digits:4']; $validator_values[BlogFrameConfig::blog_view_count] = ['required', 'numeric', 'min:1', 'max:100']; + $validator_values[BlogFrameConfig::blog_display_posted_time] = ['required', Rule::in(ShowType::getMemberKeys())]; + $validator_values[BlogFrameConfig::blog_posted_at_format] = ['required', Rule::in(BlogPostedAtFormat::getMemberKeys())]; if ($request->scope == BlogFrameScope::year || $request->scope == BlogFrameScope::fiscal) { $validator_values['scope_value'][] = ['required']; } $validator_attributes['scope_value'] = '指定年'; $validator_attributes[BlogFrameConfig::blog_view_count] = BlogFrameConfig::getDescription('blog_view_count'); + $validator_attributes[BlogFrameConfig::blog_display_posted_time] = BlogFrameConfig::getDescription(BlogFrameConfig::blog_display_posted_time); + $validator_attributes[BlogFrameConfig::blog_posted_at_format] = BlogFrameConfig::getDescription(BlogFrameConfig::blog_posted_at_format); $validator = Validator::make($request->all(), $validator_values); $validator->setAttributeNames($validator_attributes); diff --git a/config/app.php b/config/app.php index 364559108..7a5a356ca 100644 --- a/config/app.php +++ b/config/app.php @@ -284,6 +284,7 @@ 'BaseLoginRedirectPage' => \App\Enums\BaseLoginRedirectPage::class, 'BlogFrameConfig' => \App\Enums\BlogFrameConfig::class, 'BlogDisplayCreatedName' => \App\Enums\BlogDisplayCreatedName::class, + 'BlogPostedAtFormat' => \App\Enums\BlogPostedAtFormat::class, 'BlogFrameScope' => \App\Enums\BlogFrameScope::class, 'BaseHeaderFontColorClass' => \App\Enums\BaseHeaderFontColorClass::class, 'UploadMaxSize' => \App\Enums\UploadMaxSize::class, diff --git a/resources/views/plugins/user/blogs/default/blogs.blade.php b/resources/views/plugins/user/blogs/default/blogs.blade.php index 786aae83d..84a319e34 100644 --- a/resources/views/plugins/user/blogs/default/blogs.blade.php +++ b/resources/views/plugins/user/blogs/default/blogs.blade.php @@ -84,7 +84,7 @@ {{-- datafirstテンプレート --}}
{{-- 投稿日時 --}} - {{$post->posted_at->format('Y年n月j日 H時i分')}} + @include('plugins.user.blogs.default.include_posted_at', ['posted_at' => $post->posted_at]) {{-- 投稿者名 --}} @if (FrameConfig::getConfigValue($frame_configs, BlogFrameConfig::blog_display_created_name) === BlogDisplayCreatedName::display) @@ -99,7 +99,7 @@ {{-- titleindexテンプレート --}}
{{-- 投稿日時 --}} - {{$post->posted_at->format('Y年n月j日')}} + @include('plugins.user.blogs.default.include_posted_at', ['posted_at' => $post->posted_at, 'default_display_posted_time' => ShowType::not_show]) {{-- タイトル --}} {{$post->post_title}} @@ -119,7 +119,7 @@
{{-- 投稿日時 --}} - {{$post->posted_at->format('Y年n月j日')}} + @include('plugins.user.blogs.default.include_posted_at', ['posted_at' => $post->posted_at, 'default_display_posted_time' => ShowType::not_show]) {{-- タイトル --}} {{$post->post_title}} @@ -138,7 +138,7 @@

{{$post->post_title}}

{{-- 投稿日時 --}} - {{$post->posted_at->format('Y年n月j日 H時i分')}} + @include('plugins.user.blogs.default.include_posted_at', ['posted_at' => $post->posted_at]) {{-- 投稿者名 --}} @if (FrameConfig::getConfigValue($frame_configs, BlogFrameConfig::blog_display_created_name) === BlogDisplayCreatedName::display) diff --git a/resources/views/plugins/user/blogs/default/blogs_setting_frame.blade.php b/resources/views/plugins/user/blogs/default/blogs_setting_frame.blade.php index 363c53e55..8b5c3c5e2 100644 --- a/resources/views/plugins/user/blogs/default/blogs_setting_frame.blade.php +++ b/resources/views/plugins/user/blogs/default/blogs_setting_frame.blade.php @@ -57,6 +57,37 @@ class="form-control col-sm-3 @if ($errors->has(BlogFrameConfig::blog_view_count)
+ {{-- 投稿日時の時刻表示 --}} +
+ +
+ @foreach (ShowType::getMembers() as $enum_value => $enum_label) +
+ @if (FrameConfig::getConfigValueAndOld($frame_configs, BlogFrameConfig::blog_display_posted_time, ShowType::show) == $enum_value) + + @else + + @endif + +
+ @endforeach +
+
+ + {{-- 投稿日時表示形式 --}} +
+ +
+ + @include('plugins.common.errors_inline', ['name' => BlogFrameConfig::blog_posted_at_format]) + ※ 時刻を表示しない場合は、選択した形式の日付部分のみ表示します。 +
+
+
diff --git a/resources/views/plugins/user/blogs/default/blogs_show.blade.php b/resources/views/plugins/user/blogs/default/blogs_show.blade.php index 7fd10ac94..0f2bfaeab 100644 --- a/resources/views/plugins/user/blogs/default/blogs_show.blade.php +++ b/resources/views/plugins/user/blogs/default/blogs_show.blade.php @@ -17,7 +17,7 @@
{{-- 投稿日時 --}} - {{$post->posted_at->format('Y年n月j日 H時i分')}} + @include('plugins.user.blogs.default.include_posted_at', ['posted_at' => $post->posted_at]) {{-- 投稿者名 --}} @if (FrameConfig::getConfigValue($frame_configs, BlogFrameConfig::blog_display_created_name) === BlogDisplayCreatedName::display) @@ -33,7 +33,7 @@
{{-- 投稿日時 --}} - {{$post->posted_at->format('Y年n月j日 H時i分')}} + @include('plugins.user.blogs.default.include_posted_at', ['posted_at' => $post->posted_at]) {{-- 投稿者名 --}} @if (FrameConfig::getConfigValue($frame_configs, BlogFrameConfig::blog_display_created_name) === BlogDisplayCreatedName::display) @@ -49,7 +49,7 @@
{{-- 投稿日時 --}} - {{$post->posted_at->format('Y年n月j日 H時i分')}} + @include('plugins.user.blogs.default.include_posted_at', ['posted_at' => $post->posted_at]) {{-- 投稿者名 --}} @@ -69,7 +69,7 @@

{{$post->post_title}}

{{-- 投稿日時 --}} - {{$post->posted_at->format('Y年n月j日 H時i分')}} + @include('plugins.user.blogs.default.include_posted_at', ['posted_at' => $post->posted_at]) {{-- 投稿者名 --}} @if (FrameConfig::getConfigValue($frame_configs, BlogFrameConfig::blog_display_created_name) === BlogDisplayCreatedName::display) diff --git a/resources/views/plugins/user/blogs/default/include_posted_at.blade.php b/resources/views/plugins/user/blogs/default/include_posted_at.blade.php new file mode 100644 index 000000000..00b733355 --- /dev/null +++ b/resources/views/plugins/user/blogs/default/include_posted_at.blade.php @@ -0,0 +1,14 @@ +{{-- + * ブログ投稿日時の表示部品。 + * + * フレーム設定が未保存の場合は、呼び出し元テンプレートの改修前表示に合わせるため、 + * default_display_posted_time で時刻表示の既定値を指定できる。 +--}} +@php + $posted_at_format = FrameConfig::getConfigValue($frame_configs, BlogFrameConfig::blog_posted_at_format, BlogPostedAtFormat::japanese); + $default_display_posted_time = $default_display_posted_time ?? ShowType::show; + $display_posted_time = FrameConfig::getConfigValue($frame_configs, BlogFrameConfig::blog_display_posted_time, $default_display_posted_time); +@endphp + diff --git a/resources/views/plugins/user/blogs/designbase/blogs.blade.php b/resources/views/plugins/user/blogs/designbase/blogs.blade.php index 30f9e3dc9..2df8f8c75 100644 --- a/resources/views/plugins/user/blogs/designbase/blogs.blade.php +++ b/resources/views/plugins/user/blogs/designbase/blogs.blade.php @@ -65,7 +65,7 @@ @forelse($blogs_posts as $post) {{-- 投稿日時 --}}
- {{$post->posted_at->format('Y/m/d')}} + @include('plugins.user.blogs.default.include_posted_at', ['posted_at' => $post->posted_at, 'default_display_posted_time' => ShowType::not_show]) {{-- 投稿者名 --}} @if (FrameConfig::getConfigValue($frame_configs, BlogFrameConfig::blog_display_created_name) === BlogDisplayCreatedName::display) [{{$post->created_name}}] diff --git a/resources/views/plugins/user/blogs/designbase/blogs_show.blade.php b/resources/views/plugins/user/blogs/designbase/blogs_show.blade.php index 1e1ffdbca..70583efdb 100644 --- a/resources/views/plugins/user/blogs/designbase/blogs_show.blade.php +++ b/resources/views/plugins/user/blogs/designbase/blogs_show.blade.php @@ -14,7 +14,7 @@
{{-- 投稿日時 --}}

- {{$post->posted_at->format('Y/m/d')}} + @include('plugins.user.blogs.default.include_posted_at', ['posted_at' => $post->posted_at, 'default_display_posted_time' => ShowType::not_show]) {{-- 投稿者名 --}} @if (FrameConfig::getConfigValue($frame_configs, BlogFrameConfig::blog_display_created_name) === BlogDisplayCreatedName::display) [{{$post->created_name}}] diff --git a/tests/Unit/Plugins/User/Blogs/BlogPostedAtFormatTest.php b/tests/Unit/Plugins/User/Blogs/BlogPostedAtFormatTest.php new file mode 100644 index 000000000..9c5cea014 --- /dev/null +++ b/tests/Unit/Plugins/User/Blogs/BlogPostedAtFormatTest.php @@ -0,0 +1,114 @@ +renderPostedAt([ + BlogFrameConfig::blog_posted_at_format => BlogPostedAtFormat::slash, + BlogFrameConfig::blog_display_posted_time => ShowType::show, + ]); + + $this->assertStringContainsString('class="blog-posted-at-date">2026/05/20', $html); + $this->assertStringContainsString('class="blog-posted-at-time"> 09:30', $html); + } + + /** + * 時刻を表示しない設定では、日付だけを残し、時刻用spanを出力しないこと。 + */ + public function testPostedAtCanHideOnlyTime(): void + { + $html = $this->renderPostedAt([ + BlogFrameConfig::blog_posted_at_format => BlogPostedAtFormat::slash, + BlogFrameConfig::blog_display_posted_time => ShowType::not_show, + ]); + + $this->assertStringContainsString('class="blog-posted-at-date">2026/05/20', $html); + $this->assertStringNotContainsString('09:30', strip_tags($html)); + $this->assertStringNotContainsString('blog-posted-at-time', $html); + } + + /** + * 時刻表示が未設定の場合は、改修前の挙動に合わせて時刻を表示すること。 + */ + public function testPostedAtDisplaysTimeByDefault(): void + { + $html = $this->renderPostedAt([ + BlogFrameConfig::blog_posted_at_format => BlogPostedAtFormat::slash, + ]); + + $this->assertStringContainsString('class="blog-posted-at-date">2026/05/20', $html); + $this->assertStringContainsString('class="blog-posted-at-time"> 09:30', $html); + } + + /** + * テンプレート側が日付のみを既定にしている場合は、時刻設定が未保存でも改修前どおり時刻を出さないこと。 + */ + public function testPostedAtCanUseTemplateDefaultToHideTime(): void + { + $html = $this->renderPostedAt( + [ + BlogFrameConfig::blog_posted_at_format => BlogPostedAtFormat::slash, + ], + ShowType::not_show + ); + + $this->assertStringContainsString('class="blog-posted-at-date">2026/05/20', $html); + $this->assertStringNotContainsString('09:30', strip_tags($html)); + $this->assertStringNotContainsString('blog-posted-at-time', $html); + } + + /** + * 和暦形式を選ぶと、日付部分が元号と年で表示されること。 + */ + public function testPostedAtCanBeDisplayedWithJapaneseEraFormat(): void + { + $html = $this->renderPostedAt([ + BlogFrameConfig::blog_posted_at_format => BlogPostedAtFormat::japanese_era, + BlogFrameConfig::blog_display_posted_time => ShowType::show, + ]); + + $this->assertStringContainsString('class="blog-posted-at-date">令和8年5月20日', $html); + $this->assertStringContainsString('class="blog-posted-at-time"> 09時30分', $html); + } + + /** + * 表示部品に渡すフレーム設定を組み立てて、投稿日時のHTMLを返す。 + */ + private function renderPostedAt(array $configs, ?string $default_display_posted_time = null): string + { + $frame_configs = new Collection(); + foreach ($configs as $name => $value) { + $frame_configs->push(new FrameConfig(['name' => $name, 'value' => $value])); + } + + $view_data = [ + 'frame_configs' => $frame_configs, + 'posted_at' => Carbon::parse('2026-05-20 09:30:00'), + ]; + if (!is_null($default_display_posted_time)) { + $view_data['default_display_posted_time'] = $default_display_posted_time; + } + + return view('plugins.user.blogs.default.include_posted_at', $view_data)->render(); + } +} From 671c9829c9bddabe97602db84dc406aa62756fd7 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Thu, 21 May 2026 16:26:11 +0900 Subject: [PATCH 23/49] =?UTF-8?q?fix(counters):=20=E6=97=A5=E5=88=A5?= =?UTF-8?q?=E3=82=AB=E3=82=A6=E3=83=B3=E3=83=88=E3=81=AE=E9=87=8D=E8=A4=87?= =?UTF-8?q?=E3=82=92=E9=98=B2=E6=AD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Models/User/Counters/CounterCount.php | 48 +++++++----- app/Plugins/User/Counters/CountersPlugin.php | 9 ++- ...20_000000_fix_duplicate_counter_counts.php | 71 ++++++++++++++++++ .../Models/User/Counters/CounterCountTest.php | 73 +++++++++++++++++++ 4 files changed, 181 insertions(+), 20 deletions(-) create mode 100644 database/migrations/2026_05_20_000000_fix_duplicate_counter_counts.php create mode 100644 tests/Unit/Models/User/Counters/CounterCountTest.php diff --git a/app/Models/User/Counters/CounterCount.php b/app/Models/User/Counters/CounterCount.php index 73c3d6f63..fe02753ed 100644 --- a/app/Models/User/Counters/CounterCount.php +++ b/app/Models/User/Counters/CounterCount.php @@ -8,6 +8,7 @@ use App\UserableNohistory; use Carbon\Carbon; +use Illuminate\Database\QueryException; class CounterCount extends Model { @@ -37,15 +38,17 @@ class CounterCount extends Model */ public static function getCount($counter_id, $counted_at = null) { + $counted_at = (new Carbon($counted_at))->format('Y-m-d'); + $yesterday_at = (new Carbon($counted_at))->subDay()->format('Y-m-d'); + $counter_count = CounterCount::select('counter_counts.*', 'yesterday_counts.day_count as yesterday_count') ->where('counter_counts.counter_id', $counter_id) - ->where('counter_counts.counted_at', (new Carbon($counted_at))->format('Y-m-d')) - ->leftJoin('counter_counts as yesterday_counts', function ($join) use ($counted_at) { + ->where('counter_counts.counted_at', $counted_at) + ->leftJoin('counter_counts as yesterday_counts', function ($join) use ($yesterday_at) { $join->on('yesterday_counts.counter_id', '=', 'counter_counts.counter_id') - ->where('yesterday_counts.counted_at', (new Carbon($counted_at))->subDay()->format('Y-m-d')); + ->where('yesterday_counts.counted_at', $yesterday_at) + ->whereNull('yesterday_counts.deleted_at'); }) - // yesterday_counts の updated_at で降順(新しい順)に並び替え - ->orderBy('yesterday_counts.updated_at', 'desc') ->first(); return $counter_count; @@ -56,29 +59,40 @@ public static function getCount($counter_id, $counted_at = null) */ public static function getCountOrCreate($counter_id) { + $counted_at = now()->format('Y-m-d'); + // 今日のカウント取得 - $today_count = CounterCount::getCount($counter_id); + $today_count = CounterCount::getCount($counter_id, $counted_at); // 今日のカウントない if (is_null($today_count)) { // 昨日以前の最新日データを取得 - $before_counted_at = CounterCount::where('counter_id', $counter_id)->max('counted_at'); - $before_count = CounterCount::where('counter_id', $counter_id) - ->where('counted_at', $before_counted_at) + ->where('counted_at', '<', $counted_at) + ->orderBy('counted_at', 'desc') ->first(); - $before_count = $before_count ?? new CounterCount(); // 今日カウント作成 - $today_count = CounterCount::create([ - 'counter_id' => $counter_id, - 'counted_at' => now()->format('Y-m-d'), - 'day_count' => 0, - 'total_count' => $before_count->total_count, - ]); + try { + CounterCount::firstOrCreate( + [ + 'counter_id' => $counter_id, + 'counted_at' => $counted_at, + ], + [ + 'day_count' => 0, + 'total_count' => (int)($before_count->total_count ?? 0), + ] + ); + } catch (QueryException $e) { + // 並行アクセスで先に当日行が作られた場合は、作成済みの行を再取得する。 + if (is_null(CounterCount::getCount($counter_id, $counted_at))) { + throw $e; + } + } // 今日のカウント再取得 - $today_count = CounterCount::getCount($counter_id); + $today_count = CounterCount::getCount($counter_id, $counted_at); } return $today_count; diff --git a/app/Plugins/User/Counters/CountersPlugin.php b/app/Plugins/User/Counters/CountersPlugin.php index 7b66e7447..446a1b9d9 100644 --- a/app/Plugins/User/Counters/CountersPlugin.php +++ b/app/Plugins/User/Counters/CountersPlugin.php @@ -137,9 +137,12 @@ public function index($request, $page_id, $frame_id) if (! in_array($counter->id, $counter_histories_array)) { // カウントアップ - $today_count->day_count++; - $today_count->total_count++; - $today_count->save(); + CounterCount::where('id', $today_count->id)->update([ + 'day_count' => DB::raw('day_count + 1'), + 'total_count' => DB::raw('total_count + 1'), + 'updated_at' => now(), + ]); + $today_count = CounterCount::getCount($counter->id); // session = カウンターid & 区切り文字 $counter_histories = $counter_histories . ':' . $counter->id; diff --git a/database/migrations/2026_05_20_000000_fix_duplicate_counter_counts.php b/database/migrations/2026_05_20_000000_fix_duplicate_counter_counts.php new file mode 100644 index 000000000..ae686d60b --- /dev/null +++ b/database/migrations/2026_05_20_000000_fix_duplicate_counter_counts.php @@ -0,0 +1,71 @@ +select('counter_id', 'counted_at') + ->groupBy('counter_id', 'counted_at') + ->havingRaw('COUNT(*) > 1') + ->get(); + + foreach ($duplicates as $duplicate) { + $rows = DB::table('counter_counts') + ->where('counter_id', $duplicate->counter_id) + ->where('counted_at', $duplicate->counted_at) + ->orderBy('id') + ->get(); + + $active_rows = $rows->filter(function ($row) { + return is_null($row->deleted_at); + }); + $source_rows = $active_rows->isNotEmpty() ? $active_rows : $rows; + $keep_row = $source_rows->first(); + + // 1日1行へ正規化するため、日別カウントは合算し、累計は同日内の最大値を残す。 + // 論理削除済み行だけが重複している場合も、一意制約を追加できるよう1行にまとめる。 + DB::table('counter_counts') + ->where('id', $keep_row->id) + ->update([ + 'day_count' => $source_rows->sum('day_count'), + 'total_count' => $source_rows->max('total_count'), + 'updated_at' => $source_rows->max('updated_at'), + 'deleted_at' => $keep_row->deleted_at, + ]); + + DB::table('counter_counts') + ->where('counter_id', $duplicate->counter_id) + ->where('counted_at', $duplicate->counted_at) + ->where('id', '<>', $keep_row->id) + ->delete(); + } + + // 以後はアプリケーション側で集計せず、DB制約で「同じカウンターの同じ日は1行」を保証する。 + Schema::table('counter_counts', function (Blueprint $table) { + $table->unique(['counter_id', 'counted_at'], 'counter_counts_counter_id_counted_at_unique'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('counter_counts', function (Blueprint $table) { + $table->dropUnique('counter_counts_counter_id_counted_at_unique'); + }); + } +} diff --git a/tests/Unit/Models/User/Counters/CounterCountTest.php b/tests/Unit/Models/User/Counters/CounterCountTest.php new file mode 100644 index 000000000..8517083f2 --- /dev/null +++ b/tests/Unit/Models/User/Counters/CounterCountTest.php @@ -0,0 +1,73 @@ + 1, + 'counted_at' => '2026-05-20', + 'day_count' => 5, + 'total_count' => 15, + ]); + + $this->expectException(QueryException::class); + + CounterCount::create([ + 'counter_id' => 1, + 'counted_at' => '2026-05-20', + 'day_count' => 0, + 'total_count' => 15, + ]); + } + + /** + * 当日行の作成を複数回要求しても1日1行に保たれ、昨日のカウントが表示用に引き継がれることを守る。 + */ + public function testGetCountOrCreateKeepsOneDailyRowAndReturnsYesterdayCount(): void + { + Carbon::setTestNow(Carbon::parse('2026-05-20 10:00:00')); + + CounterCount::create([ + 'counter_id' => 1, + 'counted_at' => '2026-05-19', + 'day_count' => 7, + 'total_count' => 17, + ]); + + $first_count = CounterCount::getCountOrCreate(1); + $second_count = CounterCount::getCountOrCreate(1); + + $this->assertSame(1, CounterCount::where('counter_id', 1)->where('counted_at', '2026-05-20')->count()); + $this->assertSame(0, (int)$first_count->day_count); + $this->assertSame(17, (int)$first_count->total_count); + $this->assertSame(7, (int)$second_count->yesterday_count); + } +} From 8553198a00375f97082fcd8c229146585b03e357 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Thu, 21 May 2026 18:15:55 +0900 Subject: [PATCH 24/49] fix(calendars): ignore missing repeat event post ids --- .../User/Calendars/CalendarsPlugin.php | 4 +-- .../CalendarsRepeatPostsFeatureTest.php | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/app/Plugins/User/Calendars/CalendarsPlugin.php b/app/Plugins/User/Calendars/CalendarsPlugin.php index b6b1e0db0..dd6fadcc1 100644 --- a/app/Plugins/User/Calendars/CalendarsPlugin.php +++ b/app/Plugins/User/Calendars/CalendarsPlugin.php @@ -426,7 +426,7 @@ public function save($request, $page_id, $frame_id, $post_id = null) $base_post = null; if (!empty($post_id)) { $base_post = $this->getPost($post_id); - if (empty($base_post->id)) { + if (empty($base_post->id) || !$base_post->exists) { return; } } @@ -697,7 +697,7 @@ public function delete($request, $page_id, $frame_id, $post_id) // id がある場合、データを削除 if ($post_id) { $post = $this->getPost($post_id); - if (empty($post->id)) { + if (empty($post->id) || !$post->exists) { return; } diff --git a/tests/Feature/Plugins/User/Calendars/CalendarsRepeatPostsFeatureTest.php b/tests/Feature/Plugins/User/Calendars/CalendarsRepeatPostsFeatureTest.php index 14a540834..00d532ece 100644 --- a/tests/Feature/Plugins/User/Calendars/CalendarsRepeatPostsFeatureTest.php +++ b/tests/Feature/Plugins/User/Calendars/CalendarsRepeatPostsFeatureTest.php @@ -292,6 +292,33 @@ public function testDeleteAllRepeatPosts(): void ); } + /** + * 存在しない予定IDを指定した更新では、新しい予定を作らないこと。 + */ + public function testUpdateMissingPostIdDoesNotCreatePost(): void + { + $admin = $this->createContentAdminUser(); + [$page, $frame, $calendar] = $this->createCalendarFrame(); + + $response = $this->actingAs($admin)->post( + "/redirect/plugin/calendars/save/{$page->id}/{$frame->id}/999999", + $this->makePayload([ + 'title' => '存在しない予定の更新', + 'start_date' => '2026-06-01', + 'start_time' => '10:00', + 'end_date' => '2026-06-01', + 'end_time' => '11:00', + ]) + ); + + $this->assertContains($response->getStatusCode(), [200, 302]); + $this->assertSame(0, CalendarPost::where('calendar_id', $calendar->id)->count()); + $this->assertDatabaseMissing('calendar_posts', [ + 'id' => 999999, + 'title' => '存在しない予定の更新', + ]); + } + /** * 指定フレームに紐づくカレンダーを作成する。 */ From 83dd146e1588d3d4d70ad6dbd3d3fa049a2d9101 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Thu, 21 May 2026 18:16:59 +0900 Subject: [PATCH 25/49] fix(calendars): scope repeat bulk actions by permissions --- .../User/Calendars/CalendarsPlugin.php | 17 +- .../CalendarsRepeatPostsFeatureTest.php | 171 ++++++++++++++++++ 2 files changed, 184 insertions(+), 4 deletions(-) diff --git a/app/Plugins/User/Calendars/CalendarsPlugin.php b/app/Plugins/User/Calendars/CalendarsPlugin.php index dd6fadcc1..a0615565f 100644 --- a/app/Plugins/User/Calendars/CalendarsPlugin.php +++ b/app/Plugins/User/Calendars/CalendarsPlugin.php @@ -502,8 +502,7 @@ private function getRepeatEditPosts(CalendarPost $post, string $repeat_edit_type return new Collection([$post]); } - $query = CalendarPost::where('calendar_id', $post->calendar_id) - ->where('repeat_group_id', $post->repeat_group_id) + $query = $this->getRepeatPostsQuery($post) ->orderBy('start_date') ->orderBy('id'); @@ -522,6 +521,17 @@ private function getRepeatEditPosts(CalendarPost $post, string $repeat_edit_type return $query->get(); } + /** + * 権限範囲内の同一繰り返し予定を取得するクエリを返す。 + */ + private function getRepeatPostsQuery(CalendarPost $post) + { + $query = CalendarPost::where('calendar_id', $post->calendar_id) + ->where('repeat_group_id', $post->repeat_group_id); + + return $this->appendAuthWhereBase($query, 'calendar_posts'); + } + /** * 基準予定からの差分で日付をずらす。 */ @@ -722,8 +732,7 @@ private function getDeletePostIds(CalendarPost $post, string $repeat_delete_type return [$post->id]; } - $query = CalendarPost::where('calendar_id', $post->calendar_id) - ->where('repeat_group_id', $post->repeat_group_id); + $query = $this->getRepeatPostsQuery($post); if ($repeat_delete_type === 'after') { $query->where(function ($query) use ($post) { diff --git a/tests/Feature/Plugins/User/Calendars/CalendarsRepeatPostsFeatureTest.php b/tests/Feature/Plugins/User/Calendars/CalendarsRepeatPostsFeatureTest.php index 00d532ece..92a5a7d8e 100644 --- a/tests/Feature/Plugins/User/Calendars/CalendarsRepeatPostsFeatureTest.php +++ b/tests/Feature/Plugins/User/Calendars/CalendarsRepeatPostsFeatureTest.php @@ -4,11 +4,14 @@ use App\Enums\StatusType; use App\Models\Common\Buckets; +use App\Models\Common\BucketsRoles; use App\Models\Common\Frame; use App\Models\Common\Page; +use App\Models\Core\UsersRoles; use App\Models\User\Calendars\Calendar; use App\Models\User\Calendars\CalendarFrame; use App\Models\User\Calendars\CalendarPost; +use App\User; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\Feature\Plugins\User\DefaultBucketRolesFeatureTestTrait; use Tests\TestCase; @@ -319,6 +322,81 @@ public function testUpdateMissingPostIdDoesNotCreatePost(): void ]); } + /** + * 繰り返し予定の一括編集では、同じグループでも利用者の権限外の予定を更新しないこと。 + */ + public function testUpdateRepeatPostsAfterDoesNotUpdateUnauthorizedPosts(): void + { + $reporter = $this->createReporterUser(); + [$page, $frame, $calendar] = $this->createCalendarFrame(); + $this->allowReporterToPost($calendar); + $posts = $this->createMixedPermissionRepeatPosts($calendar, $reporter); + + $response = $this->actingAs($reporter)->post( + "/redirect/plugin/calendars/save/{$page->id}/{$frame->id}/{$posts['target']->id}", + [ + 'redirect_path' => '/', + 'status' => StatusType::active, + 'allday_flag' => 0, + 'title' => '権限内だけ変更', + 'start_date' => '2026-06-09', + 'start_time' => '11:00', + 'end_date' => '2026-06-09', + 'end_time' => '12:00', + 'body' => '', + 'location' => '', + 'contact' => '', + 'repeat_edit_type' => 'after', + ] + ); + + $this->assertContains($response->getStatusCode(), [200, 302]); + $this->assertDatabaseHas('calendar_posts', [ + 'id' => $posts['target']->id, + 'title' => '権限内だけ変更', + 'start_date' => '2026-06-09', + ]); + $this->assertDatabaseHas('calendar_posts', [ + 'id' => $posts['authorized_future']->id, + 'title' => '権限内だけ変更', + 'start_date' => '2026-06-23', + ]); + $this->assertDatabaseHas('calendar_posts', [ + 'id' => $posts['unauthorized_future']->id, + 'title' => '権限外の一時保存', + 'start_date' => '2026-06-15', + 'status' => StatusType::temporary, + ]); + } + + /** + * 繰り返し予定の一括削除では、同じグループでも利用者の権限外の予定を削除しないこと。 + */ + public function testDeleteRepeatPostsAfterDoesNotDeleteUnauthorizedPosts(): void + { + $reporter = $this->createReporterUser(); + [$page, $frame, $calendar] = $this->createCalendarFrame(); + $this->allowReporterToPost($calendar); + $posts = $this->createMixedPermissionRepeatPosts($calendar, $reporter); + + $response = $this->actingAs($reporter)->post( + "/redirect/plugin/calendars/delete/{$page->id}/{$frame->id}/{$posts['target']->id}", + [ + 'redirect_path' => '/', + 'repeat_delete_type' => 'after', + ] + ); + + $this->assertContains($response->getStatusCode(), [200, 302]); + $this->assertSoftDeleted('calendar_posts', ['id' => $posts['target']->id]); + $this->assertSoftDeleted('calendar_posts', ['id' => $posts['authorized_future']->id]); + $this->assertDatabaseHas('calendar_posts', [ + 'id' => $posts['unauthorized_future']->id, + 'title' => '権限外の一時保存', + 'deleted_at' => null, + ]); + } + /** * 指定フレームに紐づくカレンダーを作成する。 */ @@ -349,6 +427,36 @@ private function createCalendarFrame(): array return [$page, $frame, $calendar]; } + /** + * 編集者権限を持つユーザーを作成する。 + */ + private function createReporterUser(): User + { + $user = User::factory()->create(); + + UsersRoles::factory()->create([ + 'users_id' => $user->id, + 'target' => 'base', + 'role_name' => 'role_reporter', + 'role_value' => 1, + ]); + + return $user; + } + + /** + * 編集者がカレンダーに投稿できるよう、バケツの投稿権限を付与する。 + */ + private function allowReporterToPost(Calendar $calendar): void + { + BucketsRoles::create([ + 'buckets_id' => $calendar->bucket_id, + 'role' => 'role_reporter', + 'post_flag' => 1, + 'approval_flag' => 0, + ]); + } + /** * 毎週の繰り返し予定を削除テスト用に作成する。 */ @@ -368,6 +476,69 @@ private function createWeeklyRepeatPosts($admin, Page $page, Frame $frame): void ); } + /** + * 権限内と権限外の予定が混在する繰り返しグループを作成する。 + */ + private function createMixedPermissionRepeatPosts(Calendar $calendar, User $reporter): array + { + $other_user = User::factory()->create(); + $repeat_group_id = 'repeat-permission-boundary'; + + return [ + 'target' => $this->createCalendarPost($calendar, [ + 'created_id' => $reporter->id, + 'repeat_group_id' => $repeat_group_id, + 'title' => '権限内の対象予定', + 'start_date' => '2026-06-08', + 'end_date' => '2026-06-08', + 'status' => StatusType::active, + ]), + 'unauthorized_future' => $this->createCalendarPost($calendar, [ + 'created_id' => $other_user->id, + 'repeat_group_id' => $repeat_group_id, + 'title' => '権限外の一時保存', + 'start_date' => '2026-06-15', + 'end_date' => '2026-06-15', + 'status' => StatusType::temporary, + ]), + 'authorized_future' => $this->createCalendarPost($calendar, [ + 'created_id' => $reporter->id, + 'repeat_group_id' => $repeat_group_id, + 'title' => '権限内の後続予定', + 'start_date' => '2026-06-22', + 'end_date' => '2026-06-22', + 'status' => StatusType::active, + ]), + ]; + } + + /** + * 境界条件を検証するため、必要な予定データだけを直接作成する。 + */ + private function createCalendarPost(Calendar $calendar, array $overrides): CalendarPost + { + $post = new CalendarPost(); + $post->calendar_id = $calendar->id; + $post->allday_flag = 0; + $post->start_date = '2026-06-01'; + $post->start_time = '10:00'; + $post->end_date = '2026-06-01'; + $post->end_time = '11:00'; + $post->title = '繰り返し予定'; + $post->body = ''; + $post->location = ''; + $post->contact = ''; + $post->status = StatusType::active; + + foreach ($overrides as $key => $value) { + $post->$key = $value; + } + + $post->save(); + + return $post; + } + /** * 予定登録に必要な標準入力を作成する。 */ From 9fb7072e19b01d0bc038600de57e5c4cad838299 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Thu, 21 May 2026 18:18:23 +0900 Subject: [PATCH 26/49] =?UTF-8?q?fix(counters):=20=E9=87=8D=E8=A4=87?= =?UTF-8?q?=E8=A3=9C=E6=AD=A3=E5=BE=8C=E3=81=AE=E7=B4=AF=E8=A8=88=E3=82=92?= =?UTF-8?q?=E5=86=8D=E8=A8=88=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...20_000000_fix_duplicate_counter_counts.php | 65 ++++++++++++++++- .../Models/User/Counters/CounterCountTest.php | 73 ++++++++++++++++++- 2 files changed, 133 insertions(+), 5 deletions(-) diff --git a/database/migrations/2026_05_20_000000_fix_duplicate_counter_counts.php b/database/migrations/2026_05_20_000000_fix_duplicate_counter_counts.php index ae686d60b..7f735657c 100644 --- a/database/migrations/2026_05_20_000000_fix_duplicate_counter_counts.php +++ b/database/migrations/2026_05_20_000000_fix_duplicate_counter_counts.php @@ -14,10 +14,13 @@ class FixDuplicateCounterCounts extends Migration */ public function up() { + $recalculate_start_dates = []; $duplicates = DB::table('counter_counts') ->select('counter_id', 'counted_at') ->groupBy('counter_id', 'counted_at') ->havingRaw('COUNT(*) > 1') + ->orderBy('counter_id') + ->orderBy('counted_at') ->get(); foreach ($duplicates as $duplicate) { @@ -32,14 +35,27 @@ public function up() }); $source_rows = $active_rows->isNotEmpty() ? $active_rows : $rows; $keep_row = $source_rows->first(); + $day_count = $source_rows->sum('day_count'); + $total_count = $source_rows->max('total_count'); - // 1日1行へ正規化するため、日別カウントは合算し、累計は同日内の最大値を残す。 + if ($active_rows->isNotEmpty()) { + $total_count = $this->getPreviousActiveTotalCount( + $duplicate->counter_id, + $duplicate->counted_at + ) + $day_count; + $recalculate_start_dates[$duplicate->counter_id] = min( + $recalculate_start_dates[$duplicate->counter_id] ?? $duplicate->counted_at, + $duplicate->counted_at + ); + } + + // 1日1行へ正規化するため、日別カウントは合算し、累計は前日までの累計から再計算する。 // 論理削除済み行だけが重複している場合も、一意制約を追加できるよう1行にまとめる。 DB::table('counter_counts') ->where('id', $keep_row->id) ->update([ - 'day_count' => $source_rows->sum('day_count'), - 'total_count' => $source_rows->max('total_count'), + 'day_count' => $day_count, + 'total_count' => $total_count, 'updated_at' => $source_rows->max('updated_at'), 'deleted_at' => $keep_row->deleted_at, ]); @@ -51,6 +67,10 @@ public function up() ->delete(); } + foreach ($recalculate_start_dates as $counter_id => $start_date) { + $this->recalculateActiveTotalCounts($counter_id, $start_date); + } + // 以後はアプリケーション側で集計せず、DB制約で「同じカウンターの同じ日は1行」を保証する。 Schema::table('counter_counts', function (Blueprint $table) { $table->unique(['counter_id', 'counted_at'], 'counter_counts_counter_id_counted_at_unique'); @@ -68,4 +88,43 @@ public function down() $table->dropUnique('counter_counts_counter_id_counted_at_unique'); }); } + + /** + * 指定日より前の有効な最新累計を取得する。 + */ + private function getPreviousActiveTotalCount($counter_id, $counted_at) + { + return (int)(DB::table('counter_counts') + ->where('counter_id', $counter_id) + ->where('counted_at', '<', $counted_at) + ->whereNull('deleted_at') + ->orderBy('counted_at', 'desc') + ->orderBy('id', 'desc') + ->value('total_count') ?? 0); + } + + /** + * 重複統合で増減した日別カウントを、後続日の累計へ反映する。 + */ + private function recalculateActiveTotalCounts($counter_id, $start_date) + { + $total_count = $this->getPreviousActiveTotalCount($counter_id, $start_date); + $rows = DB::table('counter_counts') + ->where('counter_id', $counter_id) + ->where('counted_at', '>=', $start_date) + ->whereNull('deleted_at') + ->orderBy('counted_at') + ->orderBy('id') + ->get(); + + foreach ($rows as $row) { + $total_count += (int)$row->day_count; + + DB::table('counter_counts') + ->where('id', $row->id) + ->update([ + 'total_count' => $total_count, + ]); + } + } } diff --git a/tests/Unit/Models/User/Counters/CounterCountTest.php b/tests/Unit/Models/User/Counters/CounterCountTest.php index 8517083f2..f7cabe972 100644 --- a/tests/Unit/Models/User/Counters/CounterCountTest.php +++ b/tests/Unit/Models/User/Counters/CounterCountTest.php @@ -6,11 +6,13 @@ use Carbon\Carbon; use Illuminate\Database\QueryException; use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Schema; use Tests\TestCase; /** - * CounterCountモデルの日別カウント作成と取得を検証するテスト。 - * 公開メソッド経由で、同一日付の重複防止と昨日カウント取得の契約を守る。 + * CounterCountモデルと重複補正マイグレーションの日別カウント作成・取得を検証するテスト。 + * 公開メソッドとマイグレーション経由で、同一日付の重複防止と累計補正の契約を守る。 */ class CounterCountTest extends TestCase { @@ -70,4 +72,71 @@ public function testGetCountOrCreateKeepsOneDailyRowAndReturnsYesterdayCount(): $this->assertSame(17, (int)$first_count->total_count); $this->assertSame(7, (int)$second_count->yesterday_count); } + + /** + * 重複行を1日1行へ統合したとき、合算した日別カウントが当日と後続日の累計へ反映されることを守る。 + */ + public function testDuplicateFixMigrationRecalculatesTotalCountsAfterMergedDate(): void + { + $this->loadDuplicateFixMigration(); + $this->dropCounterCountUniqueIndex(); + DB::table('counter_counts')->delete(); + + DB::table('counter_counts')->insert([ + [ + 'counter_id' => 1, + 'counted_at' => '2026-05-19', + 'day_count' => 100, + 'total_count' => 100, + ], + [ + 'counter_id' => 1, + 'counted_at' => '2026-05-20', + 'day_count' => 1, + 'total_count' => 101, + ], + [ + 'counter_id' => 1, + 'counted_at' => '2026-05-20', + 'day_count' => 1, + 'total_count' => 101, + ], + [ + 'counter_id' => 1, + 'counted_at' => '2026-05-21', + 'day_count' => 5, + 'total_count' => 106, + ], + ]); + + (new \FixDuplicateCounterCounts())->up(); + + $merged_count = CounterCount::where('counter_id', 1)->where('counted_at', '2026-05-20')->first(); + $next_count = CounterCount::where('counter_id', 1)->where('counted_at', '2026-05-21')->first(); + + $this->assertSame(1, CounterCount::where('counter_id', 1)->where('counted_at', '2026-05-20')->count()); + $this->assertSame(2, (int)$merged_count->day_count); + $this->assertSame(102, (int)$merged_count->total_count); + $this->assertSame(107, (int)$next_count->total_count); + } + + /** + * マイグレーション単体を直接実行するため、未ロード時だけ定義ファイルを読み込む。 + */ + private function loadDuplicateFixMigration(): void + { + if (! class_exists(\FixDuplicateCounterCounts::class)) { + require_once database_path('migrations/2026_05_20_000000_fix_duplicate_counter_counts.php'); + } + } + + /** + * 重複した既存データを投入できるよう、一時的に日別一意制約を外す。 + */ + private function dropCounterCountUniqueIndex(): void + { + Schema::table('counter_counts', function ($table) { + $table->dropUnique('counter_counts_counter_id_counted_at_unique'); + }); + } } From da7b76eaa95d528d922316669baad61f99de0cdd Mon Sep 17 00:00:00 2001 From: gakigaki Date: Thu, 21 May 2026 18:23:08 +0900 Subject: [PATCH 27/49] =?UTF-8?q?test(counters):=20=E9=87=8D=E8=A4=87?= =?UTF-8?q?=E8=A3=9C=E6=AD=A3=E3=83=9E=E3=82=A4=E3=82=B0=E3=83=AC=E3=83=BC?= =?UTF-8?q?=E3=82=B7=E3=83=A7=E3=83=B3=E3=81=AE=E3=83=86=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=82=92=E5=88=86=E9=9B=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FixDuplicateCounterCountsTest.php | 85 +++++++++++++++++++ .../Models/User/Counters/CounterCountTest.php | 73 +--------------- 2 files changed, 87 insertions(+), 71 deletions(-) create mode 100644 tests/Unit/Database/Migrations/FixDuplicateCounterCountsTest.php diff --git a/tests/Unit/Database/Migrations/FixDuplicateCounterCountsTest.php b/tests/Unit/Database/Migrations/FixDuplicateCounterCountsTest.php new file mode 100644 index 000000000..56a0fea39 --- /dev/null +++ b/tests/Unit/Database/Migrations/FixDuplicateCounterCountsTest.php @@ -0,0 +1,85 @@ +loadMigration(); + $this->dropCounterCountUniqueIndex(); + DB::table('counter_counts')->delete(); + + DB::table('counter_counts')->insert([ + [ + 'counter_id' => 1, + 'counted_at' => '2026-05-19', + 'day_count' => 100, + 'total_count' => 100, + ], + [ + 'counter_id' => 1, + 'counted_at' => '2026-05-20', + 'day_count' => 1, + 'total_count' => 101, + ], + [ + 'counter_id' => 1, + 'counted_at' => '2026-05-20', + 'day_count' => 1, + 'total_count' => 101, + ], + [ + 'counter_id' => 1, + 'counted_at' => '2026-05-21', + 'day_count' => 5, + 'total_count' => 106, + ], + ]); + + (new \FixDuplicateCounterCounts())->up(); + + $merged_count = CounterCount::where('counter_id', 1)->where('counted_at', '2026-05-20')->first(); + $next_count = CounterCount::where('counter_id', 1)->where('counted_at', '2026-05-21')->first(); + + $this->assertSame(1, CounterCount::where('counter_id', 1)->where('counted_at', '2026-05-20')->count()); + $this->assertSame(2, (int)$merged_count->day_count); + $this->assertSame(102, (int)$merged_count->total_count); + $this->assertSame(107, (int)$next_count->total_count); + } + + /** + * マイグレーション単体を直接実行するため、未ロード時だけ定義ファイルを読み込む。 + */ + private function loadMigration(): void + { + if (! class_exists(\FixDuplicateCounterCounts::class)) { + require_once database_path('migrations/2026_05_20_000000_fix_duplicate_counter_counts.php'); + } + } + + /** + * 重複した既存データを投入できるよう、一時的に日別一意制約を外す。 + */ + private function dropCounterCountUniqueIndex(): void + { + Schema::table('counter_counts', function ($table) { + $table->dropUnique('counter_counts_counter_id_counted_at_unique'); + }); + } +} diff --git a/tests/Unit/Models/User/Counters/CounterCountTest.php b/tests/Unit/Models/User/Counters/CounterCountTest.php index f7cabe972..8517083f2 100644 --- a/tests/Unit/Models/User/Counters/CounterCountTest.php +++ b/tests/Unit/Models/User/Counters/CounterCountTest.php @@ -6,13 +6,11 @@ use Carbon\Carbon; use Illuminate\Database\QueryException; use Illuminate\Foundation\Testing\RefreshDatabase; -use Illuminate\Support\Facades\DB; -use Illuminate\Support\Facades\Schema; use Tests\TestCase; /** - * CounterCountモデルと重複補正マイグレーションの日別カウント作成・取得を検証するテスト。 - * 公開メソッドとマイグレーション経由で、同一日付の重複防止と累計補正の契約を守る。 + * CounterCountモデルの日別カウント作成と取得を検証するテスト。 + * 公開メソッド経由で、同一日付の重複防止と昨日カウント取得の契約を守る。 */ class CounterCountTest extends TestCase { @@ -72,71 +70,4 @@ public function testGetCountOrCreateKeepsOneDailyRowAndReturnsYesterdayCount(): $this->assertSame(17, (int)$first_count->total_count); $this->assertSame(7, (int)$second_count->yesterday_count); } - - /** - * 重複行を1日1行へ統合したとき、合算した日別カウントが当日と後続日の累計へ反映されることを守る。 - */ - public function testDuplicateFixMigrationRecalculatesTotalCountsAfterMergedDate(): void - { - $this->loadDuplicateFixMigration(); - $this->dropCounterCountUniqueIndex(); - DB::table('counter_counts')->delete(); - - DB::table('counter_counts')->insert([ - [ - 'counter_id' => 1, - 'counted_at' => '2026-05-19', - 'day_count' => 100, - 'total_count' => 100, - ], - [ - 'counter_id' => 1, - 'counted_at' => '2026-05-20', - 'day_count' => 1, - 'total_count' => 101, - ], - [ - 'counter_id' => 1, - 'counted_at' => '2026-05-20', - 'day_count' => 1, - 'total_count' => 101, - ], - [ - 'counter_id' => 1, - 'counted_at' => '2026-05-21', - 'day_count' => 5, - 'total_count' => 106, - ], - ]); - - (new \FixDuplicateCounterCounts())->up(); - - $merged_count = CounterCount::where('counter_id', 1)->where('counted_at', '2026-05-20')->first(); - $next_count = CounterCount::where('counter_id', 1)->where('counted_at', '2026-05-21')->first(); - - $this->assertSame(1, CounterCount::where('counter_id', 1)->where('counted_at', '2026-05-20')->count()); - $this->assertSame(2, (int)$merged_count->day_count); - $this->assertSame(102, (int)$merged_count->total_count); - $this->assertSame(107, (int)$next_count->total_count); - } - - /** - * マイグレーション単体を直接実行するため、未ロード時だけ定義ファイルを読み込む。 - */ - private function loadDuplicateFixMigration(): void - { - if (! class_exists(\FixDuplicateCounterCounts::class)) { - require_once database_path('migrations/2026_05_20_000000_fix_duplicate_counter_counts.php'); - } - } - - /** - * 重複した既存データを投入できるよう、一時的に日別一意制約を外す。 - */ - private function dropCounterCountUniqueIndex(): void - { - Schema::table('counter_counts', function ($table) { - $table->dropUnique('counter_counts_counter_id_counted_at_unique'); - }); - } } From c2f243c358078162c2ddf2afa41dfdaa9c439d85 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Thu, 21 May 2026 18:28:52 +0900 Subject: [PATCH 28/49] fix(blogs): preserve posted-at template defaults --- .../default/blogs_setting_frame.blade.php | 9 +++++-- .../blogs/default/include_posted_at.blade.php | 5 ++-- .../user/blogs/designbase/blogs.blade.php | 2 +- .../blogs/designbase/blogs_show.blade.php | 2 +- .../User/Blogs/BlogPostedAtFormatTest.php | 25 ++++++++++++++++--- 5 files changed, 33 insertions(+), 10 deletions(-) diff --git a/resources/views/plugins/user/blogs/default/blogs_setting_frame.blade.php b/resources/views/plugins/user/blogs/default/blogs_setting_frame.blade.php index 8b5c3c5e2..7de691d32 100644 --- a/resources/views/plugins/user/blogs/default/blogs_setting_frame.blade.php +++ b/resources/views/plugins/user/blogs/default/blogs_setting_frame.blade.php @@ -21,6 +21,11 @@

@else + @php + $default_display_posted_time = in_array($frame->template, ['titleindex', 'sidetitleindex', 'designbase'], true) ? ShowType::not_show : ShowType::show; + $default_posted_at_format = $frame->template == 'designbase' ? BlogPostedAtFormat::slash : BlogPostedAtFormat::japanese; + @endphp + {{-- 共通エラーメッセージ 呼び出し --}} @include('plugins.common.errors_form_line') @@ -63,7 +68,7 @@ class="form-control col-sm-3 @if ($errors->has(BlogFrameConfig::blog_view_count)
@foreach (ShowType::getMembers() as $enum_value => $enum_label)
- @if (FrameConfig::getConfigValueAndOld($frame_configs, BlogFrameConfig::blog_display_posted_time, ShowType::show) == $enum_value) + @if (FrameConfig::getConfigValueAndOld($frame_configs, BlogFrameConfig::blog_display_posted_time, $default_display_posted_time) == $enum_value) @else @@ -80,7 +85,7 @@ class="form-control col-sm-3 @if ($errors->has(BlogFrameConfig::blog_view_count)
@include('plugins.common.errors_inline', ['name' => BlogFrameConfig::blog_posted_at_format]) diff --git a/resources/views/plugins/user/blogs/default/include_posted_at.blade.php b/resources/views/plugins/user/blogs/default/include_posted_at.blade.php index 00b733355..5ee22946c 100644 --- a/resources/views/plugins/user/blogs/default/include_posted_at.blade.php +++ b/resources/views/plugins/user/blogs/default/include_posted_at.blade.php @@ -2,10 +2,11 @@ * ブログ投稿日時の表示部品。 * * フレーム設定が未保存の場合は、呼び出し元テンプレートの改修前表示に合わせるため、 - * default_display_posted_time で時刻表示の既定値を指定できる。 + * default_display_posted_time と default_posted_at_format で既定値を指定できる。 --}} @php - $posted_at_format = FrameConfig::getConfigValue($frame_configs, BlogFrameConfig::blog_posted_at_format, BlogPostedAtFormat::japanese); + $default_posted_at_format = $default_posted_at_format ?? BlogPostedAtFormat::japanese; + $posted_at_format = FrameConfig::getConfigValue($frame_configs, BlogFrameConfig::blog_posted_at_format, $default_posted_at_format); $default_display_posted_time = $default_display_posted_time ?? ShowType::show; $display_posted_time = FrameConfig::getConfigValue($frame_configs, BlogFrameConfig::blog_display_posted_time, $default_display_posted_time); @endphp diff --git a/resources/views/plugins/user/blogs/designbase/blogs.blade.php b/resources/views/plugins/user/blogs/designbase/blogs.blade.php index 2df8f8c75..367e5153d 100644 --- a/resources/views/plugins/user/blogs/designbase/blogs.blade.php +++ b/resources/views/plugins/user/blogs/designbase/blogs.blade.php @@ -65,7 +65,7 @@ @forelse($blogs_posts as $post) {{-- 投稿日時 --}}
- @include('plugins.user.blogs.default.include_posted_at', ['posted_at' => $post->posted_at, 'default_display_posted_time' => ShowType::not_show]) + @include('plugins.user.blogs.default.include_posted_at', ['posted_at' => $post->posted_at, 'default_display_posted_time' => ShowType::not_show, 'default_posted_at_format' => BlogPostedAtFormat::slash]) {{-- 投稿者名 --}} @if (FrameConfig::getConfigValue($frame_configs, BlogFrameConfig::blog_display_created_name) === BlogDisplayCreatedName::display) [{{$post->created_name}}] diff --git a/resources/views/plugins/user/blogs/designbase/blogs_show.blade.php b/resources/views/plugins/user/blogs/designbase/blogs_show.blade.php index 70583efdb..1dbfc6b8b 100644 --- a/resources/views/plugins/user/blogs/designbase/blogs_show.blade.php +++ b/resources/views/plugins/user/blogs/designbase/blogs_show.blade.php @@ -14,7 +14,7 @@
{{-- 投稿日時 --}}

- @include('plugins.user.blogs.default.include_posted_at', ['posted_at' => $post->posted_at, 'default_display_posted_time' => ShowType::not_show]) + @include('plugins.user.blogs.default.include_posted_at', ['posted_at' => $post->posted_at, 'default_display_posted_time' => ShowType::not_show, 'default_posted_at_format' => BlogPostedAtFormat::slash]) {{-- 投稿者名 --}} @if (FrameConfig::getConfigValue($frame_configs, BlogFrameConfig::blog_display_created_name) === BlogDisplayCreatedName::display) [{{$post->created_name}}] diff --git a/tests/Unit/Plugins/User/Blogs/BlogPostedAtFormatTest.php b/tests/Unit/Plugins/User/Blogs/BlogPostedAtFormatTest.php index 9c5cea014..97ad45713 100644 --- a/tests/Unit/Plugins/User/Blogs/BlogPostedAtFormatTest.php +++ b/tests/Unit/Plugins/User/Blogs/BlogPostedAtFormatTest.php @@ -66,12 +66,26 @@ public function testPostedAtDisplaysTimeByDefault(): void public function testPostedAtCanUseTemplateDefaultToHideTime(): void { $html = $this->renderPostedAt( - [ - BlogFrameConfig::blog_posted_at_format => BlogPostedAtFormat::slash, - ], + [], ShowType::not_show ); + $this->assertStringContainsString('class="blog-posted-at-date">2026年5月20日', $html); + $this->assertStringNotContainsString('09:30', strip_tags($html)); + $this->assertStringNotContainsString('blog-posted-at-time', $html); + } + + /** + * テンプレート側が日付形式も既定にしている場合は、設定未保存でも既存テンプレートの表示形式を保つこと。 + */ + public function testPostedAtCanUseTemplateDefaultFormat(): void + { + $html = $this->renderPostedAt( + [], + ShowType::not_show, + BlogPostedAtFormat::slash + ); + $this->assertStringContainsString('class="blog-posted-at-date">2026/05/20', $html); $this->assertStringNotContainsString('09:30', strip_tags($html)); $this->assertStringNotContainsString('blog-posted-at-time', $html); @@ -94,7 +108,7 @@ public function testPostedAtCanBeDisplayedWithJapaneseEraFormat(): void /** * 表示部品に渡すフレーム設定を組み立てて、投稿日時のHTMLを返す。 */ - private function renderPostedAt(array $configs, ?string $default_display_posted_time = null): string + private function renderPostedAt(array $configs, ?string $default_display_posted_time = null, ?string $default_posted_at_format = null): string { $frame_configs = new Collection(); foreach ($configs as $name => $value) { @@ -108,6 +122,9 @@ private function renderPostedAt(array $configs, ?string $default_display_posted_ if (!is_null($default_display_posted_time)) { $view_data['default_display_posted_time'] = $default_display_posted_time; } + if (!is_null($default_posted_at_format)) { + $view_data['default_posted_at_format'] = $default_posted_at_format; + } return view('plugins.user.blogs.default.include_posted_at', $view_data)->render(); } From 87882b833d7aecfcd21399a36ed089630155efd9 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Thu, 21 May 2026 18:29:11 +0900 Subject: [PATCH 29/49] test(blogs): skip era format test without intl --- tests/Unit/Plugins/User/Blogs/BlogPostedAtFormatTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Unit/Plugins/User/Blogs/BlogPostedAtFormatTest.php b/tests/Unit/Plugins/User/Blogs/BlogPostedAtFormatTest.php index 97ad45713..565e37310 100644 --- a/tests/Unit/Plugins/User/Blogs/BlogPostedAtFormatTest.php +++ b/tests/Unit/Plugins/User/Blogs/BlogPostedAtFormatTest.php @@ -96,6 +96,10 @@ public function testPostedAtCanUseTemplateDefaultFormat(): void */ public function testPostedAtCanBeDisplayedWithJapaneseEraFormat(): void { + if (!class_exists(\IntlDateFormatter::class)) { + $this->markTestSkipped('IntlDateFormatter が利用できない環境では和暦表示を検証しない。'); + } + $html = $this->renderPostedAt([ BlogFrameConfig::blog_posted_at_format => BlogPostedAtFormat::japanese_era, BlogFrameConfig::blog_display_posted_time => ShowType::show, From 1ff48c6e125e232f363d248cc754adf0ad127178 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Fri, 22 May 2026 11:47:55 +0900 Subject: [PATCH 30/49] =?UTF-8?q?fix(photoalbums):=20=E3=82=AB=E3=82=B9?= =?UTF-8?q?=E3=82=BF=E3=83=A0=E9=A0=86=E3=82=92=E4=BB=BB=E6=84=8F=E3=81=AE?= =?UTF-8?q?=E4=B8=A6=E3=81=B3=E9=A0=86=E3=81=A7=E5=88=9D=E6=9C=9F=E5=8C=96?= =?UTF-8?q?=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=99?= =?UTF-8?q?=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../User/Photoalbums/PhotoalbumsPlugin.php | 66 ++++- .../user/photoalbums/default/frame.blade.php | 58 ++++- ...oalbumsManualSortInitializeFeatureTest.php | 243 ++++++++++++++++++ 3 files changed, 355 insertions(+), 12 deletions(-) create mode 100644 tests/Feature/Plugins/User/Photoalbums/PhotoalbumsManualSortInitializeFeatureTest.php diff --git a/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php b/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php index faa89f3fc..c6c3630be 100644 --- a/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php +++ b/app/Plugins/User/Photoalbums/PhotoalbumsPlugin.php @@ -513,6 +513,48 @@ private function applySortToVisibleChildrenQuery(Builder $query, string $target, return $query->orderBy('photoalbum_contents.id', 'asc'); } + /** + * カスタム順の初期化に使える並び順を返す。 + */ + private function getManualSortInitializeOptions(): array + { + $sort_options = PhotoalbumSort::getMembers(); + unset($sort_options[PhotoalbumSort::manual_order]); + + return $sort_options; + } + + /** + * カスタム順の初期化に使える並び順か判定する。 + */ + private function isManualSortInitializeKey(?string $sort_key): bool + { + return array_key_exists((string) $sort_key, $this->getManualSortInitializeOptions()); + } + + /** + * 指定した並び順でカスタム順の表示順を再採番する。 + */ + private function initializeManualSortSequence(Photoalbum $photoalbum, string $target, string $sort_key): void + { + if (!$this->isManualSortInitializeKey($sort_key)) { + return; + } + + $items = $this->getSortedPhotoalbumItemsByTarget($photoalbum->id, $target, $sort_key, $sort_key); + + foreach ($items->groupBy('parent_id') as $siblings) { + $sequence = 1; + foreach ($siblings as $sibling) { + if ($sibling->display_sequence != $sequence) { + $sibling->display_sequence = $sequence; + $sibling->save(); + } + $sequence++; + } + } + } + /** * 親配下の表示可能コンテンツ(対象種別)を並び順付きクエリで取得する。 */ @@ -2191,6 +2233,7 @@ public function editView($request, $page_id, $frame_id) 'sort_file' => $sort_file, 'sorted_children_map' => $sorted_children_map, 'focus_open_ids' => $focus_open_ids, + 'manual_sort_initialize_options' => $this->getManualSortInitializeOptions(), ]); } @@ -2237,11 +2280,15 @@ public function saveView($request, $page_id, $frame_id, $photoalbum_id) 'description_list_length' => ['nullable', 'integer', 'min:1'], 'load_more_use_flag' => ['required', Rule::in(\App\Enums\UseType::getMemberKeys())], 'load_more_count' => ['nullable', 'integer', 'min:1', 'max:' . $max_load_more_limit], + 'manual_sort_initialize_folder' => ['nullable', Rule::in(array_keys($this->getManualSortInitializeOptions()))], + 'manual_sort_initialize_file' => ['nullable', Rule::in(array_keys($this->getManualSortInitializeOptions()))], ]); $validator->setAttributeNames([ 'description_list_length' => PhotoalbumFrameConfig::enum['description_list_length'], 'load_more_use_flag' => PhotoalbumFrameConfig::enum['load_more_use_flag'], 'load_more_count' => PhotoalbumFrameConfig::enum['load_more_count'], + 'manual_sort_initialize_folder' => 'アルバムのカスタム順初期化', + 'manual_sort_initialize_file' => '写真のカスタム順初期化', ]); // エラーがあった場合は入力画面に戻る。 @@ -2249,8 +2296,23 @@ public function saveView($request, $page_id, $frame_id, $photoalbum_id) return redirect()->back()->withErrors($validator)->withInput(); } - // フレーム設定保存 - $this->saveFrameConfigs($request, $frame_id, PhotoalbumFrameConfig::getMemberKeys()); + DB::transaction(function () use ($request, $frame_id) { + // フレーム設定保存 + $this->saveFrameConfigs($request, $frame_id, PhotoalbumFrameConfig::getMemberKeys()); + + $photoalbum = $this->getPluginBucket($this->getBucketId()); + if (empty($photoalbum->id)) { + return; + } + + if ($request->sort_folder === PhotoalbumSort::manual_order && !empty($request->manual_sort_initialize_folder)) { + $this->initializeManualSortSequence($photoalbum, 'folder', $request->manual_sort_initialize_folder); + } + if ($request->sort_file === PhotoalbumSort::manual_order && !empty($request->manual_sort_initialize_file)) { + $this->initializeManualSortSequence($photoalbum, 'image', $request->manual_sort_initialize_file); + } + }); + // 更新したので、frame_configsを設定しなおす $this->refreshFrameConfigs(); diff --git a/resources/views/plugins/user/photoalbums/default/frame.blade.php b/resources/views/plugins/user/photoalbums/default/frame.blade.php index 626c89a71..b058614cf 100644 --- a/resources/views/plugins/user/photoalbums/default/frame.blade.php +++ b/resources/views/plugins/user/photoalbums/default/frame.blade.php @@ -14,6 +14,7 @@ $(function () { var detailValue = '{{ \App\Enums\PhotoalbumPlayviewType::play_in_detail }}'; var loadMoreUseValue = '{{ \App\Enums\UseType::use }}'; + var manualSortValue = '{{ \App\Enums\PhotoalbumSort::manual_order }}'; function togglePlayViewOptions(value) { var isDetail = value == detailValue; @@ -28,6 +29,17 @@ function toggleLoadMoreOptions() { $('.photoalbum-load-more-options').toggleClass('text-muted', !isEnabled); } + function toggleManualSortInitializeOptions() { + $('.photoalbum-manual-sort-initialize-folder').toggleClass( + 'd-none', + $('select[name="sort_folder"]').val() != manualSortValue + ); + $('.photoalbum-manual-sort-initialize-file').toggleClass( + 'd-none', + $('select[name="sort_file"]').val() != manualSortValue + ); + } + var isVisibilitySaving = false; var pendingVisibilitySave = false; var $frameForm = $('#photoalbum-frame-settings-{{ $frame_id }}'); @@ -38,6 +50,8 @@ function toggleLoadMoreOptions() { $('input[name="load_more_use_flag"]').on('change', toggleLoadMoreOptions); toggleLoadMoreOptions(); + $('select[name="sort_folder"], select[name="sort_file"]').on('change', toggleManualSortInitializeOptions); + toggleManualSortInitializeOptions(); function setVisibilitySaving(isSaving) { $('.photoalbum-visibility-toggle__input').prop('disabled', isSaving); @@ -538,11 +552,23 @@ class="form-control col-sm-3 @if($errors->has('description_list_length')) border @endif @endforeach - @if (($current_sort_folder ?? '') === PhotoalbumSort::manual_order) - - カスタム順の変更は 表示プレビュー の上下ボタンから行えます。 - - @endif + + カスタム順の変更は 表示プレビュー の上下ボタンから行えます。 + +

+ + +
+ + アルバム並び順がカスタム順のときだけ、変更確定時に選択した並び順でカスタム順を作り直します。 +
{{-- 写真並び順 --}} @@ -559,11 +585,23 @@ class="form-control col-sm-3 @if($errors->has('description_list_length')) border @endif @endforeach - @if (($current_sort_file ?? '') === PhotoalbumSort::manual_order) - - カスタム順の変更は 表示プレビュー の上下ボタンから行えます。 - - @endif + + カスタム順の変更は 表示プレビュー の上下ボタンから行えます。 + +
+ + +
+ + 写真並び順がカスタム順のときだけ、変更確定時に選択した並び順でカスタム順を作り直します。 +
diff --git a/tests/Feature/Plugins/User/Photoalbums/PhotoalbumsManualSortInitializeFeatureTest.php b/tests/Feature/Plugins/User/Photoalbums/PhotoalbumsManualSortInitializeFeatureTest.php new file mode 100644 index 000000000..846335bba --- /dev/null +++ b/tests/Feature/Plugins/User/Photoalbums/PhotoalbumsManualSortInitializeFeatureTest.php @@ -0,0 +1,243 @@ +seed(); + } + + /** + * アルバム並び順をカスタム順にするとき、選択した名前順でカスタム順を初期化できること。 + */ + public function testSaveViewInitializesFolderManualSortFromSelectedSort(): void + { + [$page, $frame, $root, $photoalbum] = $this->makePhotoalbumFrame(); + $gamma = $this->createFolderContent($root, $photoalbum->id, 1, 'gamma'); + $alpha = $this->createFolderContent($root, $photoalbum->id, 2, 'alpha'); + $beta = $this->createFolderContent($root, $photoalbum->id, 3, 'beta'); + + $admin = $this->createContentAdminUser(); + $response = $this->actingAs($admin)->post( + "/redirect/plugin/photoalbums/saveView/{$page->id}/{$frame->id}/{$photoalbum->id}", + $this->makeSaveViewPayload([ + 'redirect_path' => "/plugin/photoalbums/editView/{$page->id}/{$frame->id}/{$photoalbum->bucket_id}", + 'sort_folder' => PhotoalbumSort::manual_order, + 'sort_file' => PhotoalbumSort::name_asc, + 'manual_sort_initialize_folder' => PhotoalbumSort::name_asc, + ]) + ); + + $response->assertStatus(302); + $this->assertSame( + [$alpha->id, $beta->id, $gamma->id], + $this->getOrderedChildIds($root->id, PhotoalbumContent::is_folder_on) + ); + $this->assertDatabaseHas('frame_configs', [ + 'frame_id' => $frame->id, + 'name' => PhotoalbumFrameConfig::sort_folder, + 'value' => PhotoalbumSort::manual_order, + ]); + } + + /** + * 写真並び順をカスタム順にするとき、アップロードファイル名の降順でカスタム順を初期化できること。 + */ + public function testSaveViewInitializesFileManualSortFromSelectedSort(): void + { + [$page, $frame, $root, $photoalbum] = $this->makePhotoalbumFrame(); + $alpha = $this->createImageContent($root, $photoalbum->id, 1, 'alpha.jpg'); + $gamma = $this->createImageContent($root, $photoalbum->id, 2, 'gamma.jpg'); + $beta = $this->createImageContent($root, $photoalbum->id, 3, 'beta.jpg'); + + $admin = $this->createContentAdminUser(); + $response = $this->actingAs($admin)->post( + "/redirect/plugin/photoalbums/saveView/{$page->id}/{$frame->id}/{$photoalbum->id}", + $this->makeSaveViewPayload([ + 'redirect_path' => "/plugin/photoalbums/editView/{$page->id}/{$frame->id}/{$photoalbum->bucket_id}", + 'sort_folder' => PhotoalbumSort::name_asc, + 'sort_file' => PhotoalbumSort::manual_order, + 'manual_sort_initialize_file' => PhotoalbumSort::name_desc, + ]) + ); + + $response->assertStatus(302); + $this->assertSame( + [$gamma->id, $beta->id, $alpha->id], + $this->getOrderedChildIds($root->id, PhotoalbumContent::is_folder_off) + ); + $this->assertDatabaseHas('frame_configs', [ + 'frame_id' => $frame->id, + 'name' => PhotoalbumFrameConfig::sort_file, + 'value' => PhotoalbumSort::manual_order, + ]); + } + + /** + * フォトアルバム用のページ・フレーム・バケツ・ルートを作る。 + */ + private function makePhotoalbumFrame(): array + { + $page = Page::where('permanent_link', '/')->first() ?? Page::factory()->create([ + 'permanent_link' => '/', + 'page_name' => 'home', + ]); + + $bucket = Buckets::factory()->create([ + 'bucket_name' => 'テストフォトアルバム', + 'plugin_name' => 'photoalbums', + ]); + + $frame = Frame::factory()->create([ + 'page_id' => $page->id, + 'area_id' => 2, + 'plugin_name' => 'photoalbums', + 'bucket_id' => $bucket->id, + 'template' => 'default', + 'display_sequence' => 1, + ]); + + $photoalbum = Photoalbum::create([ + 'bucket_id' => $bucket->id, + 'name' => 'テストフォトアルバム', + 'image_upload_max_size' => UploadMaxSize::two_mega_byte, + 'image_upload_max_px' => ResizedImageSize::big, + 'video_upload_max_size' => UploadMaxSize::ten_mega_byte, + ]); + + $root = PhotoalbumContent::create([ + 'photoalbum_id' => $photoalbum->id, + 'upload_id' => null, + 'name' => $photoalbum->name, + 'is_folder' => PhotoalbumContent::is_folder_on, + 'is_cover' => PhotoalbumContent::is_cover_off, + 'display_sequence' => 1, + 'parent_id' => null, + ]); + + return [$page, $frame, $root, $photoalbum]; + } + + /** + * 表示設定保存に必要な既定リクエストを作る。 + */ + private function makeSaveViewPayload(array $overrides = []): array + { + return array_merge([ + 'redirect_path' => '/', + 'hidden_folder_ids' => [''], + PhotoalbumFrameConfig::download => ShowType::not_show, + PhotoalbumFrameConfig::posted_at => ShowType::not_show, + PhotoalbumFrameConfig::load_more_use_flag => UseType::not_use, + PhotoalbumFrameConfig::embed_code => ShowType::not_show, + PhotoalbumFrameConfig::play_view => PhotoalbumPlayviewType::play_in_list, + PhotoalbumFrameConfig::description_list_length => null, + PhotoalbumFrameConfig::load_more_count => null, + PhotoalbumFrameConfig::sort_folder => PhotoalbumSort::name_asc, + PhotoalbumFrameConfig::sort_file => PhotoalbumSort::name_asc, + 'manual_sort_initialize_folder' => null, + 'manual_sort_initialize_file' => null, + ], $overrides); + } + + /** + * 子アルバムを作成する。 + */ + private function createFolderContent( + PhotoalbumContent $parent, + int $photoalbum_id, + int $display_sequence, + string $name + ): PhotoalbumContent { + return $parent->children()->create([ + 'photoalbum_id' => $photoalbum_id, + 'upload_id' => null, + 'name' => $name, + 'is_folder' => PhotoalbumContent::is_folder_on, + 'is_cover' => PhotoalbumContent::is_cover_off, + 'display_sequence' => $display_sequence, + ]); + } + + /** + * 画像コンテンツを作成する。 + */ + private function createImageContent( + PhotoalbumContent $parent, + int $photoalbum_id, + int $display_sequence, + string $original_name + ): PhotoalbumContent { + $upload = Uploads::factory()->jpg()->create([ + 'client_original_name' => $original_name, + 'plugin_name' => 'photoalbums', + ]); + + return $parent->children()->create([ + 'photoalbum_id' => $photoalbum_id, + 'upload_id' => $upload->id, + 'name' => pathinfo($original_name, PATHINFO_FILENAME), + 'is_folder' => PhotoalbumContent::is_folder_off, + 'is_cover' => PhotoalbumContent::is_cover_off, + 'display_sequence' => $display_sequence, + 'mimetype' => $upload->mimetype, + ]); + } + + /** + * 指定した親直下のコンテンツIDを表示順どおりに返す。 + */ + private function getOrderedChildIds(int $parent_id, int $is_folder): array + { + return PhotoalbumContent::where('parent_id', $parent_id) + ->where('is_folder', $is_folder) + ->orderBy('display_sequence') + ->orderBy('id') + ->pluck('id') + ->all(); + } + + /** + * コンテンツ管理者権限を持つユーザーを作成する。 + */ + private function createContentAdminUser(): User + { + $user = User::factory()->create(); + + UsersRoles::factory()->create([ + 'users_id' => $user->id, + 'target' => 'base', + 'role_name' => 'role_article_admin', + 'role_value' => 1, + ]); + + return $user; + } +} From da6939589039e916bdff0434be85990651a98a01 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Fri, 22 May 2026 15:15:18 +0900 Subject: [PATCH 31/49] =?UTF-8?q?feat(wysiwyg):=20=E8=A4=87=E6=95=B0?= =?UTF-8?q?=E7=94=BB=E5=83=8F=E3=82=A2=E3=83=83=E3=83=97=E3=83=AD=E3=83=BC?= =?UTF-8?q?=E3=83=89=E3=81=AB=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/js/tinymce/plugins/image/plugin.js | 112 +++++++++++++++++- .../views/plugins/common/wysiwyg.blade.php | 89 ++++++++++---- 2 files changed, 172 insertions(+), 29 deletions(-) diff --git a/resources/js/tinymce/plugins/image/plugin.js b/resources/js/tinymce/plugins/image/plugin.js index da60b3f37..87dc15334 100644 --- a/resources/js/tinymce/plugins/image/plugin.js +++ b/resources/js/tinymce/plugins/image/plugin.js @@ -779,6 +779,61 @@ }); } }; + const additionalImagesKey = 'cc_multiple_images'; + const getAdditionalImages = editor => { + const images = editor.cc_multiple_image_uploads; + return isArray(images) ? images : []; + }; + const hasAdditionalImages = editor => getAdditionalImages(editor).length > 0; + const getSelectedImageCount = editor => hasAdditionalImages(editor) ? getAdditionalImages(editor).length + 1 : 0; + const getSelectedImageCountId = editor => `cc-selected-image-count-${ editor.id }`; + // 複数選択時は代替説明欄を空にするため、1枚目のファイル名由来altを別に保持する。 + const getFirstImageAlt = editor => { + const alt = editor.cc_multiple_image_first_alt; + return isString(alt) ? alt : ''; + }; + const clearAdditionalImages = editor => { + editor.cc_multiple_image_uploads = []; + editor.cc_multiple_image_first_alt = ''; + }; + // TinyMCEの画像ダイアログは1つのsrcしか扱えないため、2枚目以降は保存時に追加挿入する。 + const insertAdditionalImagesAfterSelection = (editor, images) => { + const selectedImage = getSelectedImage(editor); + if (!selectedImage || images.length === 0) { + return; + } + const target = isFigure(selectedImage.parentNode) ? selectedImage.parentNode : selectedImage; + const marker = '__mceadditionalimage'; + const html = images.map((imageData, index) => { + const data = sanitizeImageData(editor, { + ...defaultData(), + ...imageData + }); + const elm = create(css => normalizeCss$1(editor, css), data); + if (index === images.length - 1) { + editor.dom.setAttrib(elm, 'data-mce-id', marker); + } + return elm.outerHTML; + }).join(''); + if (html.length > 0) { + editor.dom.insertAfter(editor.dom.createFragment(html), target); + const insertedElm = editor.dom.select(`*[data-mce-id="${ marker }"]`)[0]; + if (insertedElm) { + editor.dom.setAttrib(insertedElm, 'data-mce-id', null); + editor.selection.select(insertedElm); + } + editor.nodeChanged(); + } + }; + const insertOrUpdateImages = (editor, data) => { + const additionalImages = isArray(data[additionalImagesKey]) ? data[additionalImagesKey] : []; + const imageData = { + ...data + }; + delete imageData[additionalImagesKey]; + insertOrUpdateImage(editor, imageData); + insertAdditionalImagesAfterSelection(editor, additionalImages); + }; const deep = (old, nu) => { const bothObjects = isPlainObject(old) && isPlainObject(nu); @@ -1005,6 +1060,10 @@ type: 'collection', label: tinymce.activeEditor.options.get('cc_config').upload_max_filesize_caption, }; + const selectedImageCount = { + type: 'htmlpanel', + html: `` + }; const imageList = info.imageList.map(items => ({ name: 'images', @@ -1071,6 +1130,7 @@ } : { type: 'panel' }; return flatten([ [imageUrl], + [selectedImageCount], // add: アップロード最大サイズ説明 [uploadMaxFilesizeCaption], imageList.toArray(), @@ -1276,6 +1336,29 @@ formFillFromMeta(info, api); calculateImageSize(helpers, info, state, api); updateImagesDropdown(info, state, api); + updateAltInputState(helpers.editor, info, api); + updateSelectedImageCountText(helpers.editor); + }; + // 複数画像選択時だけ、画像ダイアログ内に選択枚数を表示する。 + const updateSelectedImageCountText = editor => { + const countPanel = document.getElementById(getSelectedImageCountId(editor)); + if (countPanel) { + const selectedImageCount = getSelectedImageCount(editor); + countPanel.textContent = selectedImageCount > 1 ? `${ selectedImageCount }枚の画像を選択しています。` : ''; + countPanel.style.display = selectedImageCount > 1 ? 'block' : 'none'; + } + }; + // 複数画像に1つの説明文を適用しないよう、複数選択時はalt入力を空にして無効化する。 + const updateAltInputState = (editor, info, api) => { + if (info.hasDescription) { + const data = api.getData(); + const hasMultipleImages = hasAdditionalImages(editor); + if (hasMultipleImages && data.alt !== '') { + api.setData({ alt: '' }); + } + const enabled = !hasMultipleImages && !(info.hasAccessibilityOptions && data.isDecorative); + api.setEnabled('alt', enabled); + } }; const changeImages = (helpers, info, state, api) => { const data = api.getData(); @@ -1353,7 +1436,7 @@ } else if (evt.name === 'fileinput') { changeFileInput(helpers, info, state, api); } else if (evt.name === 'isDecorative') { - api.setEnabled('alt', !api.getData().isDecorative); + updateAltInputState(helpers.editor, info, api); } }; const closeHandler = state => () => { @@ -1386,8 +1469,27 @@ ...data, style: getStyleValue(helpers.normalizeCss, toImageData(data, false)) }; - editor.execCommand('mceUpdateImage', false, toImageData(finalData, info.hasAccessibilityOptions)); - editor.editorUpload.uploadImagesAuto(); + const imageData = toImageData(finalData, info.hasAccessibilityOptions); + if (hasAdditionalImages(editor)) { + imageData.alt = getFirstImageAlt(editor); + } + const additionalImages = getAdditionalImages(editor).map(image => ({ + ...imageData, + src: image.src, + alt: image.alt, + width: '', + height: '' + })); + editor.execCommand('mceUpdateImage', false, { + ...imageData, + [additionalImagesKey]: additionalImages + }); + clearAdditionalImages(editor); + editor.editorUpload.uploadImagesAuto().then(() => { + editor.dispatch('ccImageUploadComplete'); + }, () => { + editor.dispatch('ccImageUploadComplete'); + }); api.close(); }; const imageSize = editor => url => { @@ -1434,6 +1536,7 @@ }); const Dialog = editor => { const helpers = { + editor, imageSize: imageSize(editor), addToBlobCache: addToBlobCache(editor), createBlobCache: createBlobCache(editor), @@ -1444,6 +1547,7 @@ uploadImage: uploadImage(editor) }; const open = () => { + clearAdditionalImages(editor); collect(editor).then(info => { const state = createState(info); return { @@ -1476,7 +1580,7 @@ const register$1 = editor => { editor.addCommand('mceImage', Dialog(editor).open); editor.addCommand('mceUpdateImage', (_ui, data) => { - editor.undoManager.transact(() => insertOrUpdateImage(editor, data)); + editor.undoManager.transact(() => insertOrUpdateImages(editor, data)); }); }; diff --git a/resources/views/plugins/common/wysiwyg.blade.php b/resources/views/plugins/common/wysiwyg.blade.php index 78f8a58f6..501c1cafa 100644 --- a/resources/views/plugins/common/wysiwyg.blade.php +++ b/resources/views/plugins/common/wysiwyg.blade.php @@ -464,6 +464,7 @@ input.value = ''; input.removeAttribute('accept'); + input.removeAttribute('multiple'); input.onchange = function () { var file = this.files[0]; @@ -520,6 +521,7 @@ var input = document.getElementById('cc-file-upload-file-{{$frame_id}}'); // 他でも使いまわすため、ここでクリア input.value = ''; + input.removeAttribute('multiple'); // console.log(meta.fieldname); @@ -528,6 +530,8 @@ // image plugin if (meta.fieldname == 'src') { + input.setAttribute('multiple', 'multiple'); + // 画像はimages_upload_handlerが動作するため、サンプル通りにblobCacheに追加する. (blobCacheに入れるとなんでアップロードできるか詳細わからなかった。) /* Note: In modern browsers input[type="file"] is functional without @@ -537,38 +541,68 @@ once you do not need it anymore. */ input.onchange = function () { - var file = this.files[0]; + var files = Array.prototype.slice.call(this.files); + var editor = tinymce.activeEditor; - var reader = new FileReader(); - reader.onload = function () { - /* - Note: Now we need to register the blob in TinyMCEs image blob - registry. In the next release this part hopefully won't be - necessary, as we are looking to handle it internally. - */ - var id = 'blobid' + (new Date()).getTime(); - var blobCache = tinymce.activeEditor.editorUpload.blobCache; - var base64 = reader.result.split(',')[1]; - var blobInfo = blobCache.create(id, file, base64); - blobCache.add(blobInfo); - - // 拡張子取り除き - var file_name = new String(file.name).substring(file.name.lastIndexOf('/') + 1); - if (file_name.lastIndexOf(".") != -1) { - file_name = file_name.substring(0, file_name.lastIndexOf(".")); - } + editor.cc_multiple_image_uploads = []; + editor.cc_multiple_image_first_alt = ''; + + if (files.length === 0) { + return; + } + + var image_promises = files.map(function(file, index) { + return new Promise(function(resolve, reject) { + var reader = new FileReader(); + reader.onload = function () { + /* + Note: Now we need to register the blob in TinyMCEs image blob + registry. In the next release this part hopefully won't be + necessary, as we are looking to handle it internally. + */ + var id = 'blobid' + (new Date()).getTime() + '-' + index; + var blobCache = editor.editorUpload.blobCache; + var base64 = reader.result.split(',')[1]; + var blobInfo = blobCache.create(id, file, base64); + blobCache.add(blobInfo); + + // 拡張子取り除き + var file_name = new String(file.name).substring(file.name.lastIndexOf('/') + 1); + if (file_name.lastIndexOf(".") != -1) { + file_name = file_name.substring(0, file_name.lastIndexOf(".")); + } + + resolve({ + src: blobInfo.blobUri(), + alt: file_name + }); + }; + reader.onerror = function () { + reject(reader.error); + }; + reader.readAsDataURL(file); + }); + }); + + Promise.all(image_promises).then(function(images) { + editor.cc_multiple_image_uploads = images.slice(1); + editor.cc_multiple_image_first_alt = images.length > 1 ? images[0].alt : ''; /* call the callback and populate the Title field with the file name */ // callback(blobInfo.blobUri(), { title: file.name }); // callback(blobInfo.blobUri(), { alt: file.name }); - callback(blobInfo.blobUri(), { alt: file_name }); + callback(images[0].src, { alt: images[0].alt }); // callback(file.name); - }; - reader.readAsDataURL(file); + }).catch(function(error) { + console.error('Image file read failed:', error); + editor.cc_multiple_image_uploads = []; + editor.cc_multiple_image_first_alt = ''; + }); }; } // media plugin else if (meta.fieldname == 'poster') { + input.removeAttribute('multiple'); // console.log('media'); // 動画のサムネイルはimages_upload_handlerが動作しないため、このタイミングでアップロードする @@ -627,6 +661,7 @@ var input = document.getElementById('cc-file-upload-file-{{$frame_id}}'); // 他でも使いまわすため、ここでクリア input.value = ''; + input.removeAttribute('multiple'); input.setAttribute('accept', '.mp4, .mp3'); @@ -814,9 +849,6 @@ formData.append('plugin_name', tinymce.activeEditor.options.get('cc_config').plugin_name); xhr.send(formData); - - // クリア - document.getElementById('cc-resized-image-size-' + frame_id).value = ''; }), setup: function(editor) { @@ -868,6 +900,13 @@ } }); + editor.on('ccImageUploadComplete', function () { + var frame_id = editor.options.get('cc_config').frame_id; + + // リサイズ画像サイズをクリア + document.getElementById('cc-resized-image-size-' + frame_id).value = ''; + }); + // bugfix: IE11でウィジウィグが動作しないバグ修正 // editor.on('OpenWindow', (event) => { editor.on('OpenWindow', function (event) { From b14673ca72d0c8819020c38a5e365402d2f09934 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Fri, 22 May 2026 15:18:18 +0900 Subject: [PATCH 32/49] =?UTF-8?q?build(wysiwyg):=20=E3=83=93=E3=83=AB?= =?UTF-8?q?=E3=83=89=E6=B8=88=E3=81=BF=E3=83=AA=E3=82=BD=E3=83=BC=E3=82=B9?= =?UTF-8?q?=E3=82=92=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/js/wysiwyg.js | 2 +- public/mix-manifest.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/js/wysiwyg.js b/public/js/wysiwyg.js index a090eb35d..1ea4d0582 100644 --- a/public/js/wysiwyg.js +++ b/public/js/wysiwyg.js @@ -1,2 +1,2 @@ /*! For license information please see wysiwyg.js.LICENSE.txt */ -(()=>{var e={8407(){tinymce.addI18n("ja",{"#":"#",Accessibility:"アクセシビリティ",Accordion:"アコーディオン","Accordion body...":"アコーディオンの本文...","Accordion summary...":"アコーディオンの概要...",Action:"アクション",Activity:"行動",Address:"アドレス",Advanced:"詳細",Align:"配置","Align center":"中央揃え","Align left":"左揃え","Align right":"右揃え",Alignment:"配置","Alignment {0}":"整列 {0}",All:"すべて","Alternative description":"代替の説明文","Alternative source":"代替ソース","Alternative source URL":"代替ソースURL",Anchor:"アンカー","Anchor...":"アンカー...",Anchors:"アンカー","Animals and Nature":"動物と自然",Arrows:"矢印",B:"青","Background color":"背景色","Background color {0}":"背景色 {0}",Black:"ブラック",Block:"ブロック","Block {0}":"ブロック {0}",Blockquote:"引用",Blocks:"ブロック",Blue:"ブルー","Blue component":"青色コンポーネント",Body:"本文",Bold:"太字",Border:"ボーダー","Border color":"ボーダーの色","Border style":"枠線スタイル","Border width":"枠線幅",Bottom:"下揃え","Browse files":"ファイルをブラウズ","Browse for an image":"画像を参照","Browse links":"リンクをブラウズ","Bullet list":"箇条書き",Cancel:"取消",Caption:"キャプション",Cell:"セル","Cell padding":"セル内のスペース","Cell properties":"セルのプロパティ","Cell spacing":"セルの間隔","Cell styles":"セルの種類","Cell type":"セルの種類",Center:"中央揃え",Characters:"文字数","Characters (no spaces)":"文字数 (スペースなし)",Circle:"丸",Class:"クラス","Clear formatting":"書式をクリア",Close:"閉じる",Code:"コード","Code sample...":"コードのサンプル...","Code view":"コード表示","Color Picker":"カラーピッカー","Color swatch":"色の見本",Cols:"列数",Column:"列","Column clipboard actions":"列のクリップボードアクション","Column group":"列グループ","Column header":"列のヘッダー","Constrain proportions":"縦横比を固定",Copy:"コピー","Copy column":"列をコピー","Copy row":"行のコピー","Could not find the specified string.":"お探しの文字列が見つかりませんでした。","Could not load emojis":"絵文字が読み込めませんでした",Count:"カウント",Currency:"通貨","Current window":"同じウィンドウ","Custom color":"ユーザー設定の色","Custom...":"ユーザー設定...",Cut:"切り取り","Cut column":"列をカット","Cut row":"行の切り取り","Dark Blue":"ダークブルー","Dark Gray":"ダークグレー","Dark Green":"ダークグリーン","Dark Orange":"ダークオレンジ","Dark Purple":"ダークパープル","Dark Red":"ダークレッド","Dark Turquoise":"ダークターコイズ","Dark Yellow":"ダークイエロー",Dashed:"破線","Date/time":"日付/時刻","Decrease indent":"インデントを減らす",Default:"既定","Delete accordion":"アコーディオンの削除","Delete column":"列の削除","Delete row":"行の削除","Delete table":"テーブルの削除",Dimensions:"サイズ",Disc:"黒丸",Div:"分割",Document:"ドキュメント",Dotted:"点線",Double:"二重線","Drop an image here":"ここに画像をドロップ","Dropped file type is not supported":"ドロップされたファイルタイプはサポートされていません",Edit:"編集",Embed:"埋め込み",Emojis:"絵文字","Emojis...":"絵文字...",Error:"エラー","Error: Form submit field collision.":"エラー:フォーム送信フィールドが競合しています。","Error: No form element found.":"エラー:フォーム要素が見つかりませんでした。","Extended Latin":"ラテン文字拡張","Failed to initialize plugin: {0}":"プラグイン{0}の初期化に失敗しました","Failed to load plugin url: {0}":"プラグインのURL{0}を読み込めませんでした","Failed to load plugin: {0} from url {1}":"URL{1}からのプラグイン{0}の読み込みに失敗しました","Failed to upload image: {0}":"画像{0}をアップロードできませんでした",File:"ファイル",Find:"検索...","Find (if searchreplace plugin activated)":"検索 (置換プラグイン有効時)","Find and Replace":"検索と置換","Find and replace...":"置換...","Find in selection":"選択部分で検索","Find whole words only":"語全体を含むもののみ検索",Flags:"旗","Focus to contextual toolbar":"コンテキストツールバーにフォーカス","Focus to element path":"要素パスにフォーカス","Focus to menubar":"メニューバーにフォーカス","Focus to toolbar":"ツールバーにフォーカス",Font:"フォント","Font size {0}":"フォントサイズ {0}","Font sizes":"フォントのサイズ","Font {0}":"フォント {0}",Fonts:"フォント","Food and Drink":"食べ物と飲み物",Footer:"フッター",Format:"書式設定","Format {0}":"フォーマット {0}",Formats:"書式",Fullscreen:"フルスクリーン",G:"緑",General:"一般",Gray:"グレー",Green:"グリーン","Green component":"緑色コンポーネント",Groove:"谷線","Handy Shortcuts":"便利なショートカット",Header:"ヘッダー","Header cell":"ヘッダーセル","Heading 1":"見出し1","Heading 2":"見出し2","Heading 3":"見出し3","Heading 4":"見出し4","Heading 5":"見出し5","Heading 6":"見出し6",Headings:"見出し",Height:"高さ",Help:"ヘルプ","Hex color code":"16進カラーコード",Hidden:"非表示","Horizontal align":"水平に整列","Horizontal line":"水平罫線","Horizontal space":"左右余白",ID:"ID","ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.":"IDは文字で始まり、その後に文字、数字、ダッシュ、ピリオド、コロン、またはアンダースコアが続く必要があります。","Image is decorative":"画像は装飾画像","Image list":"画像リスト","Image title":"画像タイトル","Image...":"画像..","ImageProxy HTTP error: Could not find Image Proxy":"画像プロキシ HTTPエラー:画像プロキシが見つかりませんでした","ImageProxy HTTP error: Incorrect Image Proxy URL":"画像プロキシ HTTPエラー:不正な画像プロキシURL","ImageProxy HTTP error: Rejected request":"画像プロキシ HTTPエラー:拒否されたリクエスト","ImageProxy HTTP error: Unknown ImageProxy error":"画像プロキシ HTTPエラー:不明な画像プロキシエラー","Increase indent":"インデントを増やす",Inline:"インライン",Insert:"挿入","Insert Template":"テンプレートの挿入..","Insert accordion":"アコーディオンの挿入","Insert column after":"後に列を挿入","Insert column before":"前に列を挿入","Insert date/time":"日付/時刻の挿入","Insert image":"画像の挿入","Insert link (if link plugin activated)":"リンクを挿入 (リンクプラグイン有効時)","Insert row after":"後に行を挿入","Insert row before":"前に行を挿入","Insert table":"表の挿入","Insert template...":"テンプレートの挿入..","Insert video":"動画の挿入","Insert/Edit code sample":"コードサンプルの挿入/編集","Insert/edit image":"画像の挿入/編集","Insert/edit link":"リンクの挿入/編集","Insert/edit media":"メディアの挿入/編集","Insert/edit video":"動画の挿入/編集",Inset:"内線","Invalid hex color code: {0}":"無効な16進カラーコード: {0}","Invalid input":"無効な入力",Italic:"斜体",Justify:"両端揃え","Keyboard Navigation":"キーボードナビゲーション",Language:"言語","Learn more...":"詳細...",Left:"左揃え","Left to right":"左から右","Light Blue":"ライトブルー","Light Gray":"ライトグレー","Light Green":"ライトグリーン","Light Purple":"ライトパープル","Light Red":"ライトレッド","Light Yellow":"ライトイエロー","Line height":"行の高さ","Link list":"リンクの一覧","Link...":"リンク...","List Properties":"箇条書きのプロパティ","List properties...":"箇条書きのプロパティ...","Loading emojis...":"絵文字を読み込んでいます…","Loading...":"読み込んでいます...","Lower Alpha":"小文字アルファベット","Lower Greek":"小文字ギリシャ文字","Lower Roman":"小文字ローマ字","Match case":"大文字と小文字を区別",Mathematical:"数学記号","Media poster (Image URL)":"メディアポスター (画像URL)","Media...":"メディア…","Medium Blue":"メディアムブルー","Medium Gray":"ミディアムグレー","Medium Purple":"ミディアムパープル","Merge cells":"セルの結合",Middle:"中央揃え","Midnight Blue":"ミッドナイトブルー","More...":"詳細...",Name:"名前","Navy Blue":"ネイビー","New document":"新規ドキュメント","New window":"新規ウィンドウ",Next:"次へ",No:"いいえ","No alignment":"配置なし","No color":"色なし","Nonbreaking space":"固定スペース",None:"なし","Numbered list":"番号付き箇条書き",OR:"または",Objects:"物",Ok:"OK","Open help dialog":"ヘルプダイアログを開く","Open link":"リンクを開く","Open link in...":"リンクの開き方...","Open popup menu for split buttons":"分割ボタンのポップアップメニューを開く",Orange:"オレンジ",Outset:"外線","Page break":"ページ区切り",Paragraph:"段落",Paste:"貼り付け","Paste as text":"テキストとして貼り付け","Paste column after":"後に列を貼り付け","Paste column before":"前に列を貼り付け","Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.":"貼り付けは現在プレーンテキストモードです。このオプションをオフにしない限り内容はプレーンテキストとして貼り付けられます。","Paste or type a link":"リンクをペーストまたは入力","Paste row after":"下側に行を貼り付け","Paste row before":"上側に行を貼り付け","Paste your embed code below:":"埋め込み用コードを以下に貼り付けてください。",People:"人",Plugins:"プラグイン","Plugins installed ({0}):":"インストール済プラグイン ({0}):","Powered by {0}":"{0} によって搭載された",Pre:"整形済みテキスト",Preferences:"プリファレンス",Preformatted:"書式設定済み","Premium plugins:":"プレミアムプラグイン:","Press the Up and Down arrow keys to resize the editor.":"上矢印と下矢印のキーを押してエディターのサイズを変更します。","Press the arrow keys to resize the editor.":"矢印キーを押してエディターのサイズを変更します。","Press {0} for help":"ヘルプを見るには {0} を押します",Preview:"プレビュー",Previous:"前へ",Print:"印刷","Print...":"印刷...",Purple:"パープル",Quotations:"引用",R:"赤","Range 0 to 255":"範囲0〜255",Red:"レッド","Red component":"赤色コンポーネント",Redo:"やり直し",Remove:"削除","Remove color":"色設定を解除","Remove link":"リンクの削除",Replace:"置換","Replace all":"すべて置換","Replace with":"置換後の文字列",Resize:"サイズ変更","Restore last draft":"前回の下書きを回復","Reveal or hide additional toolbar items":"追加のツール バー アイテムの表示または非表示","Rich Text Area":"リッチテキストエリア","Rich Text Area. Press ALT-0 for help.":"リッチテキストエリア。Alt-0でヘルプが表示されます。","Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help":"リッチテキストエリア。ALT-F9でメニュー、ALT-F10でツールバー、ALT-0でヘルプが表示されます。",Ridge:"山線",Right:"右揃え","Right to left":"右から左",Row:"行","Row clipboard actions":"行のクリップボードアクション","Row group":"行グループ","Row header":"行のヘッダー","Row properties":"行のプロパティ","Row type":"行タイプ",Rows:"行数",Save:"保存","Save (if save plugin activated)":"保存 (保存プラグイン有効時)",Scope:"スコープ",Search:"検索","Select all":"すべて選択","Select...":"選択...",Selection:"選択",Shortcut:"ショートカット","Show blocks":"文章の区切りを点線で表示","Show caption":"キャプションの表示","Show invisible characters":"非表示文字を表示",Size:"サイズ",Solid:"実線",Source:"ソース","Source code":"ソースコード","Special Character":"特殊文字","Special character...":"特殊文字...","Split cell":"セルの分割",Square:"四角","Start list at number":"番号リストの開始",Strikethrough:"取消線",Style:"スタイル",Subscript:"下付き",Superscript:"上付き","Switch to or from fullscreen mode":"フルスクリーンモード切替",Symbols:"記号","System Font":"システムフォント",Table:"表","Table caption":"テーブルの見出し","Table properties":"テーブルのプロパティ","Table styles":"テーブルの種類",Template:"テンプレート",Templates:"テンプレート",Text:"テキスト","Text color":"テキスト色","Text color {0}":"テキスト色 {0}","Text to display":"表示するテキスト","The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?":"入力されたURLはメールアドレスのようです。「mailto:」プレフィックスを追加しますか?","The URL you entered seems to be an external link. Do you want to add the required http:// prefix?":"入力されたURLは外部リンクのようです。「http://」プレフィックスを追加しますか?","The URL you entered seems to be an external link. Do you want to add the required https:// prefix?":"入力されたURLは外部リンクのようです。必要な「https://」プレフィックスを追加しますか?",Title:"タイトル","To open the popup, press Shift+Enter":"ポップアップを開くには、Shift+Enterを押してください","Toggle accordion":"アコーディオンの切り替え",Tools:"ツール",Top:"上揃え","Travel and Places":"旅行と場所",Turquoise:"ターコイズ",Underline:"下線",Undo:"元に戻す",Upload:"アップロード","Uploading image":"画像アップロード中","Upper Alpha":"大文字アルファベット","Upper Roman":"大文字ローマ字",Url:"URL","User Defined":"ユーザー定義",Valid:"有効",Version:"バージョン","Vertical align":"垂直に整列","Vertical space":"上下余白",View:"表示","Visual aids":"表の枠線を点線で表示",Warn:"警告",White:"ホワイト",Width:"幅","Word count":"文字数カウント",Words:"単語数","Words: {0}":"単語数:{0}",Yellow:"イエロー",Yes:"はい","You are using {0}":"{0}を使用中","You have unsaved changes are you sure you want to navigate away?":"まだ保存していない変更があります。このページを離れますか?","Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.":"お使いのブラウザではクリップボード機能を利用することができません。キーボードのショートカット(Ctrl+X, Ctrl+C, Ctrl+V)を使用してください。",alignment:"配置","austral sign":"アウストラル記号","cedi sign":"セディ記号","colon sign":"コロン記号","cruzeiro sign":"クルゼイロ記号","currency sign":"通貨記号","dollar sign":"ドル記号","dong sign":"ドン記号","drachma sign":"ドラクマ記号","euro-currency sign":"ユーロ記号",example:"例",formatting:"書式","french franc sign":"フランスフラン記号","german penny symbol":"ドイツペニー記号","guarani sign":"ガラニ記号",history:"履歴","hryvnia sign":"フリヴニャ記号",indentation:"インデント","indian rupee sign":"インドルピー記号","kip sign":"キープ記号","lira sign":"リラ記号","livre tournois sign":"トゥールポンド記号","manat sign":"マナト記号","mill sign":"ミル記号","naira sign":"ナイラ記号","new sheqel sign":"新シェケル記号","nordic mark sign":"北欧マルク記号","peseta sign":"ペセタ記号","peso sign":"ペソ記号","ruble sign":"ルーブル記号","rupee sign":"ルピー記号","spesmilo sign":"スペスミーロ記号",styles:"スタイル","tenge sign":"テンゲ記号","tugrik sign":"トゥグルグ記号","turkish lira sign":"トルコリラ記号","won sign":"ウォン記号","yen character":"円記号","yen/yuan character variant one":"円/元記号のバリエーション","yuan character":"人民元記号","yuan character, in hong kong and taiwan":"香港および台湾における元記号","{0} characters":"{0}文字","{0} columns, {1} rows":"{0} 列、{1} 行","{0} words":"{0}語"})},8760(){tinymce.PluginManager.add("cc_template",(function(e,t){e.ui.registry.addButton("cc_template",{icon:"template",tooltip:"テンプレートの挿入",onAction:function(){var t=window.cc_templates&&window.cc_templates.templates||[];Array.isArray(t)&&0!==t.length?e.windowManager.open({title:"テンプレートの挿入",body:{type:"panel",items:[{type:"selectbox",name:"template_select",label:"テンプレート",items:[{text:"選択してください。",value:""}].concat(t.map((function(e,t){return{text:e.title,value:String(t)}})))},{type:"htmlpanel",name:"preview",html:'
'}]},buttons:[{type:"cancel",text:"キャンセル"},{type:"submit",text:"挿入",primary:!0}],initialData:{template_select:""},onChange:function(e){!function(e,t){var o=e.getData().template_select,n=parseInt(o,10);if(""===o||isNaN(n))document.getElementById("template-preview").innerHTML="";else{var r=document.getElementById("template-preview");if(r){var i=t[o]||{};r.innerHTML="\n
\n
".concat(i.description||"",'
\n
').concat(i.content||"","
\n
\n ")}}}(e,t)},onSubmit:function(o){var n,r=parseInt(o.getData().template_select);e.insertContent((null===(n=t[r])||void 0===n?void 0:n.content)||""),o.close()}}):e.windowManager.alert("テンプレートが見つかりません。")}})}))},128(){tinymce.PluginManager.add("face",(function(e,t){function o(t){tinymce.activeEditor.windowManager.open({title:"AI顔認識",body:{type:"panel",items:[{type:"alertbanner",level:"info",text:"写真の顔をAIで判断して、モザイク処理を施します。",icon:"info"},{type:"urlinput",name:"photo",filetype:"file",label:"jpg, png 形式の画像ファイル"},{type:"collection",name:"upload_max_filesize_caption",label:e.options.get("cc_config").upload_max_filesize_caption},{type:"input",name:"alt",inputMode:"text",label:"代替テキスト",placeholder:"",disabled:!1,maximized:!1},{type:"listbox",name:"image_size",label:"画像サイズ(最大でこの大きさに縮小されます)",disabled:!1,items:e.options.get("cc_config").face_image_sizes},{type:"listbox",name:"mosaic_fineness",label:"モザイクの粗さ",disabled:!1,items:e.options.get("cc_config").finenesses}]},initialData:{image_size:e.options.get("cc_config").face_image_initial,mosaic_fineness:e.options.get("cc_config").fineness_initial},buttons:[{type:"cancel",text:"Close"},{type:"submit",text:"Save",primary:!0}],onSubmit:function(t){xhr=new XMLHttpRequest,xhr.withCredentials=!1,xhr.open("POST",tinymce.activeEditor.getParam("document_base_url")+"/upload/face"),xhr.onload=function(){var o;xhr.status<200||xhr.status>=300?console.error("HTTP Error: "+xhr.status):(void 0!==(o=JSON.parse(xhr.responseText)).link_text&&e.insertContent(o.link_text),document.getElementById("cc-face-upload-"+i).value="",t.close())};var o=document.getElementsByName("csrf-token"),n=document.getElementsByName("_page_id"),r=t.getData(),i=e.options.get("cc_config").frame_id;formData=new FormData,formData.append("_token",o[0].content),formData.append("page_id",n[0].content),formData.append("plugin_name",e.options.get("cc_config").plugin_name),formData.append("photo",document.getElementById("cc-face-upload-"+i).files[0]),formData.append("alt",r.alt),formData.append("image_size",r.image_size),formData.append("mosaic_fineness",r.mosaic_fineness),xhr.send(formData)}})}e.ui.registry.addIcon("face",'\x3c!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--\x3e'),e.ui.registry.addButton("face",{icon:"face",tooltip:"AI顔認識",onAction:o,onPostRender:function(){var t=this;e.on("NodeChange",(function(o){var n=jQuery(e.selection.getNode()).hasClass("plugin");t.active(n)})),e.on("DblClick",(function(e){"plugin"==e.target.className&&o(e.toElement.innerText)}))}})}))},7461(){tinymce.PluginManager.add("file",(function(e,t){function o(t){if(String(t).match(/^(&|#)/))void 0!==(o=t.match(/^(&|#)(\w+)\((.*)\)([\s\S]*)?/))[4]&&o[4].match(/;$/)&&(o[4]=o[4].replace(/;$/g,""));else var o=new Array("","","","","");tinymce.activeEditor.windowManager.open({title:"ファイルアップロード",width:600,height:250,body:{type:"panel",items:[{type:"urlinput",name:"file1",filetype:"file",label:"ファイル1"},{type:"urlinput",name:"file2",filetype:"file",label:"ファイル2"},{type:"urlinput",name:"file3",filetype:"file",label:"ファイル3"},{type:"urlinput",name:"file4",filetype:"file",label:"ファイル4"},{type:"urlinput",name:"file5",filetype:"file",label:"ファイル5"},{type:"collection",name:"upload_max_filesize_caption",label:e.options.get("cc_config").upload_max_filesize_caption}]},buttons:[{type:"cancel",text:"Close"},{type:"submit",text:"Save",primary:!0}],onSubmit:function(t){xhr=new XMLHttpRequest,xhr.withCredentials=!1,xhr.open("POST",tinymce.activeEditor.getParam("document_base_url")+"/upload"),xhr.onload=function(){var o;if(xhr.status<200||xhr.status>=300)console.error("HTTP Error: "+xhr.status);else{for(var n in(o=JSON.parse(xhr.responseText)).link_texts)e.insertContent(o.link_texts[n]);document.getElementById("cc-file-upload-file1-"+r).value="",document.getElementById("cc-file-upload-file2-"+r).value="",document.getElementById("cc-file-upload-file3-"+r).value="",document.getElementById("cc-file-upload-file4-"+r).value="",document.getElementById("cc-file-upload-file5-"+r).value="",t.close()}};var o=document.getElementsByName("csrf-token"),n=document.getElementsByName("_page_id");formData=new FormData,formData.append("_token",o[0].content),formData.append("page_id",n[0].content),formData.append("plugin_name",e.options.get("cc_config").plugin_name);var r=e.options.get("cc_config").frame_id;formData.append("file1",document.getElementById("cc-file-upload-file1-"+r).files[0]),formData.append("file2",document.getElementById("cc-file-upload-file2-"+r).files[0]),formData.append("file3",document.getElementById("cc-file-upload-file3-"+r).files[0]),formData.append("file4",document.getElementById("cc-file-upload-file4-"+r).files[0]),formData.append("file5",document.getElementById("cc-file-upload-file5-"+r).files[0]),xhr.send(formData)}})}e.ui.registry.addIcon("file",'\x3c!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--\x3e'),e.ui.registry.addButton("file",{icon:"file",tooltip:"ファイルアップロード",onAction:o,onPostRender:function(){var t=this;e.on("NodeChange",(function(o){var n=jQuery(e.selection.getNode()).hasClass("plugin");t.active(n)})),e.on("DblClick",(function(e){"plugin"==e.target.className&&o(e.toElement.innerText)}))}})}))},4228(){function e(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,n)}return o}function t(t){for(var n=1;n=0&&t1){var n="HTML does not have a single root node";throw console.error(n,e),new Error(n)}return I(o.childNodes[0])},fromTag:function(e,t){var o=(t||document).createElement(e);return I(o)},fromText:function(e,t){var o=(t||document).createTextNode(e);return I(o)},fromDom:I,fromPoint:function(e,t,o){return x.from(e.dom.elementFromPoint(t,o)).map(I)}},D=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),O=tinymce.util.Tools.resolve("tinymce.util.URI"),N=function(e){return e.length>0},L=function(e){return function(t){return t.options.get(e)}},P=function(e){var t=e.options.register;t("image_dimensions",{processor:"boolean",default:!0}),t("image_advtab",{processor:"boolean",default:!1}),t("image_uploadtab",{processor:"boolean",default:!0}),t("image_prepend_url",{processor:"string",default:""}),t("image_class_list",{processor:"object[]"}),t("image_description",{processor:"boolean",default:!0}),t("image_title",{processor:"boolean",default:!1}),t("image_caption",{processor:"boolean",default:!1}),t("image_list",{processor:function(e){var t=!1===e||c(e)||function(e,t){if(h(e)){for(var o=0,n=e.length;o0&&/^[0-9]+$/.test(e)&&(e+="px"),e},Q=function(e){return"IMG"===e.nodeName&&(e.hasAttribute("data-mce-object")||e.hasAttribute("data-mce-placeholder"))},q=function(e,t){var o=e.options.get;return O.isDomSafe(t,"img",{allow_html_data_urls:o("allow_html_data_urls"),allow_script_urls:o("allow_script_urls"),allow_svg_data_urls:o("allow_svg_data_urls")})},K=D.DOM,$=function(e){return e.style.marginLeft&&e.style.marginRight&&e.style.marginLeft===e.style.marginRight?X(e.style.marginLeft):""},ee=function(e){return e.style.marginTop&&e.style.marginBottom&&e.style.marginTop===e.style.marginBottom?X(e.style.marginTop):""},te=function(e){return e.style.borderWidth?X(e.style.borderWidth):""},oe=function(e,t){var o;return e.hasAttribute(t)&&null!==(o=e.getAttribute(t))&&void 0!==o?o:""},ne=function(e){return null!==e.parentNode&&"FIGURE"===e.parentNode.nodeName},re=function(e,t,o){""===o||null===o?e.removeAttribute(t):e.setAttribute(t,o)},ie=function(e){ne(e)?function(e){var t=e.parentNode;p(t)&&(K.insertAfter(e,t),K.remove(t))}(e):function(e){var t=K.create("figure",{class:"image"});K.insertAfter(t,e),t.appendChild(e),t.appendChild(K.create("figcaption",{contentEditable:"true"},"Caption")),t.contentEditable="false"}(e)},ae=function(e,t){var o=e.getAttribute("style"),n=t(null!==o?o:"");n.length>0?(e.setAttribute("style",n),e.setAttribute("data-mce-style",n)):e.removeAttribute("style")},se=function(e,t){return function(e,o,n){var r=e.style;r[o]?(r[o]=J(n),ae(e,t)):re(e,o,n)}},le=function(e,t){return e.style[t]?X(e.style[t]):oe(e,t)},ce=function(e,t){var o=J(t);e.style.marginLeft=o,e.style.marginRight=o},de=function(e,t){var o=J(t);e.style.marginTop=o,e.style.marginBottom=o},ue=function(e,t){var o=J(t);e.style.borderWidth=o},he=function(e,t){e.style.borderStyle=t},me=function(e){var t;return null!==(t=e.style.borderStyle)&&void 0!==t?t:""},ge=function(e){return p(e)&&"FIGURE"===e.nodeName},pe=function(e){return 0===K.getAttrib(e,"alt").length&&"presentation"===K.getAttrib(e,"role")},fe=function(e){return pe(e)?"":oe(e,"alt")},ve=function(e,t){var o,n=document.createElement("img");return re(n,"style",t.style),($(n)||""!==t.hspace)&&ce(n,t.hspace),(ee(n)||""!==t.vspace)&&de(n,t.vspace),(te(n)||""!==t.border)&&ue(n,t.border),(me(n)||""!==t.borderStyle)&&he(n,t.borderStyle),e(null!==(o=n.getAttribute("style"))&&void 0!==o?o:"")},be=function(e,t){return{src:oe(t,"src"),alt:fe(t),title:oe(t,"title"),width:le(t,"width"),height:le(t,"height"),class:oe(t,"class"),style:e(oe(t,"style")),caption:ne(t),hspace:$(t),vspace:ee(t),border:te(t),borderStyle:me(t),isDecorative:pe(t)}},xe=function(e,t,o,n,r){o[n]!==t[n]&&r(e,n,String(o[n]))},ye=function(e,t,o){if(o){K.setAttrib(e,"role","presentation");var n=E.fromDom(e);T(n,"alt","")}else{if(m(t)){var r=E.fromDom(e);a="alt",r.dom.removeAttribute(a)}else{var i=E.fromDom(e);T(i,"alt",t)}"presentation"===K.getAttrib(e,"role")&&K.setAttrib(e,"role","")}var a},we=function(e,t){return function(o,n,r){e(o,r),ae(o,t)}},_e=function(e,t,o){var n=be(e,o);xe(o,n,t,"caption",(function(e,t,o){return ie(e)})),xe(o,n,t,"src",re),xe(o,n,t,"title",re),xe(o,n,t,"width",se(0,e)),xe(o,n,t,"height",se(0,e)),xe(o,n,t,"class",re),xe(o,n,t,"style",we((function(e,t){return re(e,"style",t)}),e)),xe(o,n,t,"hspace",we(ce,e)),xe(o,n,t,"vspace",we(de,e)),xe(o,n,t,"border",we(ue,e)),xe(o,n,t,"borderStyle",we(he,e)),function(e,t,o){o.alt===t.alt&&o.isDecorative===t.isDecorative||ye(e,o.alt,o.isDecorative)}(o,n,t)},Ce=function(e,t){var o=function(e){if(e.margin){var t=String(e.margin).split(" ");switch(t.length){case 1:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[0],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[0];break;case 2:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[1];break;case 3:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[1];break;case 4:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[3]}delete e.margin}return e}(e.dom.styles.parse(t)),n=e.dom.styles.parse(e.dom.styles.serialize(o));return e.dom.styles.serialize(n)},Se=function(e){var t=e.selection.getNode(),o=e.dom.getParent(t,"figure.image");return o?e.dom.select("img",o)[0]:t&&("IMG"!==t.nodeName||Q(t))?null:t},ke=function(e,t){var o,n=e.dom,r=function(e,t){var o,n={};return _(e,t,(o=n,function(e,t){o[t]=e}),b),n}(e.schema.getTextBlockElements(),(function(t,o){return!e.schema.isValidChild(o,"figure")})),i=n.getParent(t.parentNode,(function(e){return t=r,o=e.nodeName,C(t,o)&&void 0!==t[o]&&null!==t[o];var t,o}),e.getBody());return i&&null!==(o=n.split(i,t))&&void 0!==o?o:t},Ae=function(e,o){var n=function(e,o){var n=document.createElement("img");if(_e(e,t(t({},o),{},{caption:!1}),n),ye(n,o.alt,o.isDecorative),o.caption){var r=K.create("figure",{class:"image"});return r.appendChild(n),r.appendChild(K.create("figcaption",{contentEditable:"true"},"Caption")),r.contentEditable="false",r}return n}((function(t){return Ce(e,t)}),o);e.dom.setAttrib(n,"data-mce-id","__mcenew"),e.focus(),e.selection.setContent(n.outerHTML);var r=e.dom.select('*[data-mce-id="__mcenew"]')[0];if(e.dom.setAttrib(r,"data-mce-id",null),ge(r)){var i=ke(e,r);e.selection.select(i)}else e.selection.select(r)},Me=function(e,t){var o=Se(e);if(o)if(_e((function(t){return Ce(e,t)}),t,o),function(e,t){e.dom.setAttrib(t,"src",t.getAttribute("src"))}(e,o),ge(o.parentNode)){e.dom.setStyle(o,"float","");var n=o.parentNode;ke(e,n),e.selection.select(o.parentNode)}else e.selection.select(o),function(e,t,o){var n=function(){o.onload=o.onerror=null,e.selection&&(e.selection.select(o),e.nodeChanged())};o.onload=function(){t.width||t.height||!R(e)||e.dom.setAttribs(o,{width:String(o.clientWidth),height:String(o.clientHeight)}),n()},o.onerror=n}(e,t,o)},Te=function(e,o){var n=Se(e);if(n){var r=t(t({},be((function(t){return Ce(e,t)}),n)),o),i=function(e,o){var n=o.src;return t(t({},o),{},{src:q(e,n)?n:""})}(e,r);r.src?Me(e,i):function(e,t){if(t){var o=e.dom.is(t.parentNode,"figure.image")?t.parentNode:t;e.dom.remove(o),e.focus(),e.nodeChanged(),e.dom.isEmpty(e.getBody())&&(e.setContent(""),e.selection.setCursorLocation())}}(e,n)}else o.src&&Ae(e,t(t({},{src:"",alt:"",title:"",width:"",height:"",class:"",style:"",caption:!1,hspace:"",vspace:"",border:"",borderStyle:"",isDecorative:!1}),o))},Ie=(M=function(e,t){return u(e)&&u(t)?Ie(e,t):t},function(){if(0===arguments.length)throw new Error("Can't merge zero objects");for(var e={},t=0;t0&&void 0!==arguments[0]?arguments[0]:Oe;return function(t){return t?x.from(t).map((function(t){return Ne(t,e)})):x.none()}},Pe=function(e,t){return function(e,t){for(var o=0;o0}));return o.then((function(e){return{image:l,imageList:e,classList:n,hasAdvTab:r,hasUploadTab:i,hasUploadUrl:a,hasUploadHandler:s,hasDescription:d,hasImageTitle:u,hasDimensions:h,hasImageCaption:m,prependURL:b,hasAccessibilityOptions:g,automaticUploads:v}}))},He=function(e){var o,n=tinymce.activeEditor.options.get("cc_config").has_image_resize,r={name:"upload_max_filesize_caption",type:"collection",label:tinymce.activeEditor.options.get("cc_config").upload_max_filesize_caption},i=e.imageList.map((function(e){return{name:"images",type:"listbox",label:"Image list",items:e}})),a={name:"alt",type:"input",label:"Alternative description",enabled:!(e.hasAccessibilityOptions&&e.image.isDecorative)},s={name:"resize",type:"listbox",label:"画像サイズ",items:tinymce.activeEditor.options.get("cc_config").resized_image_size_items},l=e.classList.map((function(e){return{name:"classes",type:"listbox",label:"Class",items:e}}));return k([[{name:"src",type:"urlinput",filetype:"image",label:"Source",picker_text:"Browse files"}],[r],i.toArray(),e.hasAccessibilityOptions&&e.hasDescription?[{type:"label",label:"Accessibility",items:[{name:"isDecorative",type:"checkbox",label:"Image is decorative"}]}]:[],e.hasDescription?[a]:[],e.hasImageTitle?[{name:"title",type:"input",label:"Image title"}]:[],n?[s]:[],[{name:"image_resize_caption",type:"collection",label:"※ 画像アップロード時のみ、画像サイズを指定できます。"}],e.hasDimensions?[{name:"dimensions",type:"sizeinput"}]:[],[t(t({},(o=e.classList.isSome()&&e.hasImageCaption,o?{type:"grid",columns:2}:{type:"panel"})),{},{items:k([l.toArray(),e.hasImageCaption?[{type:"label",label:"Caption",items:[{type:"checkbox",name:"caption",label:"Show caption"}]}]:[]])})]])},Ue=function(e){return{title:"General",name:"general",items:He(e)}},Ve=He,Ze=function(e){return{title:"Upload",name:"upload",items:[{type:"dropzone",name:"fileinput"}]}},We=function(e){return{src:{value:e.src,meta:{}},images:e.src,alt:e.alt,title:e.title,dimensions:{width:e.width,height:e.height},classes:e.class,caption:e.caption,style:e.style,vspace:e.vspace,border:e.border,hspace:e.hspace,borderstyle:e.borderStyle,fileinput:[],isDecorative:e.isDecorative,resize:tinymce.activeEditor.options.get("cc_config").resized_image_size_initial}},Ye=function(e,t){return{src:e.src.value,alt:null!==e.alt&&0!==e.alt.length||!t?e.alt:null,title:e.title,width:e.dimensions.width,height:e.dimensions.height,class:e.classes,style:e.style,caption:e.caption,hspace:e.hspace,vspace:e.vspace,border:e.border,borderStyle:e.borderstyle,isDecorative:e.isDecorative,resize:e.resize}},Ge=function(e,t){var o=t.getData();(function(e,t){return/^(?:[a-zA-Z]+:)?\/\//.test(t)?x.none():e.prependURL.bind((function(e){return t.substring(0,e.length)!==e?x.some(e+t):x.none()}))})(e,o.src.value).each((function(e){t.setData({src:{value:e,meta:o.src.meta}})}))},Xe=function(e,t){var o=t.getData(),n=o.src.meta;if(void 0!==n){var r=Ie({},o);!function(e,t,o){e.hasDescription&&c(o.alt)&&(t.alt=o.alt),e.hasAccessibilityOptions&&(t.isDecorative=o.isDecorative||t.isDecorative||!1),e.hasImageTitle&&c(o.title)&&(t.title=o.title),e.hasDimensions&&(c(o.width)&&(t.dimensions.width=o.width),c(o.height)&&(t.dimensions.height=o.height)),c(o.class)&&ze(e.classList,o.class).each((function(e){t.classes=e.value})),e.hasImageCaption&&g(o.caption)&&(t.caption=o.caption),e.hasAdvTab&&(c(o.style)&&(t.style=o.style),c(o.vspace)&&(t.vspace=o.vspace),c(o.border)&&(t.border=o.border),c(o.hspace)&&(t.hspace=o.hspace),c(o.borderstyle)&&(t.borderstyle=o.borderstyle))}(e,r,n),t.setData(r)}},Je=function(e,t,o,n){Ge(t,n),Xe(t,n),function(e,t,o,n){var r=n.getData(),i=r.src.value,a=r.src.meta||{},s=tinymce.activeEditor.options.get("cc_config").has_image_resize;a.width||a.height||!t.hasDimensions||(N(i)?e.imageSize(i).then((function(e){o.open&&(s||n.setData({dimensions:e}))})).catch((function(e){return console.error(e)})):n.setData({dimensions:{width:"",height:""}}))}(e,t,o,n),function(e,t,o){var n=o.getData(),r=ze(e.imageList,n.src.value);t.prevImage=r,o.setData({images:r.map((function(e){return e.value})).getOr("")})}(t,o,n)},Qe=function(e,t,o,n){var r=n.getData();n.block("Uploading image"),A(r.fileinput).fold((function(){n.unblock()}),(function(r){var i,a=URL.createObjectURL(r),s=function(){n.unblock(),URL.revokeObjectURL(a)},l=function(r){n.setData({src:{value:r,meta:{}}}),n.showTab("general"),Je(e,t,o,n),n.focus("src")};(i=r,new Promise((function(e,t){var o=new FileReader;o.onload=function(){e(o.result)},o.onerror=function(){var e;t(null===(e=o.error)||void 0===e?void 0:e.message)},o.readAsDataURL(i)}))).then((function(o){var i=e.createBlobCache(r,a,o);t.automaticUploads?e.uploadImage(i).then((function(e){l(e.url),s()})).catch((function(t){s(),e.alertErr(t,(function(){n.focus("fileinput")}))})):(e.addToBlobCache(i),l(i.blobUri()),n.unblock())}))}))},qe=function(e,t,o){return function(n,r){"src"===r.name?Je(e,t,o,n):"images"===r.name?function(e,t,o,n){var r=n.getData(),i=ze(t.imageList,r.images);i.each((function(e){var t=""===r.alt||o.prevImage.map((function(e){return e.text===r.alt})).getOr(!1);t?""===e.value?n.setData({src:e,alt:o.prevAlt}):n.setData({src:e,alt:e.text}):n.setData({src:e})})),o.prevImage=i,Je(e,t,o,n)}(e,t,o,n):"alt"===r.name?o.prevAlt=n.getData().alt:"fileinput"===r.name?Qe(e,t,o,n):"isDecorative"===r.name&&n.setEnabled("alt",!n.getData().isDecorative)}},Ke=function(e){return function(){e.open=!1}},$e=function(e){return e.hasAdvTab||e.hasUploadTab&&(e.hasUploadUrl||e.hasUploadHandler)?{type:"tabpanel",tabs:k([[Ue(e)],e.hasAdvTab?[Be(e)]:[],e.hasUploadTab&&(e.hasUploadUrl||e.hasUploadHandler)?[Ze(e)]:[]])}:{type:"panel",items:Ve(e)}},et=function(e,o,n){return function(r){var i=Ie(We(o.image),r.getData()),a=t(t({},i),{},{style:ve(n.normalizeCss,Ye(i,!1))});e.execCommand("mceUpdateImage",!1,Ye(a,o.hasAccessibilityOptions)),e.editorUpload.uploadImagesAuto(),r.close()}},tt=function(e){return function(t){return q(e,t)?function(e){return new Promise((function(t){var o=document.createElement("img"),n=function(e){o.parentNode&&o.parentNode.removeChild(o),t(e)};o.addEventListener("load",(function(){var e={width:G(o.width,o.clientWidth),height:G(o.height,o.clientHeight)};n(Promise.resolve(e))})),o.addEventListener("error",(function(){n(Promise.reject("Failed to get image dimensions for: ".concat(e)))}));var r=o.style;r.visibility="hidden",r.position="fixed",r.bottom=r.left="0px",r.width=r.height="auto",document.body.appendChild(o),o.src=e}))}(e.documentBaseURI.toAbsolute(t)).then((function(e){return{width:String(e.width),height:String(e.height)}})):Promise.resolve({width:"",height:""})}},ot=function(e){return function(t,o,n){var r;return e.editorUpload.blobCache.create({blob:t,blobUri:o,name:null===(r=t.name)||void 0===r?void 0:r.replace(/\.[^\.]+$/,""),filename:t.name,base64:n.split(",")[1]})}},nt=function(e){return function(t){e.editorUpload.blobCache.add(t)}},rt=function(e){return function(t,o){e.windowManager.alert(t,o)}},it=function(e){return function(t){return Ce(e,t)}},at=function(e){return function(t){return e.dom.parseStyle(t)}},st=function(e){return function(t,o){return e.dom.serializeStyle(t,o)}},lt=function(e){return function(t){return Ee(e).upload([t],!1).then((function(e){var t;return 0===e.length?Promise.reject("Failed to upload image"):!1===e[0].status?Promise.reject(null===(t=e[0].error)||void 0===t?void 0:t.message):e[0]}))}},ct=function(e){var t={imageSize:tt(e),addToBlobCache:nt(e),createBlobCache:ot(e),alertErr:rt(e),normalizeCss:it(e),parseStyle:at(e),serializeStyle:st(e),uploadImage:lt(e)};return{open:function(){Fe(e).then((function(o){var n=function(e){return{prevImage:ze(e.imageList,e.image.src),prevAlt:e.image.alt,open:!0}}(o);return{title:"Insert/Edit Image",size:"normal",body:$e(o),buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:We(o.image),onSubmit:et(e,o,t),onChange:qe(t,o,n),onClose:Ke(n)}})).then(e.windowManager.open)}}},dt=function(e){var t=e.attr("class");return p(t)&&/\bimage\b/.test(t)},ut=function(e){return function(t){for(var o=t.length,n=function(t){t.attr("contenteditable",e?"true":null)};o--;){var r=t[o];dt(r)&&(r.attr("contenteditable",e?"false":null),De.each(r.getAll("figcaption"),n))}}},ht=function(e){return function(t){var o=function(){t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",o),o(),function(){e.off("NodeChange",o)}}};o.add("image",(function(e){P(e),function(e){e.on("PreInit",(function(){e.parser.addNodeFilter("figure",ut(!0)),e.serializer.addNodeFilter("figure",ut(!1))}))}(e),function(e){e.ui.registry.addToggleButton("image",{icon:"image",tooltip:"Insert/edit image",onAction:ct(e).open,onSetup:function(t){t.setActive(p(Se(e)));var o=e.selection.selectorChangedWithUnbind("img:not([data-mce-object]):not([data-mce-placeholder]),figure.image",t.setActive).unbind,n=ht(e)(t);return function(){o(),n()}}}),e.ui.registry.addMenuItem("image",{icon:"image",text:"Image...",onAction:ct(e).open,onSetup:ht(e)}),e.ui.registry.addContextMenu("image",{update:function(t){return e.selection.isEditable()&&(ge(t)||"IMG"===t.nodeName&&!Q(t))?["image"]:[]}})}(e),function(e){e.addCommand("mceImage",ct(e).open),e.addCommand("mceUpdateImage",(function(t,o){e.undoManager.transact((function(){return Te(e,o)}))}))}(e)}))}()},9289(){tinymce.PluginManager.add("pdf",(function(e,t){function o(t){tinymce.activeEditor.windowManager.open({title:"PDFアップロード",body:{type:"panel",items:[{type:"alertbanner",level:"info",text:"PDFからサムネイル画像を自動作成します。",icon:"info"},{type:"urlinput",name:"pdf",filetype:"file",label:"PDF"},{type:"collection",name:"upload_max_filesize_caption",label:e.options.get("cc_config").upload_max_filesize_caption},{type:"listbox",name:"width_of_pdf_thumbnails",label:"サムネイルの大きさ",disabled:!1,items:e.options.get("cc_config").width_of_pdf_thumbnails_items},{type:"listbox",name:"number_of_pdf_thumbnails",label:"サムネイルの数",disabled:!1,items:e.options.get("cc_config").number_of_pdf_thumbnails_items},{type:"input",name:"pdf_password",inputMode:"text",label:"PDFパスワード",placeholder:"",disabled:!1,maximized:!1},{type:"collection",name:"pdf_password_caption",label:"※ パスワード付PDFの場合、入力してください。"}]},initialData:{width_of_pdf_thumbnails:e.options.get("cc_config").width_of_pdf_thumbnails_initial,number_of_pdf_thumbnails:e.options.get("cc_config").number_of_pdf_thumbnails_initial},buttons:[{type:"cancel",text:"Close"},{type:"submit",text:"Save",primary:!0}],onSubmit:function(t){xhr=new XMLHttpRequest,xhr.withCredentials=!1,xhr.open("POST",tinymce.activeEditor.getParam("document_base_url")+"/upload"),xhr.onload=function(){var o;xhr.status<200||xhr.status>=300?console.error("HTTP Error: "+xhr.status):(void 0!==(o=JSON.parse(xhr.responseText)).link_text&&e.insertContent(o.link_text),document.getElementById("cc-pdf-upload-"+i).value="",t.close())};var o=document.getElementsByName("csrf-token"),n=document.getElementsByName("_page_id"),r=t.getData(),i=e.options.get("cc_config").frame_id;formData=new FormData,formData.append("_token",o[0].content),formData.append("page_id",n[0].content),formData.append("plugin_name",e.options.get("cc_config").plugin_name),formData.append("pdf",document.getElementById("cc-pdf-upload-"+i).files[0]),formData.append("pdf_password",r.pdf_password),formData.append("width_of_pdf_thumbnails",r.width_of_pdf_thumbnails),formData.append("number_of_pdf_thumbnails",r.number_of_pdf_thumbnails),xhr.send(formData)}})}e.ui.registry.addIcon("pdf",'\x3c!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--\x3e'),e.ui.registry.addButton("pdf",{icon:"pdf",tooltip:"PDFアップロード",onAction:o,onPostRender:function(){var t=this;e.on("NodeChange",(function(o){var n=jQuery(e.selection.getNode()).hasClass("plugin");t.active(n)})),e.on("DblClick",(function(e){"plugin"==e.target.className&&o(e.toElement.innerText)}))}})}))},4665(){tinymce.PluginManager.add("translate",(function(e,t){function o(t){if(String(t).match(/^(&|#)/))void 0!==(o=t.match(/^(&|#)(\w+)\((.*)\)([\s\S]*)?/))[4]&&o[4].match(/;$/)&&(o[4]=o[4].replace(/;$/g,""));else var o=new Array("","","","","");tinymce.activeEditor.windowManager.open({title:"翻訳",width:600,height:250,body:{type:"panel",items:[{type:"textarea",name:"inline_text",label:"",maximized:!0},{type:"selectbox",name:"target_language",label:"翻訳後の言語",size:1,items:[{value:"en",text:"英語"},{value:"pt",text:"ポルトガル語"},{value:"vi",text:"ベトナム語"},{value:"fr",text:"フランス語"},{value:"de",text:"ドイツ語"},{value:"es",text:"スペイン語"},{value:"zh",text:"中国語 (簡体字)"},{value:"zh-TW",text:"中国語 (繁体字)"},{value:"ko",text:"韓国語"},{value:"tl",text:"タガログ語"}]}]},buttons:[{type:"cancel",text:"Close"},{type:"submit",text:"翻訳",primary:!0}],initialData:{inline_text:e.selection.getContent()},onSubmit:function(t){var o=t.getData();xhr=new XMLHttpRequest,xhr.withCredentials=!1,xhr.open("POST",tinymce.activeEditor.getParam("document_base_url")+"/api/translate/post"),xhr.onload=function(){var n;if(xhr.status<200||xhr.status>=300)console.error("HTTP Error: "+xhr.status);else{for(var r in(n=JSON.parse(xhr.responseText)).return_texts)o.inline_text?e.insertContent("

"+o.inline_text+"
"+n.return_texts[r]+"

"):e.insertContent("

"+n.return_texts[r]+"

");t.close()}};var n=document.getElementsByName("csrf-token");formData=new FormData,formData.append("_token",n[0].content),formData.append("inline_text",o.inline_text),formData.append("target_language",o.target_language),xhr.send(formData)}}),textarea=jQuery(".tox-textarea")[0],textarea.setAttribute("style","min-height: 220px;")}e.ui.registry.addIcon("translate",'\x3c!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--\x3e'),e.ui.registry.addButton("translate",{icon:"translate",tooltip:"翻訳",onAction:o,onPostRender:function(){var t=this;e.on("NodeChange",(function(o){var n=jQuery(e.selection.getNode()).hasClass("plugin");t.active(n)})),e.on("DblClick",(function(e){"plugin"==e.target.className&&o(e.toElement.innerText)}))}})}))},7526(e,t){"use strict";t.byteLength=function(e){var t=s(e),o=t[0],n=t[1];return 3*(o+n)/4-n},t.toByteArray=function(e){var t,o,i=s(e),a=i[0],l=i[1],c=new r(function(e,t,o){return 3*(t+o)/4-o}(0,a,l)),d=0,u=l>0?a-4:a;for(o=0;o>16&255,c[d++]=t>>8&255,c[d++]=255&t;2===l&&(t=n[e.charCodeAt(o)]<<2|n[e.charCodeAt(o+1)]>>4,c[d++]=255&t);1===l&&(t=n[e.charCodeAt(o)]<<10|n[e.charCodeAt(o+1)]<<4|n[e.charCodeAt(o+2)]>>2,c[d++]=t>>8&255,c[d++]=255&t);return c},t.fromByteArray=function(e){for(var t,n=e.length,r=n%3,i=[],a=16383,s=0,c=n-r;sc?c:s+a));1===r?(t=e[n-1],i.push(o[t>>2]+o[t<<4&63]+"==")):2===r&&(t=(e[n-2]<<8)+e[n-1],i.push(o[t>>10]+o[t>>4&63]+o[t<<2&63]+"="));return i.join("")};for(var o=[],n=[],r="undefined"!=typeof Uint8Array?Uint8Array:Array,i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",a=0;a<64;++a)o[a]=i[a],n[i.charCodeAt(a)]=a;function s(e){var t=e.length;if(t%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var o=e.indexOf("=");return-1===o&&(o=t),[o,o===t?0:4-o%4]}function l(e,t,n){for(var r,i,a=[],s=t;s>18&63]+o[i>>12&63]+o[i>>6&63]+o[63&i]);return a.join("")}n["-".charCodeAt(0)]=62,n["_".charCodeAt(0)]=63},8287(e,t,o){"use strict";var n=o(7526),r=o(251),i=o(4634);function a(){return l.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function s(e,t){if(a()=a())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+a().toString(16)+" bytes");return 0|e}function g(e,t){if(l.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var o=e.length;if(0===o)return 0;for(var n=!1;;)switch(t){case"ascii":case"latin1":case"binary":return o;case"utf8":case"utf-8":case void 0:return H(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*o;case"hex":return o>>>1;case"base64":return U(e).length;default:if(n)return H(e).length;t=(""+t).toLowerCase(),n=!0}}function p(e,t,o){var n=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===o||o>this.length)&&(o=this.length),o<=0)return"";if((o>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return E(this,t,o);case"utf8":case"utf-8":return A(this,t,o);case"ascii":return T(this,t,o);case"latin1":case"binary":return I(this,t,o);case"base64":return k(this,t,o);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return D(this,t,o);default:if(n)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),n=!0}}function f(e,t,o){var n=e[t];e[t]=e[o],e[o]=n}function v(e,t,o,n,r){if(0===e.length)return-1;if("string"==typeof o?(n=o,o=0):o>2147483647?o=2147483647:o<-2147483648&&(o=-2147483648),o=+o,isNaN(o)&&(o=r?0:e.length-1),o<0&&(o=e.length+o),o>=e.length){if(r)return-1;o=e.length-1}else if(o<0){if(!r)return-1;o=0}if("string"==typeof t&&(t=l.from(t,n)),l.isBuffer(t))return 0===t.length?-1:b(e,t,o,n,r);if("number"==typeof t)return t&=255,l.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?r?Uint8Array.prototype.indexOf.call(e,t,o):Uint8Array.prototype.lastIndexOf.call(e,t,o):b(e,[t],o,n,r);throw new TypeError("val must be string, number or Buffer")}function b(e,t,o,n,r){var i,a=1,s=e.length,l=t.length;if(void 0!==n&&("ucs2"===(n=String(n).toLowerCase())||"ucs-2"===n||"utf16le"===n||"utf-16le"===n)){if(e.length<2||t.length<2)return-1;a=2,s/=2,l/=2,o/=2}function c(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}if(r){var d=-1;for(i=o;is&&(o=s-l),i=o;i>=0;i--){for(var u=!0,h=0;hr&&(n=r):n=r;var i=t.length;if(i%2!=0)throw new TypeError("Invalid hex string");n>i/2&&(n=i/2);for(var a=0;a>8,r=o%256,i.push(r),i.push(n);return i}(t,e.length-o),e,o,n)}function k(e,t,o){return 0===t&&o===e.length?n.fromByteArray(e):n.fromByteArray(e.slice(t,o))}function A(e,t,o){o=Math.min(e.length,o);for(var n=[],r=t;r239?4:c>223?3:c>191?2:1;if(r+u<=o)switch(u){case 1:c<128&&(d=c);break;case 2:128==(192&(i=e[r+1]))&&(l=(31&c)<<6|63&i)>127&&(d=l);break;case 3:i=e[r+1],a=e[r+2],128==(192&i)&&128==(192&a)&&(l=(15&c)<<12|(63&i)<<6|63&a)>2047&&(l<55296||l>57343)&&(d=l);break;case 4:i=e[r+1],a=e[r+2],s=e[r+3],128==(192&i)&&128==(192&a)&&128==(192&s)&&(l=(15&c)<<18|(63&i)<<12|(63&a)<<6|63&s)>65535&&l<1114112&&(d=l)}null===d?(d=65533,u=1):d>65535&&(d-=65536,n.push(d>>>10&1023|55296),d=56320|1023&d),n.push(d),r+=u}return function(e){var t=e.length;if(t<=M)return String.fromCharCode.apply(String,e);var o="",n=0;for(;n0&&(e=this.toString("hex",0,o).match(/.{2}/g).join(" "),this.length>o&&(e+=" ... ")),""},l.prototype.compare=function(e,t,o,n,r){if(!l.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===o&&(o=e?e.length:0),void 0===n&&(n=0),void 0===r&&(r=this.length),t<0||o>e.length||n<0||r>this.length)throw new RangeError("out of range index");if(n>=r&&t>=o)return 0;if(n>=r)return-1;if(t>=o)return 1;if(this===e)return 0;for(var i=(r>>>=0)-(n>>>=0),a=(o>>>=0)-(t>>>=0),s=Math.min(i,a),c=this.slice(n,r),d=e.slice(t,o),u=0;ur)&&(o=r),e.length>0&&(o<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");n||(n="utf8");for(var i=!1;;)switch(n){case"hex":return x(this,e,t,o);case"utf8":case"utf-8":return y(this,e,t,o);case"ascii":return w(this,e,t,o);case"latin1":case"binary":return _(this,e,t,o);case"base64":return C(this,e,t,o);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return S(this,e,t,o);default:if(i)throw new TypeError("Unknown encoding: "+n);n=(""+n).toLowerCase(),i=!0}},l.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var M=4096;function T(e,t,o){var n="";o=Math.min(e.length,o);for(var r=t;rn)&&(o=n);for(var r="",i=t;io)throw new RangeError("Trying to access beyond buffer length")}function N(e,t,o,n,r,i){if(!l.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>r||te.length)throw new RangeError("Index out of range")}function L(e,t,o,n){t<0&&(t=65535+t+1);for(var r=0,i=Math.min(e.length-o,2);r>>8*(n?r:1-r)}function P(e,t,o,n){t<0&&(t=4294967295+t+1);for(var r=0,i=Math.min(e.length-o,4);r>>8*(n?r:3-r)&255}function R(e,t,o,n,r,i){if(o+n>e.length)throw new RangeError("Index out of range");if(o<0)throw new RangeError("Index out of range")}function j(e,t,o,n,i){return i||R(e,0,o,4),r.write(e,t,o,n,23,4),o+4}function z(e,t,o,n,i){return i||R(e,0,o,8),r.write(e,t,o,n,52,8),o+8}l.prototype.slice=function(e,t){var o,n=this.length;if((e=~~e)<0?(e+=n)<0&&(e=0):e>n&&(e=n),(t=void 0===t?n:~~t)<0?(t+=n)<0&&(t=0):t>n&&(t=n),t0&&(r*=256);)n+=this[e+--t]*r;return n},l.prototype.readUInt8=function(e,t){return t||O(e,1,this.length),this[e]},l.prototype.readUInt16LE=function(e,t){return t||O(e,2,this.length),this[e]|this[e+1]<<8},l.prototype.readUInt16BE=function(e,t){return t||O(e,2,this.length),this[e]<<8|this[e+1]},l.prototype.readUInt32LE=function(e,t){return t||O(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},l.prototype.readUInt32BE=function(e,t){return t||O(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},l.prototype.readIntLE=function(e,t,o){e|=0,t|=0,o||O(e,t,this.length);for(var n=this[e],r=1,i=0;++i=(r*=128)&&(n-=Math.pow(2,8*t)),n},l.prototype.readIntBE=function(e,t,o){e|=0,t|=0,o||O(e,t,this.length);for(var n=t,r=1,i=this[e+--n];n>0&&(r*=256);)i+=this[e+--n]*r;return i>=(r*=128)&&(i-=Math.pow(2,8*t)),i},l.prototype.readInt8=function(e,t){return t||O(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},l.prototype.readInt16LE=function(e,t){t||O(e,2,this.length);var o=this[e]|this[e+1]<<8;return 32768&o?4294901760|o:o},l.prototype.readInt16BE=function(e,t){t||O(e,2,this.length);var o=this[e+1]|this[e]<<8;return 32768&o?4294901760|o:o},l.prototype.readInt32LE=function(e,t){return t||O(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},l.prototype.readInt32BE=function(e,t){return t||O(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},l.prototype.readFloatLE=function(e,t){return t||O(e,4,this.length),r.read(this,e,!0,23,4)},l.prototype.readFloatBE=function(e,t){return t||O(e,4,this.length),r.read(this,e,!1,23,4)},l.prototype.readDoubleLE=function(e,t){return t||O(e,8,this.length),r.read(this,e,!0,52,8)},l.prototype.readDoubleBE=function(e,t){return t||O(e,8,this.length),r.read(this,e,!1,52,8)},l.prototype.writeUIntLE=function(e,t,o,n){(e=+e,t|=0,o|=0,n)||N(this,e,t,o,Math.pow(2,8*o)-1,0);var r=1,i=0;for(this[t]=255&e;++i=0&&(i*=256);)this[t+r]=e/i&255;return t+o},l.prototype.writeUInt8=function(e,t,o){return e=+e,t|=0,o||N(this,e,t,1,255,0),l.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},l.prototype.writeUInt16LE=function(e,t,o){return e=+e,t|=0,o||N(this,e,t,2,65535,0),l.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):L(this,e,t,!0),t+2},l.prototype.writeUInt16BE=function(e,t,o){return e=+e,t|=0,o||N(this,e,t,2,65535,0),l.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):L(this,e,t,!1),t+2},l.prototype.writeUInt32LE=function(e,t,o){return e=+e,t|=0,o||N(this,e,t,4,4294967295,0),l.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):P(this,e,t,!0),t+4},l.prototype.writeUInt32BE=function(e,t,o){return e=+e,t|=0,o||N(this,e,t,4,4294967295,0),l.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):P(this,e,t,!1),t+4},l.prototype.writeIntLE=function(e,t,o,n){if(e=+e,t|=0,!n){var r=Math.pow(2,8*o-1);N(this,e,t,o,r-1,-r)}var i=0,a=1,s=0;for(this[t]=255&e;++i=0&&(a*=256);)e<0&&0===s&&0!==this[t+i+1]&&(s=1),this[t+i]=(e/a|0)-s&255;return t+o},l.prototype.writeInt8=function(e,t,o){return e=+e,t|=0,o||N(this,e,t,1,127,-128),l.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},l.prototype.writeInt16LE=function(e,t,o){return e=+e,t|=0,o||N(this,e,t,2,32767,-32768),l.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):L(this,e,t,!0),t+2},l.prototype.writeInt16BE=function(e,t,o){return e=+e,t|=0,o||N(this,e,t,2,32767,-32768),l.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):L(this,e,t,!1),t+2},l.prototype.writeInt32LE=function(e,t,o){return e=+e,t|=0,o||N(this,e,t,4,2147483647,-2147483648),l.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):P(this,e,t,!0),t+4},l.prototype.writeInt32BE=function(e,t,o){return e=+e,t|=0,o||N(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),l.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):P(this,e,t,!1),t+4},l.prototype.writeFloatLE=function(e,t,o){return j(this,e,t,!0,o)},l.prototype.writeFloatBE=function(e,t,o){return j(this,e,t,!1,o)},l.prototype.writeDoubleLE=function(e,t,o){return z(this,e,t,!0,o)},l.prototype.writeDoubleBE=function(e,t,o){return z(this,e,t,!1,o)},l.prototype.copy=function(e,t,o,n){if(o||(o=0),n||0===n||(n=this.length),t>=e.length&&(t=e.length),t||(t=0),n>0&&n=this.length)throw new RangeError("sourceStart out of bounds");if(n<0)throw new RangeError("sourceEnd out of bounds");n>this.length&&(n=this.length),e.length-t=0;--r)e[r+t]=this[r+o];else if(i<1e3||!l.TYPED_ARRAY_SUPPORT)for(r=0;r>>=0,o=void 0===o?this.length:o>>>0,e||(e=0),"number"==typeof e)for(i=t;i55295&&o<57344){if(!r){if(o>56319){(t-=3)>-1&&i.push(239,191,189);continue}if(a+1===n){(t-=3)>-1&&i.push(239,191,189);continue}r=o;continue}if(o<56320){(t-=3)>-1&&i.push(239,191,189),r=o;continue}o=65536+(r-55296<<10|o-56320)}else r&&(t-=3)>-1&&i.push(239,191,189);if(r=null,o<128){if((t-=1)<0)break;i.push(o)}else if(o<2048){if((t-=2)<0)break;i.push(o>>6|192,63&o|128)}else if(o<65536){if((t-=3)<0)break;i.push(o>>12|224,o>>6&63|128,63&o|128)}else{if(!(o<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;i.push(o>>18|240,o>>12&63|128,o>>6&63|128,63&o|128)}}return i}function U(e){return n.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(B,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function V(e,t,o,n){for(var r=0;r=t.length||r>=e.length);++r)t[r+o]=e[r];return r}},1145(e,t,o){"use strict";o.d(t,{A:()=>i});var n=o(6314),r=o.n(n)()((function(e){return e[1]}));r.push([e.id,'/*!\n * TOAST UI Color Picker\n * @version 2.2.8\n * @author NHN Cloud FE Development Team \n * @license MIT\n */.tui-colorpicker-clearfix{zoom:1}.tui-colorpicker-clearfix:after{clear:both;content:"";display:block}.tui-colorpicker-vml{behavior:url(#default#VML);display:block}.tui-colorpicker-container,.tui-colorpicker-palette-container{width:152px}.tui-colorpicker-palette-container ul{margin:0;padding:0;width:152px}.tui-colorpicker-palette-container li{float:left;list-style:none;margin:0;padding:0 3px 3px 0}.tui-colorpicker-palette-button{border:1px solid #ccc;cursor:pointer;display:block;height:16px;margin:0;outline:none;overflow:hidden;padding:0;width:16px}.tui-colorpicker-palette-button.tui-colorpicker-selected{border:2px solid #000}.tui-colorpicker-palette-button.tui-colorpicker-color-transparent{barckground-repeat:repeat;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAOCAYAAAD0f5bSAAABfGlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGAqSSwoyGFhYGDIzSspCnJ3UoiIjFJgv8PAzcDDIMRgxSCemFxc4BgQ4MOAE3y7xsAIoi/rgsxK8/x506a1fP4WNq+ZclYlOrj1gQF3SmpxMgMDIweQnZxSnJwLZOcA2TrJBUUlQPYMIFu3vKQAxD4BZIsUAR0IZN8BsdMh7A8gdhKYzcQCVhMS5AxkSwDZAkkQtgaInQ5hW4DYyRmJKUC2B8guiBvAgNPDRcHcwFLXkYC7SQa5OaUwO0ChxZOaFxoMcgcQyzB4MLgwKDCYMxgwWDLoMjiWpFaUgBQ65xdUFmWmZ5QoOAJDNlXBOT+3oLQktUhHwTMvWU9HwcjA0ACkDhRnEKM/B4FNZxQ7jxDLX8jAYKnMwMDcgxBLmsbAsH0PA4PEKYSYyjwGBn5rBoZt5woSixLhDmf8xkKIX5xmbARh8zgxMLDe+///sxoDA/skBoa/E////73o//+/i4H2A+PsQA4AJHdp4IxrEg8AAAGbaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA1LjQuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPGV4aWY6UGl4ZWxYRGltZW5zaW9uPjEzPC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6UGl4ZWxZRGltZW5zaW9uPjE0PC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CghrN1AAAABzSURBVCgVldKxEYAgDAXQD5VOpLuwgi4jlrTMqF00oOd5Aia/CcV/F4oYOgNlrLjvVyCEVJchBjEC25538PeaWTzRMBLxvIL7UZwFwL06qoA6aoAy+gFfJABvJAQPUoCMlICRRd8BzgHzJL4ok9aJ67l4AK9AxVKhHryUAAAAAElFTkSuQmCC");background-repeat:no-repeat}.tui-colorpicker-palette-hex{font-family:monospace;width:60px}.tui-colorpicker-palette-hex,.tui-colorpicker-palette-preview{zoom:1;display:inline-block;*display:inline;vertical-align:middle}.tui-colorpicker-palette-preview{border:1px solid #ccc;height:12px;overflow:hidden;width:12px}.tui-colorpicker-palette-toggle-slider{zoom:1;display:inline-block;*display:inline;float:right;vertical-align:middle}.tui-colorpicker-slider-container{zoom:1;height:122px;margin:5px 0 0}.tui-colorpicker-slider-container:after{clear:both;content:"";display:block}.tui-colorpicker-slider-left{float:left;height:120px;width:120px}.tui-colorpicker-slider-right{float:right;height:120px;width:32px}.tui-colorpicker-svg{display:block}.tui-colorpicker-slider-handle{height:1px;left:0;opacity:.9;overflow:visible;position:absolute;top:0;width:1px;z-index:2}.tui-colorpicker-svg-slider,.tui-colorpicker-vml-slider{border:1px solid #ccc;height:120px;overflow:hidden;width:120px}.tui-colorpicker-vml-slider{position:relative}.tui-colorpicker-vml-slider-bg{height:122px;left:0;margin:-1px 0 0 -1px;position:absolute;top:0;width:122px}.tui-colorpicker-svg-huebar{border:1px solid #ccc;float:right;height:120px;overflow:visible;width:18px}.tui-colorpicker-vml-huebar{position:relative;width:32px}.tui-colorpicker-vml-huebar-bg{height:121px;position:absolute;right:0;top:0;width:18px}',""]);const i=r},1093(e,t,o){"use strict";o.d(t,{A:()=>i});var n=o(6314),r=o.n(n)()((function(e){return e[1]}));r.push([e.id,'/*!\n * TOAST UI ImageEditor\n * @version 3.15.3\n * @license MIT\n */body>textarea{position:fixed!important}.tui-image-editor-container{background-color:#282828;-webkit-box-sizing:border-box;box-sizing:border-box;height:100%;letter-spacing:.3px;margin:0;min-height:300px;overflow:hidden;padding:0;position:relative}.tui-image-editor-container div,.tui-image-editor-container input,.tui-image-editor-container label,.tui-image-editor-container li,.tui-image-editor-container ul{-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:0;-ms-user-select:none;-moz-user-select:-moz-none;-webkit-user-select:none;user-select:none}.tui-image-editor-container .tui-image-editor-header{background-color:#151515;min-width:533px;position:absolute;top:0;width:100%}.tui-image-editor-container .tui-image-editor-controls-buttons,.tui-image-editor-container .tui-image-editor-header-buttons{float:right;margin:8px}.tui-image-editor-container .tui-image-editor-controls-logo,.tui-image-editor-container .tui-image-editor-header-logo{float:left;padding:17px;width:30%}.tui-image-editor-container .tui-image-editor-controls-buttons,.tui-image-editor-container .tui-image-editor-controls-logo{display:none;height:100%;width:270px}.tui-image-editor-container .tui-image-editor-controls-buttons button,.tui-image-editor-container .tui-image-editor-controls-buttons div,.tui-image-editor-container .tui-image-editor-header-buttons button,.tui-image-editor-container .tui-image-editor-header-buttons div{border:1px solid #ddd;border-radius:20px;cursor:pointer;display:inline-block;font-family:Noto Sans,sans-serif;font-size:12px;font-weight:700;height:40px;letter-spacing:.3px;line-height:40px;outline:none;padding:0;position:relative;text-align:center;vertical-align:middle;width:120px}.tui-image-editor-container .tui-image-editor-download-btn{background-color:#fdba3b;border-color:#fdba3b;color:#fff}.tui-image-editor-container .tui-image-editor-load-btn{bottom:0;cursor:pointer;display:inline-block;left:0;opacity:0;position:absolute;right:0;top:0;width:100%}.tui-image-editor-container .tui-image-editor-main-container{bottom:64px;position:absolute;top:0;width:100%}.tui-image-editor-container .tui-image-editor-main{bottom:0;left:0;position:absolute;right:0;text-align:center;top:64px}.tui-image-editor-container .tui-image-editor-wrap{bottom:0;overflow:auto;width:100%}.tui-image-editor-container .tui-image-editor-wrap .tui-image-editor-size-wrap{display:table;height:100%;width:100%}.tui-image-editor-container .tui-image-editor-wrap .tui-image-editor-size-wrap .tui-image-editor-align-wrap{display:table-cell;vertical-align:middle}.tui-image-editor-container .tui-image-editor{display:inline-block;position:relative}.tui-image-editor-container .tui-image-editor-help-menu,.tui-image-editor-container .tui-image-editor-menu{display:table-cell;list-style:none;margin:0 auto;padding:0;text-align:center;vertical-align:middle;white-space:nowrap;width:auto}.tui-image-editor-container .tui-image-editor-help-menu>.tui-image-editor-item,.tui-image-editor-container .tui-image-editor-menu>.tui-image-editor-item{border-radius:2px;cursor:pointer;display:inline-block;margin:0 4px;padding:7px 8px 3px;position:relative}.tui-image-editor-container .tui-image-editor-help-menu>.tui-image-editor-item[tooltip-content]:hover:before,.tui-image-editor-container .tui-image-editor-menu>.tui-image-editor-item[tooltip-content]:hover:before{border-left:7px solid transparent;border-right:7px solid transparent;border-top:7px solid #2f2f2f;content:"";display:inline-block;height:0;left:13px;margin:0 auto;position:absolute;top:-2px;width:0}.tui-image-editor-container .tui-image-editor-help-menu>.tui-image-editor-item[tooltip-content]:hover:after,.tui-image-editor-container .tui-image-editor-menu>.tui-image-editor-item[tooltip-content]:hover:after{background-color:#2f2f2f;border-radius:3px;color:#fff;content:attr(tooltip-content);display:inline-block;font-size:11px;font-weight:lighter;left:0;max-height:23px;min-width:24px;padding:5px 8px;position:absolute;top:-25px}.tui-image-editor-container .tui-image-editor-help-menu>.tui-image-editor-item.active,.tui-image-editor-container .tui-image-editor-menu>.tui-image-editor-item.active{background-color:#fff;-webkit-transition:all .3s ease;transition:all .3s ease}.tui-image-editor-container .tui-image-editor-wrap{position:absolute}.tui-image-editor-container .tui-image-editor-grid-visual{border:1px solid hsla(0,0%,100%,.7);display:none;height:100%;position:absolute;width:100%}.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-flip .tui-image-editor,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-rotate .tui-image-editor{-webkit-transition:none;transition:none}.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-flip .tui-image-editor-grid-visual,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-resize .tui-image-editor-grid-visual,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-rotate .tui-image-editor-grid-visual{display:block}.tui-image-editor-container .tui-image-editor-grid-visual table{border-collapse:collapse;height:100%;width:100%}.tui-image-editor-container .tui-image-editor-grid-visual table td{border:1px solid hsla(0,0%,100%,.3)}.tui-image-editor-container .tui-image-editor-grid-visual table td.dot:before{background-color:#fff;border:0;border-radius:100%;-webkit-box-shadow:0 0 1px 0 rgba(0,0,0,.3);box-shadow:0 0 1px 0 rgba(0,0,0,.3);-webkit-box-sizing:border-box;box-sizing:border-box;content:"";height:10px;position:absolute;width:10px}.tui-image-editor-container .tui-image-editor-grid-visual table td.dot.left-top:before{left:-5px;top:-5px}.tui-image-editor-container .tui-image-editor-grid-visual table td.dot.right-top:before{right:-5px;top:-5px}.tui-image-editor-container .tui-image-editor-grid-visual table td.dot.left-bottom:before{bottom:-5px;left:-5px}.tui-image-editor-container .tui-image-editor-grid-visual table td.dot.right-bottom:before{bottom:-5px;right:-5px}.tui-image-editor-container .tui-image-editor-submenu{bottom:0;display:none;height:150px;position:absolute;white-space:nowrap;width:100%;z-index:2}.tui-image-editor-container .tui-image-editor-submenu .tui-image-editor-button:hover svg>use.active{display:block}.tui-image-editor-container .tui-image-editor-submenu .tui-image-editor-submenu-item li{display:inline-block;vertical-align:top}.tui-image-editor-container .tui-image-editor-submenu .tui-image-editor-submenu-item .tui-image-editor-newline{display:block;margin-top:0}.tui-image-editor-container .tui-image-editor-submenu .tui-image-editor-submenu-item .tui-image-editor-button{cursor:pointer;display:inline-block;font-size:11px;font-weight:400;margin:0 9px;position:relative}.tui-image-editor-container .tui-image-editor-submenu .tui-image-editor-submenu-item .tui-image-editor-button.preset{margin:0 9px 20px 5px}.tui-image-editor-container .tui-image-editor-submenu .tui-image-editor-submenu-item label>span{cursor:pointer;display:inline-block;font-family:Noto Sans,sans-serif;font-size:11px;padding-top:5px}.tui-image-editor-container .tui-image-editor-submenu .tui-image-editor-submenu-item .tui-image-editor-button.apply label,.tui-image-editor-container .tui-image-editor-submenu .tui-image-editor-submenu-item .tui-image-editor-button.cancel label{vertical-align:7px}.tui-image-editor-container .tui-image-editor-submenu>div{display:none;vertical-align:bottom}.tui-image-editor-container .tui-image-editor-submenu .tui-image-editor-submenu-style{bottom:0;display:block;left:0;opacity:.95;position:absolute;right:0;top:0;z-index:-1}.tui-image-editor-container .tui-image-editor-partition>div{border-left:1px solid #3c3c3c;height:52px;margin:0 8px;width:1px}.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-filter .tui-image-editor-partition>div{height:108px;margin:0 29px 0 0}.tui-image-editor-container .tui-image-editor-submenu-align{margin-right:30px;text-align:left}.tui-image-editor-container .tui-image-editor-submenu-align label>span{white-space:nowrap;width:55px}.tui-image-editor-container .tui-image-editor-submenu-align:first-child{margin-right:0}.tui-image-editor-container .tui-image-editor-submenu-align:first-child label>span{width:70px}.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-crop .tui-image-editor-submenu>div.tui-image-editor-menu-crop,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-draw .tui-image-editor-submenu>div.tui-image-editor-menu-draw,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-filter .tui-image-editor-submenu>div.tui-image-editor-menu-filter,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-flip .tui-image-editor-submenu>div.tui-image-editor-menu-flip,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-icon .tui-image-editor-submenu>div.tui-image-editor-menu-icon,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-mask .tui-image-editor-submenu>div.tui-image-editor-menu-mask,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-resize .tui-image-editor-submenu>div.tui-image-editor-menu-resize,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-rotate .tui-image-editor-submenu>div.tui-image-editor-menu-rotate,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-shape .tui-image-editor-submenu>div.tui-image-editor-menu-shape,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-text .tui-image-editor-submenu>div.tui-image-editor-menu-text,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-zoom .tui-image-editor-submenu>div.tui-image-editor-menu-zoom{display:table-cell}.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-crop .tui-image-editor-submenu,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-draw .tui-image-editor-submenu,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-filter .tui-image-editor-submenu,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-flip .tui-image-editor-submenu,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-icon .tui-image-editor-submenu,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-mask .tui-image-editor-submenu,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-resize .tui-image-editor-submenu,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-rotate .tui-image-editor-submenu,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-shape .tui-image-editor-submenu,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-text .tui-image-editor-submenu,.tui-image-editor-container .tui-image-editor-main.tui-image-editor-menu-zoom .tui-image-editor-submenu{display:table}.tui-image-editor-container .tui-image-editor-help-menu{background-color:hsla(0,0%,100%,.06);border-radius:20px;list-style:none;margin:0 auto;padding:0;position:absolute;text-align:center;vertical-align:middle;z-index:2}.tui-image-editor-container .tui-image-editor-help-menu .tie-panel-history{background-color:#fff;-webkit-box-shadow:0 2px 6px 0 rgba(0,0,0,.15);box-shadow:0 2px 6px 0 rgba(0,0,0,.15);color:#444;cursor:auto;display:none;height:276px;padding:4px 2px;position:absolute;-webkit-transform:translateX(calc(-50% + 12px));transform:translateX(calc(-50% + 12px));width:196px}.tui-image-editor-container .tui-image-editor-help-menu .tie-panel-history .history-list{height:268px;list-style:none;overflow:hidden scroll;padding:0}.tui-image-editor-container .tui-image-editor-help-menu .tie-panel-history .history-list .history-item{font-size:11px;height:24px;line-height:24px}.tui-image-editor-container .tui-image-editor-help-menu .tie-panel-history .history-list .history-item .tui-image-editor-history-item{cursor:pointer;height:24px;position:relative}.tui-image-editor-container .tui-image-editor-help-menu .tie-panel-history .history-list .history-item .tui-image-editor-history-item svg{height:24px;width:24px}.tui-image-editor-container .tui-image-editor-help-menu .tie-panel-history .history-list .history-item .tui-image-editor-history-item span{display:inline-block;height:24px;text-align:left;width:128px}.tui-image-editor-container .tui-image-editor-help-menu .tie-panel-history .history-list .history-item .tui-image-editor-history-item .history-item-icon{display:inline-block;height:24px;left:6px;position:absolute;top:6px;width:24px}.tui-image-editor-container .tui-image-editor-help-menu .tie-panel-history .history-list .history-item .tui-image-editor-history-item .history-item-checkbox{display:none;height:24px;position:absolute;right:-6px;top:5px;width:24px}.tui-image-editor-container .tui-image-editor-help-menu .tie-panel-history .history-list .history-item.selected-item{background-color:hsla(0,0%,47%,.12)}.tui-image-editor-container .tui-image-editor-help-menu .tie-panel-history .history-list .history-item.selected-item .history-item-checkbox{display:inline-block}.tui-image-editor-container .tui-image-editor-help-menu .tie-panel-history .history-list .history-item.disabled-item{color:#333;opacity:.3}.tui-image-editor-container .tui-image-editor-help-menu .opened .tie-panel-history{display:block}.tui-image-editor-container .tui-image-editor-help-menu .opened .tie-panel-history:before{content:"";display:inline-block;height:0;margin:0 auto;position:absolute;width:0}.tui-image-editor-container .filter-color-item{display:inline-block}.tui-image-editor-container .filter-color-item .tui-image-editor-checkbox{display:block}.tui-image-editor-container .tui-image-editor-checkbox-wrap{display:inline-block!important;text-align:left}.tui-image-editor-container .tui-image-editor-checkbox-wrap.fixed-width{white-space:normal;width:187px}.tui-image-editor-container .tui-image-editor-checkbox{display:inline-block;margin:1px 0}.tui-image-editor-container .tui-image-editor-checkbox input{height:14px;opacity:0;width:14px}.tui-image-editor-container .tui-image-editor-checkbox>label>span{color:#fff;height:14px;position:relative}.tui-image-editor-container .tui-image-editor-checkbox input+label:before,.tui-image-editor-container .tui-image-editor-checkbox>label>span:before{background-color:#fff;border:0;border-radius:2px;-webkit-box-sizing:border-box;box-sizing:border-box;content:"";display:inline-block;font-size:11px;height:14px;left:-19px;margin:0;padding-top:1px;position:absolute;text-align:center;top:6px;width:14px}.tui-image-editor-container .tui-image-editor-checkbox input[type=checkbox]:checked+span:before{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAMBJREFUKBWVkjEOwjAMRe2WgZW7IIHEDdhghhuwcQ42rlJugAQS54Cxa5cq1QM5TUpByZfS2j9+dlJVt/tX5ZxbS4ZU9VLkQvSHKTIGRaVJYFmKrBbTCJxE2UgCdDzMZDkHrOV6b95V0US6UmgKodujEZbJg0B0ZgEModO5lrY1TMQf1TpyJGBEjD+E2NPN7ukIUDiF/BfEXgRiGEw8NgkffYGYwCi808fpn/6OvfUfsDr/Vc1IfRf8sKnFVqeiVQfDu0tf/nWH9gAAAABJRU5ErkJggg==);background-size:cover}.tui-image-editor-container .tui-image-editor-selectlist-wrap{position:relative}.tui-image-editor-container .tui-image-editor-selectlist-wrap select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border:1px solid #cbdbdb;border-radius:0;height:28px;margin-top:4px;outline:0;padding:0 7px 0 10px;width:100%}.tui-image-editor-container .tui-image-editor-selectlist-wrap .tui-image-editor-selectlist{background-color:#fff;border:1px solid #ccc;border-top:0;display:none;padding:4px 0;position:relative;top:-1px}.tui-image-editor-container .tui-image-editor-selectlist-wrap .tui-image-editor-selectlist li{display:block;font-family:Noto Sans,sans-serif;padding:7px 10px;text-align:left}.tui-image-editor-container .tui-image-editor-selectlist-wrap .tui-image-editor-selectlist li:hover{background-color:rgba(81,92,230,.05)}.tui-image-editor-container .tui-image-editor-selectlist-wrap:before{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAHlJREFUKBVjYBgFOEOAEVkmPDxc89+/f6eAYjzI4kD2FyYmJrOVK1deh4kzwRggGiQBVJCELAZig8SQNYHEmEEEMrh69eo1HR0dfqCYJUickZGxf9WqVf3IakBsFBthklpaWmVA9mEQhrJhUoTp0NBQCRAmrHL4qgAAuu4cWZOZIGsAAAAASUVORK5CYII=);background-size:cover;content:"";display:inline-block;height:14px;position:absolute;right:5px;top:10px;width:14px}.tui-image-editor-container .tui-image-editor-selectlist-wrap select::-ms-expand{display:none}.tui-image-editor-container .tui-image-editor-virtual-range-bar .tui-image-editor-disabled,.tui-image-editor-container .tui-image-editor-virtual-range-pointer .tui-image-editor-disabled,.tui-image-editor-container .tui-image-editor-virtual-range-subbar .tui-image-editor-disabled{backbround-color:red}.tui-image-editor-container .tui-image-editor-range{display:inline-block;height:17px;position:relative;top:5px;width:166px}.tui-image-editor-container .tui-image-editor-virtual-range-bar{background-color:#666;height:2px;position:absolute;top:7px;width:100%}.tui-image-editor-container .tui-image-editor-virtual-range-subbar{background-color:#d1d1d1;height:100%;left:0;position:absolute;right:0}.tui-image-editor-container .tui-image-editor-virtual-range-pointer{background-color:#fff;border-radius:100%;cursor:pointer;height:12px;left:0;position:absolute;top:-5px;width:12px}.tui-image-editor-container .tui-image-editor-range-wrap{display:inline-block;margin-left:4px}.tui-image-editor-container .tui-image-editor-range-wrap.short .tui-image-editor-range{width:100px}.tui-image-editor-container .color-picker-control .tui-image-editor-range{margin-left:10px;width:108px}.tui-image-editor-container .color-picker-control .tui-image-editor-virtual-range-pointer{background-color:#333}.tui-image-editor-container .color-picker-control .tui-image-editor-virtual-range-bar{background-color:#ccc}.tui-image-editor-container .color-picker-control .tui-image-editor-virtual-range-subbar{background-color:#606060}.tui-image-editor-container .tui-image-editor-range-wrap.tui-image-editor-newline.short{margin-left:19px;margin-top:-2px}.tui-image-editor-container .tui-image-editor-range-wrap.tui-image-editor-newline.short label{color:#8e8e8e;font-weight:400}.tui-image-editor-container .tui-image-editor-range-wrap label{color:#fff;font-size:11px;margin-right:7px;vertical-align:baseline}.tui-image-editor-container .tui-image-editor-range-value{background-color:#1c1c1c;border:1px solid #d5d5d5;border-radius:2px;-webkit-box-shadow:none;box-shadow:none;color:#fff;cursor:default;font-family:Noto Sans,sans-serif;font-weight:lighter;height:24px;margin-left:4px;margin-top:15px;outline:none;text-align:center;vertical-align:baseline;width:40px}.tui-image-editor-container .tui-image-editor-controls{background-color:#151515;bottom:0;display:table;height:64px;position:absolute;width:100%;z-index:2}.tui-image-editor-container .tui-image-editor-icpartition{background-color:#444;display:inline-block;height:24px;width:1px}.tui-image-editor-container.left .tui-image-editor-menu>.tui-image-editor-item[tooltip-content]:before{border-bottom:7px solid transparent;border-right:7px solid #2f2f2f;border-top:7px solid transparent;left:28px;top:11px}.tui-image-editor-container.left .tui-image-editor-menu>.tui-image-editor-item[tooltip-content]:after{left:42px;top:7px;white-space:nowrap}.tui-image-editor-container.left .tui-image-editor-submenu{height:100%;left:0;width:248px}.tui-image-editor-container.left .tui-image-editor-main-container{height:100%;left:64px;width:calc(100% - 64px)}.tui-image-editor-container.left .tui-image-editor-controls{display:table;height:100%;width:64px}.tui-image-editor-container.left .tui-image-editor-menu,.tui-image-editor-container.right .tui-image-editor-menu{white-space:inherit}.tui-image-editor-container.left .tui-image-editor-submenu,.tui-image-editor-container.right .tui-image-editor-submenu{white-space:normal}.tui-image-editor-container.left .tui-image-editor-submenu>div,.tui-image-editor-container.right .tui-image-editor-submenu>div{vertical-align:middle}.tui-image-editor-container.left .tui-image-editor-controls li,.tui-image-editor-container.right .tui-image-editor-controls li{display:inline-block;margin:4px auto}.tui-image-editor-container.left .tui-image-editor-icpartition,.tui-image-editor-container.right .tui-image-editor-icpartition{height:1px;position:relative;top:-7px;width:24px}.tui-image-editor-container.left .tui-image-editor-submenu .tui-image-editor-partition,.tui-image-editor-container.right .tui-image-editor-submenu .tui-image-editor-partition{display:block;margin:auto;width:75%}.tui-image-editor-container.left .tui-image-editor-submenu .tui-image-editor-partition>div,.tui-image-editor-container.right .tui-image-editor-submenu .tui-image-editor-partition>div{border-bottom:1px solid #3c3c3c;border-left:0;height:10px;margin:0;width:100%}.tui-image-editor-container.left .tui-image-editor-submenu .tui-image-editor-submenu-align,.tui-image-editor-container.right .tui-image-editor-submenu .tui-image-editor-submenu-align{margin-right:0}.tui-image-editor-container.left .tui-image-editor-submenu .tui-image-editor-submenu-item li,.tui-image-editor-container.right .tui-image-editor-submenu .tui-image-editor-submenu-item li{margin-top:15px}.tui-image-editor-container.left .tui-image-editor-submenu .tui-image-editor-submenu-item .tui-colorpicker-clearfix li,.tui-image-editor-container.right .tui-image-editor-submenu .tui-image-editor-submenu-item .tui-colorpicker-clearfix li{margin-top:0}.tui-image-editor-container.left .tui-image-editor-checkbox-wrap.fixed-width,.tui-image-editor-container.right .tui-image-editor-checkbox-wrap.fixed-width{white-space:normal;width:182px}.tui-image-editor-container.left .tui-image-editor-range-wrap.tui-image-editor-newline label.range,.tui-image-editor-container.right .tui-image-editor-range-wrap.tui-image-editor-newline label.range{display:block;margin:auto;text-align:left;width:75%}.tui-image-editor-container.left .tui-image-editor-range,.tui-image-editor-container.right .tui-image-editor-range{width:136px}.tui-image-editor-container.right .tui-image-editor-menu>.tui-image-editor-item[tooltip-content]:before{border-bottom:7px solid transparent;border-left:7px solid #2f2f2f;border-top:7px solid transparent;left:-3px;top:11px}.tui-image-editor-container.right .tui-image-editor-menu>.tui-image-editor-item[tooltip-content]:after{left:unset;right:43px;top:7px;white-space:nowrap}.tui-image-editor-container.right .tui-image-editor-submenu{height:100%;right:0;width:248px}.tui-image-editor-container.right .tui-image-editor-main-container{height:100%;right:64px;width:calc(100% - 64px)}.tui-image-editor-container.right .tui-image-editor-controls{display:table;height:100%;right:0;width:64px}.tui-image-editor-container.bottom .tui-image-editor-submenu .tui-image-editor-partition.only-left-right,.tui-image-editor-container.top .tui-image-editor-submenu .tui-image-editor-partition.only-left-right{display:none}.tui-image-editor-container.bottom .tui-image-editor-submenu>div{padding-bottom:24px}.tui-image-editor-container.top .color-picker-control .triangle{border-bottom:8px solid #fff;border-left:7px solid transparent;border-right:7px solid transparent;border-top:0;top:-8px}.tui-image-editor-container.top .tui-image-editor-size-wrap{height:100%}.tui-image-editor-container.top .tui-image-editor-main-container{bottom:0}.tui-image-editor-container.top .tui-image-editor-menu>.tui-image-editor-item[tooltip-content]:before{border-bottom:7px solid #2f2f2f;border-top:0;left:13px;top:33px}.tui-image-editor-container.top .tui-image-editor-menu>.tui-image-editor-item[tooltip-content]:after{top:38px}.tui-image-editor-container.top .tui-image-editor-submenu{bottom:auto;top:0}.tui-image-editor-container.top .tui-image-editor-submenu>div{padding-top:24px;vertical-align:top}.tui-image-editor-container.top .tui-image-editor-controls-buttons,.tui-image-editor-container.top .tui-image-editor-controls-logo{display:table-cell}.tui-image-editor-container.top .tui-image-editor-main{height:calc(100% - 64px);top:64px}.tui-image-editor-container.top .tui-image-editor-controls{bottom:inherit;top:0}.tui-image-editor-container .tui-image-editor-help-menu.top{height:40px;left:50%;top:8px;-webkit-transform:translateX(-50%);transform:translateX(-50%);white-space:nowrap;width:506px}.tui-image-editor-container .tui-image-editor-help-menu.top .tie-panel-history{top:45px}.tui-image-editor-container .tui-image-editor-help-menu.top .opened .tie-panel-history:before{border-bottom:8px solid #fff;border-left:8px solid transparent;border-right:8px solid transparent;left:90px;top:-8px}.tui-image-editor-container .tui-image-editor-help-menu.top>.tui-image-editor-item[tooltip-content]:before{border:7px solid transparent;border-bottom:7px solid #2f2f2f;border-top:none;left:13px;top:35px}.tui-image-editor-container .tui-image-editor-help-menu.top>.tui-image-editor-item[tooltip-content]:after{left:-4px;top:41px;white-space:nowrap}.tui-image-editor-container .tui-image-editor-help-menu.top>.tui-image-editor-item[tooltip-content].opened:after,.tui-image-editor-container .tui-image-editor-help-menu.top>.tui-image-editor-item[tooltip-content].opened:before{content:none}.tui-image-editor-container .tui-image-editor-help-menu.bottom{bottom:8px;height:40px;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);white-space:nowrap;width:506px}.tui-image-editor-container .tui-image-editor-help-menu.bottom .tie-panel-history{bottom:45px}.tui-image-editor-container .tui-image-editor-help-menu.bottom .opened .tie-panel-history:before{border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #fff;bottom:-8px;left:90px}.tui-image-editor-container .tui-image-editor-help-menu.bottom>.tui-image-editor-item[tooltip-content]:before{border:7px solid transparent;border-bottom:none;border-top-color:#2f2f2f;bottom:36px;left:13px;top:auto}.tui-image-editor-container .tui-image-editor-help-menu.bottom>.tui-image-editor-item[tooltip-content]:after{bottom:41px;left:-4px;top:auto;white-space:nowrap}.tui-image-editor-container .tui-image-editor-help-menu.bottom>.tui-image-editor-item[tooltip-content].opened:after,.tui-image-editor-container .tui-image-editor-help-menu.bottom>.tui-image-editor-item[tooltip-content].opened:before{content:none}.tui-image-editor-container .tui-image-editor-help-menu.left{height:506px;left:8px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);white-space:inherit;width:40px}.tui-image-editor-container .tui-image-editor-help-menu.left .tie-panel-history{left:140px;top:-4px}.tui-image-editor-container .tui-image-editor-help-menu.left .opened .tie-panel-history:before{border-bottom:8px solid transparent;border-right:8px solid #fff;border-top:8px solid transparent;left:-8px;top:14px}.tui-image-editor-container .tui-image-editor-help-menu.left .tui-image-editor-item{margin:4px auto;padding:6px 8px}.tui-image-editor-container .tui-image-editor-help-menu.left>.tui-image-editor-item[tooltip-content]:before{border:7px solid transparent;border-left:none;border-right-color:#2f2f2f;left:27px;top:11px}.tui-image-editor-container .tui-image-editor-help-menu.left>.tui-image-editor-item[tooltip-content]:after{left:40px;top:7px;white-space:nowrap}.tui-image-editor-container .tui-image-editor-help-menu.left>.tui-image-editor-item[tooltip-content].opened:after,.tui-image-editor-container .tui-image-editor-help-menu.left>.tui-image-editor-item[tooltip-content].opened:before{content:none}.tui-image-editor-container .tui-image-editor-help-menu.right{height:506px;right:8px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);white-space:inherit;width:40px}.tui-image-editor-container .tui-image-editor-help-menu.right .tie-panel-history{right:-30px;top:-4px}.tui-image-editor-container .tui-image-editor-help-menu.right .opened .tie-panel-history:before{border-bottom:8px solid transparent;border-left:8px solid #fff;border-top:8px solid transparent;right:-8px;top:14px}.tui-image-editor-container .tui-image-editor-help-menu.right .tui-image-editor-item{margin:4px auto;padding:6px 8px}.tui-image-editor-container .tui-image-editor-help-menu.right>.tui-image-editor-item[tooltip-content]:before{border:7px solid transparent;border-left:7px solid #2f2f2f;border-right:none;left:-6px;top:11px}.tui-image-editor-container .tui-image-editor-help-menu.right>.tui-image-editor-item[tooltip-content]:after{left:auto;right:39px;top:7px;white-space:nowrap}.tui-image-editor-container .tui-image-editor-help-menu.right>.tui-image-editor-item[tooltip-content].opened:after,.tui-image-editor-container .tui-image-editor-help-menu.right>.tui-image-editor-item[tooltip-content].opened:before{content:none}.tui-image-editor-container .tie-icon-add-button .tui-image-editor-button{min-width:42px}.tui-image-editor-container .svg_ic-helpmenu,.tui-image-editor-container .svg_ic-menu{height:24px;width:24px}.tui-image-editor-container .svg_ic-submenu{height:32px;width:32px}.tui-image-editor-container .svg_img-bi{height:26px;width:257px}.tui-image-editor-container .tui-image-editor-controls svg>use,.tui-image-editor-container .tui-image-editor-help-menu svg>use{display:none}.tui-image-editor-container .tui-image-editor-controls .enabled svg:hover>use.hover,.tui-image-editor-container .tui-image-editor-controls .normal svg:hover>use.hover,.tui-image-editor-container .tui-image-editor-help-menu .enabled svg:hover>use.hover,.tui-image-editor-container .tui-image-editor-help-menu .normal svg:hover>use.hover{display:block}.tui-image-editor-container .tui-image-editor-controls .active svg:hover>use.hover,.tui-image-editor-container .tui-image-editor-help-menu .active svg:hover>use.hover{display:none}.tui-image-editor-container .tui-image-editor-controls .active svg>use.active,.tui-image-editor-container .tui-image-editor-controls .enabled svg>use.enabled,.tui-image-editor-container .tui-image-editor-controls .on svg>use.hover,.tui-image-editor-container .tui-image-editor-controls .opened svg>use.hover,.tui-image-editor-container .tui-image-editor-controls svg>use.normal,.tui-image-editor-container .tui-image-editor-help-menu .active svg>use.active,.tui-image-editor-container .tui-image-editor-help-menu .enabled svg>use.enabled,.tui-image-editor-container .tui-image-editor-help-menu .on svg>use.hover,.tui-image-editor-container .tui-image-editor-help-menu .opened svg>use.hover,.tui-image-editor-container .tui-image-editor-help-menu svg>use.normal{display:block}.tui-image-editor-container .tui-image-editor-controls .active svg>use.normal,.tui-image-editor-container .tui-image-editor-controls .enabled svg>use.normal,.tui-image-editor-container .tui-image-editor-help-menu .active svg>use.normal,.tui-image-editor-container .tui-image-editor-help-menu .enabled svg>use.normal{display:none}.tui-image-editor-container .tui-image-editor-controls .help svg>use.disabled,.tui-image-editor-container .tui-image-editor-controls .help.enabled svg>use.normal,.tui-image-editor-container .tui-image-editor-help-menu .help svg>use.disabled,.tui-image-editor-container .tui-image-editor-help-menu .help.enabled svg>use.normal{display:block}.tui-image-editor-container .tui-image-editor-controls .help.enabled svg>use.disabled,.tui-image-editor-container .tui-image-editor-help-menu .help.enabled svg>use.disabled{display:none}.tui-image-editor-container .tui-image-editor-controls:hover{z-index:3}.tui-image-editor-container div.tui-colorpicker-clearfix{background-color:#f5f5f5;border:1px solid #d5d5d5;border-radius:2px;height:28px;margin-top:6px;padding:4px 7px;width:159px}.tui-image-editor-container .tui-colorpicker-palette-hex{background-color:#f5f5f5;border:0;font-family:Noto Sans,sans-serif;font-size:11px;margin-top:2px;width:114px}.tui-image-editor-container .tui-colorpicker-palette-hex[value=""]+.tui-colorpicker-palette-preview,.tui-image-editor-container .tui-colorpicker-palette-hex[value="#ffffff"]+.tui-colorpicker-palette-preview{border:1px solid #ccc}.tui-image-editor-container .tui-colorpicker-palette-hex[value=""]+.tui-colorpicker-palette-preview{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAdBJREFUWAnFl0FuwjAQRZ0ukiugHqFSOQNdseuKW3ALzkA4BateICvUGyCxrtRFd4WuunH/TzykaYJrnLEYaTJJsP2+x8GZZCbQrLU5mj7Bn+EP8HvnCObd+R7xBV5lWfaNON4AnsA38E94qLEt+0yiFaBzAV/Bv+Cxxr4co7hKCDpw1q9wLeNYYdlAwyn8TYt8Hme3+8D5ozcTaMCZ68PXa2tnM2sbEcOZAJhrrpl2DAcTOGNjZPSfCdzkw6JrfbiMv+osBe4y9WOedhm4jZfhbENWuxS44H9Wz/xw4WzqLOAqh1+zycgAwzEMzr5k5gaHOa9ULBwuuDkFlHI1Kl4PJ66kgIpnoywOTmRFAYcbwYk9UMApWkD8zAV5ihcwHk4Rx7gl0IFTQL0EFc+CTQ9OZHWH3YhlVJiVpTHbrTGLhTHLZVgff6s9lyBsI9KduSS83oj+34rTwJutmBmCnMsvozRwZqB5GTkBw6/jdPDu69iJ6BYk6eCcfbcgcQIK/MByaaiMqm8rHcjol2TnpWDhyAKSGdA3FrxtJUToX0ODqatetfGE+8tyEUOV8GY5dGRwLP/MBS4RHQr4bT7NRAQjlcOTfZxmv2G+c4hI8nn+Ax5PG/zhI393AAAAAElFTkSuQmCC);background-size:cover}.tui-image-editor-container .tui-colorpicker-palette-preview{border:0;border-radius:100%;float:left;height:17px;width:17px}.tui-image-editor-container .color-picker-control{background-color:#fff;border-radius:2px;-webkit-box-shadow:0 3px 22px 6px rgba(0,0,0,.15);box-shadow:0 3px 22px 6px rgba(0,0,0,.15);display:none;padding:16px;position:absolute;width:192px;z-index:99}.tui-image-editor-container .color-picker-control .tui-colorpicker-palette-toggle-slider{display:none}.tui-image-editor-container .color-picker-control .tui-colorpicker-palette-button{background-size:cover;border:0;border-radius:100%;font-size:1px;margin:2px}.tui-image-editor-container .color-picker-control .tui-colorpicker-palette-button[title=""],.tui-image-editor-container .color-picker-control .tui-colorpicker-palette-button[title="#ffffff"]{border:1px solid #ccc}.tui-image-editor-container .color-picker-control .triangle{border-left:7px solid transparent;border-right:7px solid transparent;border-top:8px solid #fff;bottom:-8px;height:0;left:84px;position:absolute;width:0}.tui-image-editor-container .color-picker-control .tui-colorpicker-container,.tui-image-editor-container .color-picker-control .tui-colorpicker-palette-container,.tui-image-editor-container .color-picker-control .tui-colorpicker-palette-container ul{height:auto;width:100%}.tui-image-editor-container .filter-color-item .color-picker-control label{font-color:#333;font-weight:400;margin-right:7pxleft}.tui-image-editor-container .filter-color-item .tui-image-editor-checkbox{margin-top:0}.tui-image-editor-container .filter-color-item .tui-image-editor-checkbox input+label:before,.tui-image-editor-container .filter-color-item .tui-image-editor-checkbox>label:before{left:-16px}.tui-image-editor-container .color-picker{height:auto;width:100%}.tui-image-editor-container .color-picker-value{border:0;border-radius:100%;height:32px;margin:auto auto 1px;width:32px}.tui-image-editor-container .color-picker-value.transparent{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAdBJREFUWAnFl0FuwjAQRZ0ukiugHqFSOQNdseuKW3ALzkA4BateICvUGyCxrtRFd4WuunH/TzykaYJrnLEYaTJJsP2+x8GZZCbQrLU5mj7Bn+EP8HvnCObd+R7xBV5lWfaNON4AnsA38E94qLEt+0yiFaBzAV/Bv+Cxxr4co7hKCDpw1q9wLeNYYdlAwyn8TYt8Hme3+8D5ozcTaMCZ68PXa2tnM2sbEcOZAJhrrpl2DAcTOGNjZPSfCdzkw6JrfbiMv+osBe4y9WOedhm4jZfhbENWuxS44H9Wz/xw4WzqLOAqh1+zycgAwzEMzr5k5gaHOa9ULBwuuDkFlHI1Kl4PJ66kgIpnoywOTmRFAYcbwYk9UMApWkD8zAV5ihcwHk4Rx7gl0IFTQL0EFc+CTQ9OZHWH3YhlVJiVpTHbrTGLhTHLZVgff6s9lyBsI9KduSS83oj+34rTwJutmBmCnMsvozRwZqB5GTkBw6/jdPDu69iJ6BYk6eCcfbcgcQIK/MByaaiMqm8rHcjol2TnpWDhyAKSGdA3FrxtJUToX0ODqatetfGE+8tyEUOV8GY5dGRwLP/MBS4RHQr4bT7NRAQjlcOTfZxmv2G+c4hI8nn+Ax5PG/zhI393AAAAAElFTkSuQmCC);background-size:cover;border:1px solid #cbcbcb}.tui-image-editor-container .color-picker-value+label{color:#fff}.tui-image-editor-container .tui-image-editor-submenu svg>use{display:none}.tie-icon-add-button.icon-arrow .tui-image-editor-button[data-icontype=icon-arrow] svg>use.active,.tie-icon-add-button.icon-arrow-2 .tui-image-editor-button[data-icontype=icon-arrow-2] svg>use.active,.tie-icon-add-button.icon-arrow-3 .tui-image-editor-button[data-icontype=icon-arrow-3] svg>use.active,.tie-icon-add-button.icon-bubble .tui-image-editor-button[data-icontype=icon-bubble] svg>use.active,.tie-icon-add-button.icon-heart .tui-image-editor-button[data-icontype=icon-heart] svg>use.active,.tie-icon-add-button.icon-location .tui-image-editor-button[data-icontype=icon-location] svg>use.active,.tie-icon-add-button.icon-polygon .tui-image-editor-button[data-icontype=icon-polygon] svg>use.active,.tie-icon-add-button.icon-star .tui-image-editor-button[data-icontype=icon-star] svg>use.active,.tie-icon-add-button.icon-star-2 .tui-image-editor-button[data-icontype=icon-star-2] svg>use.active,.tui-image-editor-container .tui-image-editor-submenu svg>use.normal{display:block}.tie-draw-line-select-button.free .tui-image-editor-button.free svg>use.normal,.tie-draw-line-select-button.line .tui-image-editor-button.line svg>use.normal{display:none}.tie-draw-line-select-button.free .tui-image-editor-button.free svg>use.active,.tie-draw-line-select-button.line .tui-image-editor-button.line svg>use.active{display:block}.tie-flip-button.flipX .tui-image-editor-button.flipX svg>use.normal,.tie-flip-button.flipY .tui-image-editor-button.flipY svg>use.normal,.tie-flip-button.resetFlip .tui-image-editor-button.resetFlip svg>use.normal{display:none}.tie-flip-button.flipX .tui-image-editor-button.flipX svg>use.active,.tie-flip-button.flipY .tui-image-editor-button.flipY svg>use.active,.tie-flip-button.resetFlip .tui-image-editor-button.resetFlip svg>use.active{display:block}.tie-mask-apply.apply.active .tui-image-editor-button.apply label{color:#fff}.tie-mask-apply.apply.active .tui-image-editor-button.apply svg>use.active{display:block}.tie-crop-button .tui-image-editor-button.apply,.tie-crop-preset-button .tui-image-editor-button.apply{margin-right:24px}.tie-crop-button .tui-image-editor-button.apply.active svg>use.active,.tie-crop-button .tui-image-editor-button.preset.active svg>use.active,.tie-crop-preset-button .tui-image-editor-button.apply.active svg>use.active,.tie-crop-preset-button .tui-image-editor-button.preset.active svg>use.active{display:block}.tie-resize-button .tui-image-editor-button.apply,.tie-resize-preset-button .tui-image-editor-button.apply{margin-right:24px}.tie-resize-button .tui-image-editor-button.apply.active svg>use.active,.tie-resize-button .tui-image-editor-button.preset.active svg>use.active,.tie-resize-preset-button .tui-image-editor-button.apply.active svg>use.active,.tie-resize-preset-button .tui-image-editor-button.preset.active svg>use.active{display:block}.tie-shape-button.circle .tui-image-editor-button.circle svg>use.normal,.tie-shape-button.rect .tui-image-editor-button.rect svg>use.normal,.tie-shape-button.triangle .tui-image-editor-button.triangle svg>use.normal{display:none}.tie-shape-button.circle .tui-image-editor-button.circle svg>use.active,.tie-shape-button.rect .tui-image-editor-button.rect svg>use.active,.tie-shape-button.triangle .tui-image-editor-button.triangle svg>use.active,.tie-text-align-button.tie-text-align-center .tui-image-editor-button.center svg>use.active,.tie-text-align-button.tie-text-align-left .tui-image-editor-button.left svg>use.active,.tie-text-align-button.tie-text-align-right .tui-image-editor-button.right svg>use.active,.tie-text-effect-button .tui-image-editor-button.active svg>use.active{display:block}.tie-icon-image-file,.tie-mask-image-file{border:1px solid green;cursor:inherit;height:100%;left:0;opacity:0;position:absolute;top:0;width:100%}.tie-zoom-button.flipX .tui-image-editor-button.flipX svg>use.normal,.tie-zoom-button.flipY .tui-image-editor-button.flipY svg>use.normal,.tie-zoom-button.resetFlip .tui-image-editor-button.resetFlip svg>use.normal{display:none}.tie-zoom-button.flipX .tui-image-editor-button.flipX svg>use.active,.tie-zoom-button.flipY .tui-image-editor-button.flipY svg>use.active,.tie-zoom-button.resetFlip .tui-image-editor-button.resetFlip svg>use.active{display:block}.tui-image-editor-container.top.tui-image-editor-top-optimization .tui-image-editor-controls ul{text-align:right}.tui-image-editor-container.top.tui-image-editor-top-optimization .tui-image-editor-controls-logo{display:none}',""]);const i=r},6314(e){"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var o=e(t);return t[2]?"@media ".concat(t[2]," {").concat(o,"}"):o})).join("")},t.i=function(e,o,n){"string"==typeof e&&(e=[[null,e,""]]);var r={};if(n)for(var i=0;i>1,d=-7,u=o?r-1:0,h=o?-1:1,m=e[t+u];for(u+=h,i=m&(1<<-d)-1,m>>=-d,d+=s;d>0;i=256*i+e[t+u],u+=h,d-=8);for(a=i&(1<<-d)-1,i>>=-d,d+=n;d>0;a=256*a+e[t+u],u+=h,d-=8);if(0===i)i=1-c;else{if(i===l)return a?NaN:1/0*(m?-1:1);a+=Math.pow(2,n),i-=c}return(m?-1:1)*a*Math.pow(2,i-n)},t.write=function(e,t,o,n,r,i){var a,s,l,c=8*i-r-1,d=(1<>1,h=23===r?Math.pow(2,-24)-Math.pow(2,-77):0,m=n?0:i-1,g=n?1:-1,p=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(s=isNaN(t)?1:0,a=d):(a=Math.floor(Math.log(t)/Math.LN2),t*(l=Math.pow(2,-a))<1&&(a--,l*=2),(t+=a+u>=1?h/l:h*Math.pow(2,1-u))*l>=2&&(a++,l/=2),a+u>=d?(s=0,a=d):a+u>=1?(s=(t*l-1)*Math.pow(2,r),a+=u):(s=t*Math.pow(2,u-1)*Math.pow(2,r),a=0));r>=8;e[o+m]=255&s,m+=g,s/=256,r-=8);for(a=a<0;e[o+m]=255&a,m+=g,a/=256,c-=8);e[o+m-g]|=128*p}},4634(e){var t={}.toString;e.exports=Array.isArray||function(e){return"[object Array]"==t.call(e)}},5072(e,t,o){"use strict";var n,r=function(){return void 0===n&&(n=Boolean(window&&document&&document.all&&!window.atob)),n},i=function(){var e={};return function(t){if(void 0===e[t]){var o=document.querySelector(t);if(window.HTMLIFrameElement&&o instanceof window.HTMLIFrameElement)try{o=o.contentDocument.head}catch(e){o=null}e[t]=o}return e[t]}}(),a=[];function s(e){for(var t=-1,o=0;o',"accordion-toggle":'',accordion:'',"action-next":'',"action-prev":'',addtag:'',"ai-prompt":'',ai:'',"align-center":'',"align-justify":'',"align-left":'',"align-none":'',"align-right":'',"arrow-left":'',"arrow-right":'',bold:'',bookmark:'',"border-style":'',"border-width":'',brightness:'',browse:'',cancel:'',"cell-background-color":'',"cell-border-color":'',"change-case":'',"character-count":'',"checklist-rtl":'',checklist:'',checkmark:'',"chevron-down":'',"chevron-left":'',"chevron-right":'',"chevron-up":'',close:'',"code-sample":'',"color-levels":'',"color-picker":'',"color-swatch-remove-color":'',"color-swatch":'',"comment-add":'',comment:'',contrast:'',copy:'',crop:'',"cut-column":'',"cut-row":'',cut:'',"document-properties":'',drag:'',"duplicate-column":'',"duplicate-row":'',duplicate:'',"edit-block":'',"edit-image":'',"embed-page":'',embed:'',emoji:'',export:'',fill:'',"flip-horizontally":'',"flip-vertically":'',footnote:'',"format-code":'',"format-painter":'',format:'',fullscreen:'',gallery:'',gamma:'',help:'',"highlight-bg-color":'',home:'',"horizontal-rule":'',"image-options":'',image:'',indent:'',info:'',"insert-character":'',"insert-time":'',invert:'',italic:'',language:'',"line-height":'',line:'',link:'',"list-bull-circle":'',"list-bull-default":'',"list-bull-square":'',"list-num-default-rtl":'',"list-num-default":'',"list-num-lower-alpha-rtl":'',"list-num-lower-alpha":'',"list-num-lower-greek-rtl":'',"list-num-lower-greek":'',"list-num-lower-roman-rtl":'',"list-num-lower-roman":'',"list-num-upper-alpha-rtl":'',"list-num-upper-alpha":'',"list-num-upper-roman-rtl":'',"list-num-upper-roman":'',lock:'',ltr:'',"math-equation":'',mentions:'',minus:'',"more-drawer":'',"new-document":'',"new-tab":'',"non-breaking":'',notice:'',"ordered-list-rtl":'',"ordered-list":'',orientation:'',outdent:'',"export-pdf":'',"export-word":'',"import-word":'',"page-break":'',paragraph:'',"paste-column-after":'',"paste-column-before":'',"paste-row-after":'',"paste-row-before":'',"paste-text":'',paste:'',"permanent-pen":'',plus:'',preferences:'',preview:'',print:'',quote:'',redo:'',reload:'',"remove-formatting":'',remove:'',"resize-handle":'',resize:'',"restore-draft":'',"revision-history":'',"rotate-left":'',"rotate-right":'',rtl:'',save:'',search:'',"select-all":'',selected:'',send:'',settings:'',sharpen:'',sourcecode:'',"spell-check":'',"strike-through":'',subscript:'',superscript:'',"table-caption":'',"table-cell-classes":'',"table-cell-properties":'',"table-cell-select-all":'',"table-cell-select-inner":'',"table-classes":'',"table-delete-column":'',"table-delete-row":'',"table-delete-table":'',"table-insert-column-after":'',"table-insert-column-before":'',"table-insert-row-above":'',"table-insert-row-after":'',"table-left-header":'',"table-merge-cells":'',"table-row-numbering-rtl":'',"table-row-numbering":'',"table-row-properties":'',"table-split-cells":'',"table-top-header":'',table:'',"template-add":'',template:'',"temporary-placeholder":'',"text-color":'',"text-size-decrease":'',"text-size-increase":'',toc:'',translate:'',typography:'',underline:'',undo:'',unlink:'',unlock:'',"unordered-list":'',unselected:'',upload:'',"add-file":'',adjustments:'',"alt-text":'',"auto-image-enhancement":'',blur:'',box:'',camera:'',caption:'',dropbox:'',evernote:'',exposure:'',fb:'',flickr:'',folder:'',"google-drive":'',"google-photos":'',grayscale:'',huddle:'',"image-decorative":'',"image-enhancements":'',instagram:'',onedrive:'',"photo-filter":'',"revert-changes":'',saturation:'',"transform-image":'',vibrance:'',vk:'',warmth:'',user:'',"vertical-align":'',visualblocks:'',visualchars:'',warning:'',"zoom-in":'',"zoom-out":''}})},7741(e,t,o){o(2983)},7726(e,t,o){o(9595)},9595(){!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.ModelManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=r=e,n=(i=String).prototype,n.isPrototypeOf(o)||(null===(a=r.constructor)||void 0===a?void 0:a.name)===i.name)?"string":t;var o,n;var r,i,a})(t)===e,o=e=>t=>typeof t===e,n=e=>t=>e===t,r=t("string"),i=t("object"),a=t("array"),s=n(null),l=o("boolean"),c=n(void 0),d=e=>!(e=>null==e)(e),u=o("function"),h=o("number"),m=()=>{},g=e=>()=>e,p=e=>e,f=(e,t)=>e===t;function v(e,...t){return(...o)=>{const n=t.concat(o);return e.apply(null,n)}}const b=e=>t=>!e(t),x=e=>e(),y=g(!1),w=g(!0);class _{constructor(e,t){this.tag=e,this.value=t}static some(e){return new _(!0,e)}static none(){return _.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?_.some(e(this.value)):_.none()}bind(e){return this.tag?e(this.value):_.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:_.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return d(e)?_.some(e):_.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}_.singletonNone=new _(!1);const C=Array.prototype.slice,S=Array.prototype.indexOf,k=Array.prototype.push,A=(e,t)=>{return o=e,n=t,S.call(o,n)>-1;var o,n},M=(e,t)=>{for(let o=0,n=e.length;o{const o=[];for(let n=0;n{const o=e.length,n=new Array(o);for(let r=0;r{for(let o=0,n=e.length;o{const o=[],n=[];for(let r=0,i=e.length;r{const o=[];for(let n=0,r=e.length;n(((e,t)=>{for(let o=e.length-1;o>=0;o--)t(e[o],o)})(e,((e,n)=>{o=t(o,e,n)})),o),L=(e,t,o)=>(E(e,((e,n)=>{o=t(o,e,n)})),o),P=(e,t)=>((e,t,o)=>{for(let n=0,r=e.length;n{for(let o=0,n=e.length;o{const t=[];for(let o=0,n=e.length;oj(I(e,t)),B=(e,t)=>{for(let o=0,n=e.length;o{const o={};for(let n=0,r=e.length;nt>=0&&tH(e,0),V=e=>H(e,e.length-1),Z=(e,t)=>{for(let o=0;o{const o=W(e);for(let n=0,r=o.length;nJ(e,((e,o)=>({k:o,v:t(e,o)}))),J=(e,t)=>{const o={};return G(e,((e,n)=>{const r=t(e,n);o[r.k]=r.v})),o},Q=(e,t)=>{const o={};return((e,t,o,n)=>{G(e,((e,r)=>{(t(e,r)?o:n)(e,r)}))})(e,t,(e=>(t,o)=>{e[o]=t})(o),m),o},q=(e,t)=>{const o=[];return G(e,((e,n)=>{o.push(t(e,n))})),o},K=e=>q(e,p),$=(e,t)=>Y.call(e,t),ee="undefined"!=typeof window?window:Function("return this;")(),te=(e,t)=>((e,t)=>{let o=null!=t?t:ee;for(let t=0;t{const o=((e,t)=>te(e,t))(e,t);if(null==o)throw new Error(e+" not available on this browser");return o},ne=Object.getPrototypeOf,re=e=>{const t=te("ownerDocument.defaultView",e);return i(e)&&((e=>oe("HTMLElement",e))(t).prototype.isPrototypeOf(e)||/^HTML\w*Element$/.test(ne(e).constructor.name))},ie=e=>e.dom.nodeName.toLowerCase(),ae=e=>e.dom.nodeType,se=e=>t=>ae(t)===e,le=e=>8===ae(e)||"#comment"===ie(e),ce=e=>de(e)&&re(e.dom),de=se(1),ue=se(3),he=se(9),me=se(11),ge=e=>t=>de(t)&&ie(t)===e,pe=(e,t,o)=>{if(!(r(o)||l(o)||h(o)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",o,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,o+"")},fe=(e,t,o)=>{pe(e.dom,t,o)},ve=(e,t)=>{const o=e.dom;G(t,((e,t)=>{pe(o,t,e)}))},be=(e,t)=>{const o=e.dom.getAttribute(t);return null===o?void 0:o},xe=(e,t)=>_.from(be(e,t)),ye=(e,t)=>{e.dom.removeAttribute(t)},we=e=>L(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}),_e=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},Ce={fromHtml:(e,t)=>{const o=(t||document).createElement("div");if(o.innerHTML=e,!o.hasChildNodes()||o.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return _e(o.childNodes[0])},fromTag:(e,t)=>{const o=(t||document).createElement(e);return _e(o)},fromText:(e,t)=>{const o=(t||document).createTextNode(e);return _e(o)},fromDom:_e,fromPoint:(e,t,o)=>_.from(e.dom.elementFromPoint(t,o)).map(_e)},Se=(e,t)=>{const o=e.dom;if(1!==o.nodeType)return!1;{const e=o;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},ke=e=>1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType||0===e.childElementCount,Ae=(e,t)=>{const o=void 0===t?document:t.dom;return ke(o)?_.none():_.from(o.querySelector(e)).map(Ce.fromDom)},Me=(e,t)=>e.dom===t.dom,Te=(e,t)=>{const o=e.dom,n=t.dom;return o!==n&&o.contains(n)},Ie=Se,Ee=e=>Ce.fromDom(e.dom.ownerDocument),De=e=>he(e)?e:Ee(e),Oe=e=>_.from(e.dom.parentNode).map(Ce.fromDom),Ne=e=>_.from(e.dom.parentElement).map(Ce.fromDom),Le=(e,t)=>{const o=u(t)?t:y;let n=e.dom;const r=[];for(;null!==n.parentNode&&void 0!==n.parentNode;){const e=n.parentNode,t=Ce.fromDom(e);if(r.push(t),!0===o(t))break;n=e}return r},Pe=e=>_.from(e.dom.previousSibling).map(Ce.fromDom),Re=e=>_.from(e.dom.nextSibling).map(Ce.fromDom),je=e=>I(e.dom.childNodes,Ce.fromDom),ze=(e,t)=>{const o=e.dom.childNodes;return _.from(o[t]).map(Ce.fromDom)},Be=(e,t)=>{Oe(e).each((o=>{o.dom.insertBefore(t.dom,e.dom)}))},Fe=(e,t)=>{Re(e).fold((()=>{Oe(e).each((e=>{Ue(e,t)}))}),(e=>{Be(e,t)}))},He=(e,t)=>{const o=(e=>ze(e,0))(e);o.fold((()=>{Ue(e,t)}),(o=>{e.dom.insertBefore(t.dom,o.dom)}))},Ue=(e,t)=>{e.dom.appendChild(t.dom)},Ve=(e,t)=>{Be(e,t),Ue(t,e)},Ze=(e,t)=>{E(t,((o,n)=>{const r=0===n?e:t[n-1];Fe(r,o)}))},We=(e,t)=>{E(t,(t=>{Ue(e,t)}))},Ye=e=>{e.dom.textContent="",E(je(e),(e=>{Ge(e)}))},Ge=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)},Xe=e=>{const t=je(e);t.length>0&&Ze(e,t),Ge(e)},Je=(e,t)=>Ce.fromDom(e.dom.cloneNode(t)),Qe=e=>Je(e,!1),qe=e=>Je(e,!0),Ke=(e,t)=>{const o=Ce.fromTag(t),n=we(e);return ve(o,n),o},$e=["tfoot","thead","tbody","colgroup"],et=(e,t,o)=>({element:e,rowspan:t,colspan:o}),tt=(e,t,o)=>({element:e,cells:t,section:o}),ot=(e,t,o)=>({element:e,isNew:t,isLocked:o}),nt=(e,t,o,n)=>({element:e,cells:t,section:o,isNew:n}),rt=e=>me(e)&&d(e.dom.host),it=e=>Ce.fromDom(e.dom.getRootNode()),at=e=>Ce.fromDom(e.dom.host),st=e=>d(e.dom.shadowRoot),lt=e=>{const t=ue(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const o=t.ownerDocument;return(e=>{const t=it(e);return rt(t)?_.some(t):_.none()})(Ce.fromDom(t)).fold((()=>o.body.contains(t)),(n=lt,r=at,e=>n(r(e))));var n,r},ct=()=>dt(Ce.fromDom(document)),dt=e=>{const t=e.dom.body;if(null==t)throw new Error("Body is not available yet");return Ce.fromDom(t)},ut=(e,t)=>{let o=[];return E(je(e),(e=>{t(e)&&(o=o.concat([e])),o=o.concat(ut(e,t))})),o},ht=(e,t,o)=>((e,t,o)=>O(Le(e,o),t))(e,(e=>Se(e,t)),o),mt=(e,t)=>((e,t)=>O(je(e),t))(e,(e=>Se(e,t))),gt=(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return ke(o)?[]:I(o.querySelectorAll(e),Ce.fromDom)})(t,e);var pt=(e,t,o,n,r)=>e(o,n)?_.some(o):u(r)&&r(o)?_.none():t(o,n,r);const ft=(e,t,o)=>{let n=e.dom;const r=u(o)?o:y;for(;n.parentNode;){n=n.parentNode;const e=Ce.fromDom(n);if(t(e))return _.some(e);if(r(e))break}return _.none()},vt=(e,t,o)=>pt(((e,t)=>t(e)),ft,e,t,o),bt=(e,t,o)=>ft(e,(e=>Se(e,t)),o),xt=(e,t)=>((e,t)=>P(e.dom.childNodes,(e=>t(Ce.fromDom(e)))).map(Ce.fromDom))(e,(e=>Se(e,t))),yt=(e,t)=>Ae(t,e),wt=(e,t,o)=>pt(((e,t)=>Se(e,t)),bt,e,t,o),_t=(e,t,o=f)=>e.exists((e=>o(e,t))),Ct=e=>{const t=[],o=e=>{t.push(e)};for(let t=0;te?_.some(t):_.none(),kt=(e,t,o)=>""===t||e.length>=t.length&&e.substr(o,o+t.length)===t,At=(e,t,o=0,n)=>{const r=e.indexOf(t,o);return-1!==r&&(!!c(n)||r+t.length<=n)},Mt=(e,t)=>kt(e,t,0),Tt=(e,t)=>kt(e,t,e.length-t.length),It=(e=>t=>t.replace(e,""))(/^\s+|\s+$/g),Et=e=>e.length>0,Dt=e=>void 0!==e.style&&u(e.style.getPropertyValue),Ot=(e,t,o)=>{if(!r(o))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",o,":: Element ",e),new Error("CSS value must be a string: "+o);Dt(e)&&e.style.setProperty(t,o)},Nt=(e,t,o)=>{const n=e.dom;Ot(n,t,o)},Lt=(e,t)=>{const o=e.dom;G(t,((e,t)=>{Ot(o,t,e)}))},Pt=(e,t)=>{const o=e.dom,n=window.getComputedStyle(o).getPropertyValue(t);return""!==n||lt(e)?n:Rt(o,t)},Rt=(e,t)=>Dt(e)?e.style.getPropertyValue(t):"",jt=(e,t)=>{const o=e.dom,n=Rt(o,t);return _.from(n).filter((e=>e.length>0))},zt=(e,t)=>{((e,t)=>{Dt(e)&&e.style.removeProperty(t)})(e.dom,t),_t(xe(e,"style").map(It),"")&&ye(e,"style")},Bt=(e,t,o=0)=>xe(e,t).map((e=>parseInt(e,10))).getOr(o),Ft=(e,t)=>Bt(e,t,1),Ht=e=>ge("col")(e)?Bt(e,"span",1)>1:Ft(e,"colspan")>1,Ut=(e,t)=>parseInt(Pt(e,t),10),Vt=g(10),Zt=g(10),Wt=(e,t)=>Yt(e,t,w),Yt=(e,t,o)=>z(je(e),(e=>Se(e,t)?o(e)?[e]:[]:Yt(e,t,o))),Gt=(e,t)=>((e,t,o=y)=>o(t)?_.none():A(e,ie(t))?_.some(t):bt(t,e.join(","),(e=>Se(e,"table")||o(e))))(["td","th"],e,t),Xt=e=>Wt(e,"th,td"),Jt=e=>Se(e,"colgroup")?mt(e,"col"):z(Kt(e),(e=>mt(e,"col"))),Qt=(e,t)=>wt(e,"table",t),qt=e=>Wt(e,"tr"),Kt=e=>Qt(e).fold(g([]),(e=>mt(e,"colgroup"))),$t=(e,t)=>I(e,(e=>{if("colgroup"===ie(e)){const t=I(Jt(e),(e=>{const t=Bt(e,"span",1);return et(e,1,t)}));return tt(e,t,"colgroup")}{const o=I(Xt(e),(e=>{const t=Bt(e,"rowspan",1),o=Bt(e,"colspan",1);return et(e,t,o)}));return tt(e,o,t(e))}})),eo=e=>Oe(e).map((e=>{const t=ie(e);return(e=>A($e,e))(t)?t:"tbody"})).getOr("tbody"),to=e=>{const t=qt(e),o=[...Kt(e),...t];return $t(o,eo)},oo=e=>{let t,o=!1;return(...n)=>(o||(o=!0,t=e.apply(null,n)),t)},no=()=>ro(0,0),ro=(e,t)=>({major:e,minor:t}),io={nu:ro,detect:(e,t)=>{const o=String(t).toLowerCase();return 0===e.length?no():((e,t)=>{const o=((e,t)=>{for(let o=0;oNumber(t.replace(o,"$"+e));return ro(n(1),n(2))})(e,o)},unknown:no},ao=(e,t)=>{const o=String(t).toLowerCase();return P(e,(e=>e.search(o)))},so=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,lo=e=>t=>At(t,e),co=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:e=>At(e,"edge/")&&At(e,"chrome")&&At(e,"safari")&&At(e,"applewebkit")},{name:"Chromium",brand:"Chromium",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,so],search:e=>At(e,"chrome")&&!At(e,"chromeframe")},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:e=>At(e,"msie")||At(e,"trident")},{name:"Opera",versionRegexes:[so,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:lo("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:lo("firefox")},{name:"Safari",versionRegexes:[so,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:e=>(At(e,"safari")||At(e,"mobile/"))&&At(e,"applewebkit")}],uo=[{name:"Windows",search:lo("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:e=>At(e,"iphone")||At(e,"ipad"),versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:lo("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"macOS",search:lo("mac os x"),versionRegexes:[/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:lo("linux"),versionRegexes:[]},{name:"Solaris",search:lo("sunos"),versionRegexes:[]},{name:"FreeBSD",search:lo("freebsd"),versionRegexes:[]},{name:"ChromeOS",search:lo("cros"),versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/]}],ho={browsers:g(co),oses:g(uo)},mo="Edge",go="Chromium",po="Opera",fo="Firefox",vo="Safari",bo=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isEdge:n(mo),isChromium:n(go),isIE:n("IE"),isOpera:n(po),isFirefox:n(fo),isSafari:n(vo)}},xo={unknown:()=>bo({current:void 0,version:io.unknown()}),nu:bo,edge:g(mo),chromium:g(go),ie:g("IE"),opera:g(po),firefox:g(fo),safari:g(vo)},yo="Windows",wo="Android",_o="Linux",Co="macOS",So="Solaris",ko="FreeBSD",Ao="ChromeOS",Mo=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isWindows:n(yo),isiOS:n("iOS"),isAndroid:n(wo),isMacOS:n(Co),isLinux:n(_o),isSolaris:n(So),isFreeBSD:n(ko),isChromeOS:n(Ao)}},To={unknown:()=>Mo({current:void 0,version:io.unknown()}),nu:Mo,windows:g(yo),ios:g("iOS"),android:g(wo),linux:g(_o),macos:g(Co),solaris:g(So),freebsd:g(ko),chromeos:g(Ao)},Io=(e,t,o)=>{const n=ho.browsers(),r=ho.oses(),i=t.bind((e=>((e,t)=>Z(t.brands,(t=>{const o=t.brand.toLowerCase();return P(e,(e=>{var t;return o===(null===(t=e.brand)||void 0===t?void 0:t.toLowerCase())})).map((e=>({current:e.name,version:io.nu(parseInt(t.version,10),0)})))})))(n,e))).orThunk((()=>((e,t)=>ao(e,t).map((e=>{const o=io.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(n,e))).fold(xo.unknown,xo.nu),a=((e,t)=>ao(e,t).map((e=>{const o=io.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(r,e).fold(To.unknown,To.nu),s=((e,t,o,n)=>{const r=e.isiOS()&&!0===/ipad/i.test(o),i=e.isiOS()&&!r,a=e.isiOS()||e.isAndroid(),s=a||n("(pointer:coarse)"),l=r||!i&&a&&n("(min-device-width:768px)"),c=i||a&&!l,d=t.isSafari()&&e.isiOS()&&!1===/safari/i.test(o),u=!c&&!l&&!d;return{isiPad:g(r),isiPhone:g(i),isTablet:g(l),isPhone:g(c),isTouch:g(s),isAndroid:e.isAndroid,isiOS:e.isiOS,isWebView:g(d),isDesktop:g(u)}})(a,i,e,o);return{browser:i,os:a,deviceType:s}},Eo=e=>window.matchMedia(e).matches;let Do=oo((()=>Io(window.navigator.userAgent,_.from(window.navigator.userAgentData),Eo)));const Oo=()=>Do(),No=(e,t)=>{const o=o=>{const n=t(o);if(n<=0||null===n){const t=Pt(o,e);return parseFloat(t)||0}return n},n=(e,t)=>L(t,((t,o)=>{const n=Pt(e,o),r=void 0===n?0:parseInt(n,10);return isNaN(r)?t:t+r}),0);return{set:(t,o)=>{if(!h(o)&&!o.match(/^[0-9]+$/))throw new Error(e+".set accepts only positive integer values. Value was "+o);const n=t.dom;Dt(n)&&(n.style[e]=o+"px")},get:o,getOuter:o,aggregate:n,max:(e,t,o)=>{const r=n(e,o);return t>r?t-r:0}}},Lo=(e,t)=>(e=>{const t=parseFloat(e);return isNaN(t)?_.none():_.some(t)})(e).getOr(t),Po=(e,t,o)=>Lo(Pt(e,t),o),Ro=(e,t)=>{const o=e.dom,n=o.getBoundingClientRect().width||o.offsetWidth;return"border-box"===t?n:((e,t,o,n)=>t-Po(e,`padding-${o}`,0)-Po(e,`padding-${n}`,0)-Po(e,`border-${o}-width`,0)-Po(e,`border-${n}-width`,0))(e,n,"left","right")},jo=No("width",(e=>e.dom.offsetWidth)),zo=e=>jo.get(e),Bo=e=>jo.getOuter(e),Fo=e=>Ro(e,"content-box"),Ho=e=>Po(e,"width",e.dom.offsetWidth),Uo=(e,t,o)=>{const n=e.cells,r=n.slice(0,t),i=n.slice(t),a=r.concat(o).concat(i);return Wo(e,a)},Vo=(e,t,o)=>Uo(e,t,[o]),Zo=(e,t,o)=>{e.cells[t]=o},Wo=(e,t)=>nt(e.element,t,e.section,e.isNew),Yo=(e,t)=>e.cells[t],Go=(e,t)=>Yo(e,t).element,Xo=e=>e.cells.length,Jo=e=>{const t=D(e,(e=>"colgroup"===e.section));return{rows:t.fail,cols:t.pass}},Qo=(e,t,o)=>{const n=I(e.cells,o);return nt(t(e.element),n,e.section,!0)},qo="data-snooker-locked-cols",Ko=e=>xe(e,qo).bind((e=>_.from(e.match(/\d+/g)))).map((e=>F(e,w))),$o=e=>{const t=L(Jo(e).rows,((e,t)=>(E(t.cells,((t,o)=>{t.isLocked&&(e[o]=!0)})),e)),{}),o=q(t,((e,t)=>parseInt(t,10)));return((e,t)=>{const o=C.call(e,0);return o.sort(t),o})(o)},en=(e,t)=>e+","+t,tn=(e,t)=>{const o=z(e.all,(e=>e.cells));return O(o,t)},on=e=>{const t={},o=[],n=U(e).map((e=>e.element)).bind(Qt).bind(Ko).getOr({});let r=0,i=0,a=0;const{pass:s,fail:l}=D(e,(e=>"colgroup"===e.section));E(l,(e=>{const s=[];E(e.cells,(e=>{let o=0;for(;void 0!==t[en(a,o)];)o++;const r=((e,t)=>$(e,t)&&void 0!==e[t]&&null!==e[t])(n,o.toString()),l=((e,t,o,n,r,i)=>({element:e,rowspan:t,colspan:o,row:n,column:r,isLocked:i}))(e.element,e.rowspan,e.colspan,a,o,r);for(let n=0;n{const t=(e=>{const t={};let o=0;return E(e.cells,(e=>{const n=e.colspan;T(n,(r=>{const i=o+r;t[i]=((e,t,o)=>({element:e,colspan:t,column:o}))(e.element,n,i)})),o+=n})),t})(e),o=((e,t)=>({element:e,columns:t}))(e.element,K(t));return{colgroups:[o],columns:t}})).getOrThunk((()=>({colgroups:[],columns:{}}))),u=((e,t)=>({rows:e,columns:t}))(r,i);return{grid:u,access:t,all:o,columns:c,colgroups:d}},nn={fromTable:e=>{const t=to(e);return on(t)},generate:on,getAt:(e,t,o)=>_.from(e.access[en(t,o)]),findItem:(e,t,o)=>{const n=tn(e,(e=>o(t,e.element)));return n.length>0?_.some(n[0]):_.none()},filterItems:tn,justCells:e=>z(e.all,(e=>e.cells)),justColumns:e=>K(e.columns),hasColumns:e=>W(e.columns).length>0,getColumnAt:(e,t)=>_.from(e.columns[t])},rn=(e,t=w)=>{const o=e.grid,n=T(o.columns,p),r=T(o.rows,p);return I(n,(o=>an((()=>z(r,(t=>nn.getAt(e,t,o).filter((e=>e.column===o)).toArray()))),(e=>1===e.colspan&&t(e.element)),(()=>nn.getAt(e,0,o)))))},an=(e,t,o)=>{const n=e();return P(n,t).orThunk((()=>_.from(n[0]).orThunk(o))).map((e=>e.element))},sn=e=>{const t=e.grid,o=T(t.rows,p),n=T(t.columns,p);return I(o,(t=>an((()=>z(n,(o=>nn.getAt(e,t,o).filter((e=>e.row===t)).fold(g([]),(e=>[e]))))),(e=>1===e.rowspan),(()=>nn.getAt(e,t,0)))))},ln=(e,t)=>{if(t<0||t>=e.length-1)return _.none();const o=e[t].fold((()=>{const o=(e=>{const t=C.call(e,0);return t.reverse(),t})(e.slice(0,t));return Z(o,((e,t)=>e.map((e=>({value:e,delta:t+1})))))}),(e=>_.some({value:e,delta:0}))),n=e[t+1].fold((()=>{const o=e.slice(t+1);return Z(o,((e,t)=>e.map((e=>({value:e,delta:t+1})))))}),(e=>_.some({value:e,delta:1})));return o.bind((e=>n.map((t=>{const o=t.delta+e.delta;return Math.abs(t.value-e.value)/o}))))},cn=(e,t)=>o=>"rtl"===dn(o)?t:e,dn=e=>"rtl"===Pt(e,"direction")?"rtl":"ltr",un=No("height",(e=>{const t=e.dom;return lt(e)?t.getBoundingClientRect().height:t.offsetHeight})),hn=e=>un.get(e),mn=e=>un.getOuter(e),gn=e=>Po(e,"height",e.dom.offsetHeight),pn=(e,t)=>({left:e,top:t,translate:(o,n)=>pn(e+o,t+n)}),fn=pn,vn=(e,t)=>void 0!==e?e:void 0!==t?t:0,bn=e=>{const t=e.dom.ownerDocument,o=t.body,n=t.defaultView,r=t.documentElement;if(o===e.dom)return fn(o.offsetLeft,o.offsetTop);const i=vn(null==n?void 0:n.pageYOffset,r.scrollTop),a=vn(null==n?void 0:n.pageXOffset,r.scrollLeft),s=vn(r.clientTop,o.clientTop),l=vn(r.clientLeft,o.clientLeft);return xn(e).translate(a-l,i-s)},xn=e=>{const t=e.dom,o=t.ownerDocument.body;return o===t?fn(o.offsetLeft,o.offsetTop):lt(e)?(e=>{const t=e.getBoundingClientRect();return fn(t.left,t.top)})(t):fn(0,0)},yn=(e,t)=>({row:e,y:t}),wn=(e,t)=>({col:e,x:t}),_n=e=>bn(e).left+Bo(e),Cn=e=>bn(e).left,Sn=(e,t)=>wn(e,Cn(t)),kn=(e,t)=>wn(e,_n(t)),An=e=>bn(e).top,Mn=(e,t)=>yn(e,An(t)),Tn=(e,t)=>yn(e,An(t)+mn(t)),In=(e,t,o)=>{if(0===o.length)return[];const n=I(o.slice(1),((t,o)=>t.map((t=>e(o,t))))),r=o[o.length-1].map((e=>t(o.length-1,e)));return n.concat([r])},En={delta:p,positions:e=>In(Mn,Tn,e),edge:An},Dn=cn({delta:p,edge:Cn,positions:e=>In(Sn,kn,e)},{delta:e=>-e,edge:_n,positions:e=>In(kn,Sn,e)}),On={delta:(e,t)=>Dn(t).delta(e,t),positions:(e,t)=>Dn(t).positions(e,t),edge:e=>Dn(e).edge(e)},Nn={unsupportedLength:["em","ex","cap","ch","ic","rem","lh","rlh","vw","vh","vi","vb","vmin","vmax","cm","mm","Q","in","pc","pt","px"],fixed:["px","pt"],relative:["%"],empty:[""]},Ln=(()=>{const e="[0-9]+",t="[eE]"+("[+-]?"+e),o=e=>`(?:${e})?`,n=["Infinity",e+"\\."+o(e)+o(t),"\\."+e+o(t),e+o(t)].join("|");return new RegExp(`^(${`[+-]?(?:${n})`})(.*)$`)})(),Pn=(e,t)=>_.from(Ln.exec(e)).bind((e=>{const o=Number(e[1]),n=e[2];return((e,t)=>M(t,(t=>M(Nn[t],(t=>e===t)))))(n,t)?_.some({value:o,unit:n}):_.none()})),Rn=/(\d+(\.\d+)?)%/,jn=/(\d+(\.\d+)?)px|em/,zn=ge("col"),Bn=ge("tr"),Fn=(e,t,o)=>{const n=Ne(e).getOrThunk((()=>dt(Ee(e))));return t(e)/o(n)*100},Hn=(e,t)=>{Nt(e,"width",t+"px")},Un=(e,t)=>{Nt(e,"width",t+"%")},Vn=(e,t)=>{Nt(e,"height",t+"px")},Zn=(e,t,o,n)=>{const r=parseFloat(e);return Tt(e,"%")&&"table"!==ie(t)?((e,t,o,n)=>{const r=Qt(e).map((e=>{const n=o(e);return Math.floor(t/100*n)})).getOr(t);return n(e,r),r})(t,r,o,n):r},Wn=e=>{const t=(e=>gn(e)+"px")(e);return t?Zn(t,e,hn,Vn):hn(e)},Yn=(e,t)=>jt(e,t).orThunk((()=>xe(e,t).map((e=>e+"px")))),Gn=e=>Yn(e,"width"),Xn=e=>Fn(e,zo,Fo),Jn=e=>zn(e)?zo(e):Ho(e),Qn=e=>Bn(e)?hn(e):((e,t,o)=>o(e)/Ft(e,t))(e,"rowspan",Wn),qn=(e,t,o)=>{Nt(e,"width",t+o)},Kn=e=>Fn(e,zo,Fo)+"%",$n=g(Rn),er=ge("col"),tr=e=>Gn(e).getOrThunk((()=>Jn(e)+"px")),or=e=>{return(t=e,Yn(t,"height")).getOrThunk((()=>Qn(e)+"px"));var t},nr=(e,t,o,n,r,i)=>e.filter(n).fold((()=>i(ln(o,t))),(e=>r(e))),rr=(e,t,o,n)=>{const r=rn(e),i=nn.hasColumns(e)?(e=>I(nn.justColumns(e),(e=>_.from(e.element))))(e):r,a=[_.some(On.edge(t))].concat(I(On.positions(r,t),(e=>e.map((e=>e.x))))),s=b(Ht);return I(i,((e,t)=>nr(e,t,a,s,(e=>{if((e=>{const t=Oo().browser,o=t.isChromium()||t.isFirefox();return!er(e)||o})(e))return o(e);{const e=(i=r[t],l=p,null!=i?l(i):_.none());return nr(e,t,a,s,(e=>n(_.some(zo(e)))),n)}var i,l}),n)))},ir=e=>e.map((e=>e+"px")).getOr(""),ar=(e,t,o)=>rr(e,t,Jn,(e=>e.getOrThunk(o.minCellWidth))),sr=(e,t,o,n)=>{const r=sn(e),i=I(e.all,(e=>_.some(e.element))),a=[_.some(En.edge(t))].concat(I(En.positions(r,t),(e=>e.map((e=>e.y)))));return I(i,((e,t)=>nr(e,t,a,w,o,n)))},lr=(e,t)=>()=>lt(e)?t(e):parseFloat(jt(e,"width").getOr("0")),cr=e=>{const t=lr(e,zo),o=g(0);return{width:t,pixelWidth:t,getWidths:(t,o)=>ar(t,e,o),getCellDelta:o,singleColumnWidth:g([0]),minCellWidth:o,setElementWidth:m,adjustTableWidth:m,isRelative:!0,label:"none"}},dr=e=>{const t=lr(e,(e=>parseFloat(Kn(e)))),o=lr(e,zo);return{width:t,pixelWidth:o,getWidths:(t,o)=>((e,t,o)=>rr(e,t,Xn,(e=>e.fold((()=>o.minCellWidth()),(e=>e/o.pixelWidth()*100)))))(t,e,o),getCellDelta:e=>e/o()*100,singleColumnWidth:(e,t)=>[100-e],minCellWidth:()=>Vt()/o()*100,setElementWidth:Un,adjustTableWidth:o=>{const n=t();Un(e,n+o/100*n)},isRelative:!0,label:"percent"}},ur=e=>{const t=lr(e,zo);return{width:t,pixelWidth:t,getWidths:(t,o)=>ar(t,e,o),getCellDelta:p,singleColumnWidth:(e,t)=>[Math.max(Vt(),e+t)-e],minCellWidth:Vt,setElementWidth:Hn,adjustTableWidth:o=>{const n=t()+o;Hn(e,n)},isRelative:!1,label:"pixel"}},hr=e=>Gn(e).fold((()=>cr(e)),(t=>((e,t)=>null!==$n().exec(t)?dr(e):ur(e))(e,t))),mr=ur,gr=dr,pr=(e,t,o)=>{const n=e[o].element,r=Ce.fromTag("td");Ue(r,Ce.fromTag("br"));(t?Ue:He)(n,r)},fr=(e,t)=>{const o=e=>Se(e.element,t),n=qe(e),r=to(n),i=hr(e),a=nn.generate(r),s=((e,t)=>{const o=e.grid.columns;let n=e.grid.rows,r=o,i=0,a=0;const s=[],l=[];return G(e.access,(e=>{if(s.push(e),t(e)){l.push(e);const t=e.row,o=t+e.rowspan-1,s=e.column,c=s+e.colspan-1;ti&&(i=o),sa&&(a=c)}})),((e,t,o,n,r,i)=>({minRow:e,minCol:t,maxRow:o,maxCol:n,allCells:r,selectedCells:i}))(n,r,i,a,s,l)})(a,o),l="th:not("+t+"),td:not("+t+")",c=Yt(n,"th,td",(e=>Se(e,l)));E(c,Ge),((e,t,o,n)=>{const r=O(e,(e=>"colgroup"!==e.section)),i=t.grid.columns,a=t.grid.rows;for(let e=0;eo.maxRow||so.maxCol||(nn.getAt(t,e,s).filter(n).isNone()?pr(r,a,e):a=!0)}})(r,a,s,o);const d=((e,t,o,n)=>{if(0===n.minCol&&t.grid.columns===n.maxCol+1)return 0;const r=ar(t,e,o),i=L(r,((e,t)=>e+t),0),a=L(r.slice(n.minCol,n.maxCol+1),((e,t)=>e+t),0),s=a/i*o.pixelWidth()-o.pixelWidth();return o.getCellDelta(s)})(e,nn.fromTable(e),i,s);return((e,t,o,n)=>{G(o.columns,(e=>{(e.columnt.maxCol)&&Ge(e.element)}));const r=O(Wt(e,"tr"),(e=>0===e.dom.childElementCount));E(r,Ge),t.minCol!==t.maxCol&&t.minRow!==t.maxRow||E(Wt(e,"th,td"),(e=>{ye(e,"rowspan"),ye(e,"colspan")})),ye(e,qo),ye(e,"data-snooker-col-series"),hr(e).adjustTableWidth(n)})(n,s,a,d),n},vr=((e,t)=>{const o=t=>e(t)?_.from(t.dom.nodeValue):_.none();return{get:n=>{if(!e(n))throw new Error("Can only get "+t+" value of a "+t+" node");return o(n).getOr("")},getOption:o,set:(o,n)=>{if(!e(o))throw new Error("Can only set raw "+t+" value of a "+t+" node");o.dom.nodeValue=n}}})(ue,"text"),br=e=>vr.get(e),xr=e=>vr.getOption(e),yr=(e,t)=>vr.set(e,t),wr=e=>"img"===ie(e)?1:xr(e).fold((()=>je(e).length),(e=>e.length)),_r=["img","br"],Cr=e=>xr(e).filter((e=>0!==e.trim().length||e.indexOf(" ")>-1)).isSome()||A(_r,ie(e))||(e=>ce(e)&&"false"===be(e,"contenteditable"))(e),Sr=e=>((e,t)=>{const o=e=>{for(let n=0;nAr(e,Cr),Ar=(e,t)=>{const o=e=>{const n=je(e);for(let e=n.length-1;e>=0;e--){const r=n[e];if(t(r))return _.some(r);const i=o(r);if(i.isSome())return i}return _.none()};return o(e)},Mr={scope:["row","col"]},Tr=e=>()=>{const t=Ce.fromTag("td",e.dom);return Ue(t,Ce.fromTag("br",e.dom)),t},Ir=e=>()=>Ce.fromTag("col",e.dom),Er=e=>()=>Ce.fromTag("colgroup",e.dom),Dr=e=>()=>Ce.fromTag("tr",e.dom),Or=(e,t,o)=>{const n=((e,t)=>{const o=Ke(e,t),n=je(qe(e));return We(o,n),o})(e,t);return G(o,((e,t)=>{null===e?ye(n,t):fe(n,t,e)})),n},Nr=e=>e,Lr=(e,t,o)=>{const n=(e,t)=>{((e,t)=>{const o=e.dom,n=t.dom;Dt(o)&&Dt(n)&&(n.style.cssText=o.style.cssText)})(e.element,t),zt(t,"height"),1!==e.colspan&&zt(t,"width")};return{col:o=>{const r=Ce.fromTag(ie(o.element),t.dom);return n(o,r),e(o.element,r),r},colgroup:Er(t),row:Dr(t),cell:r=>{const i=Ce.fromTag(ie(r.element),t.dom),a=o.getOr(["strong","em","b","i","span","font","h1","h2","h3","h4","h5","h6","p","div"]),s=a.length>0?((e,t,o)=>Sr(e).map((n=>{const r=o.join(","),i=ht(n,r,(t=>Me(t,e)));return N(i,((e,t)=>{const o=Qe(t);return Ue(e,o),o}),t)})).getOr(t))(r.element,i,a):i;return Ue(s,Ce.fromTag("br")),n(r,i),((e,t)=>{G(Mr,((o,n)=>xe(e,n).filter((e=>A(o,e))).each((e=>fe(t,n,e)))))})(r.element,i),e(r.element,i),i},replace:Or,colGap:Ir(t),gap:Tr(t)}},Pr=e=>({col:Ir(e),colgroup:Er(e),row:Dr(e),cell:Tr(e),replace:Nr,colGap:Ir(e),gap:Tr(e)}),Rr=e=>t=>t.options.get(e),jr="100%",zr=e=>{var t;const o=e.dom,n=null!==(t=o.getParent(e.selection.getStart(),o.isBlock))&&void 0!==t?t:e.getBody();return Fo(Ce.fromDom(n))+"px"},Br=e=>_.from(e.options.get("table_clone_elements")),Fr=Rr("table_header_type"),Hr=Rr("table_column_resizing"),Ur=e=>"preservetable"===Hr(e),Vr=e=>"resizetable"===Hr(e),Zr=Rr("table_sizing_mode"),Wr=e=>"relative"===Zr(e),Yr=e=>"fixed"===Zr(e),Gr=e=>"responsive"===Zr(e),Xr=Rr("table_resize_bars"),Jr=Rr("table_style_by_css"),Qr=Rr("table_merge_content_on_paste"),qr=e=>{const t=e.options,o=t.get("table_default_attributes");return t.isSet("table_default_attributes")?o:((e,t)=>Gr(e)||Jr(e)?t:Yr(e)?{...t,width:zr(e)}:{...t,width:jr})(e,o)},Kr=e=>{const t=e.options,o=t.get("table_default_styles");return t.isSet("table_default_styles")?o:((e,t)=>Gr(e)||!Jr(e)?t:Yr(e)?{...t,width:zr(e)}:{...t,width:jr})(e,o)},$r=Rr("table_use_colgroups"),ei=Rr("fixed_toolbar_container"),ti=Rr("fixed_toolbar_container_target"),oi=e=>e.inline&&(e=>{var t;if(!e.inline)return _.none();const o=null!==(t=ei(e))&&void 0!==t?t:"";if(o.length>0)return yt(ct(),o);const n=ti(e);return d(n)?_.some(Ce.fromDom(n)):_.none()})(e).isSome(),ni=Rr("ui_mode"),ri=e=>wt(e,"[contenteditable]"),ii=(e,t=!1)=>lt(e)?e.dom.isContentEditable:ri(e).fold(g(t),(e=>"true"===ai(e))),ai=e=>e.dom.contentEditable,si=e=>Ce.fromDom(e.getBody()),li=e=>t=>Me(t,si(e)),ci=e=>{ye(e,"data-mce-style");const t=e=>ye(e,"data-mce-style");E(Xt(e),t),E(Jt(e),t),E(qt(e),t)},di=e=>Ce.fromDom(e.selection.getStart()),ui=e=>e.getBoundingClientRect().width,hi=e=>e.getBoundingClientRect().height,mi=e=>(t,o)=>{const n=t.dom.getStyle(o,e)||t.dom.getAttrib(o,e);return _.from(n).filter(Et)},gi=mi("width"),pi=mi("height"),fi=e=>vt(e,ge("table")).exists(ii),vi=(e,t)=>{const o=t.column,n=t.column+t.colspan-1,r=t.row,i=t.row+t.rowspan-1;return o<=e.finishCol&&n>=e.startCol&&r<=e.finishRow&&i>=e.startRow},bi=(e,t)=>t.column>=e.startCol&&t.column+t.colspan-1<=e.finishCol&&t.row>=e.startRow&&t.row+t.rowspan-1<=e.finishRow,xi=(e,t,o)=>{const n=nn.findItem(e,t,Me),r=nn.findItem(e,o,Me);return n.bind((e=>r.map((t=>{return o=e,n=t,r=Math.min(o.row,n.row),i=Math.min(o.column,n.column),a=Math.max(o.row+o.rowspan-1,n.row+n.rowspan-1),s=Math.max(o.column+o.colspan-1,n.column+n.colspan-1),{startRow:r,startCol:i,finishRow:a,finishCol:s};var o,n,r,i,a,s}))))},yi=(e,t,o)=>xi(e,t,o).bind((t=>((e,t)=>{let o=!0;const n=v(bi,t);for(let r=t.startRow;r<=t.finishRow;r++)for(let i=t.startCol;i<=t.finishCol;i++)o=o&&nn.getAt(e,r,i).exists(n);return o?_.some(t):_.none()})(e,t))),wi=(e,t,o)=>xi(e,t,o).map((t=>{const o=nn.filterItems(e,v(vi,t));return I(o,(e=>e.element))})),_i=(e,t)=>nn.findItem(e,t,((e,t)=>Te(t,e))).map((e=>e.element)),Ci=(e,t,o)=>Qt(e).bind((n=>((e,t,o,n)=>nn.findItem(e,t,Me).bind((t=>{const r=o>0?t.row+t.rowspan-1:t.row,i=n>0?t.column+t.colspan-1:t.column;return nn.getAt(e,r+o,i+n).map((e=>e.element))})))(Ai(n),e,t,o))),Si=(e,t,o)=>{const n=Ai(e);return wi(n,t,o)},ki=(e,t,o,n,r)=>{const i=Ai(e),a=Me(e,o)?_.some(t):_i(i,t),s=Me(e,r)?_.some(n):_i(i,n);return a.bind((e=>s.bind((t=>wi(i,e,t)))))},Ai=nn.fromTable;var Mi=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","li","table","thead","tbody","tfoot","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"],Ti=()=>({up:g({selector:bt,closest:wt,predicate:ft,all:Le}),down:g({selector:gt,predicate:ut}),styles:g({get:Pt,getRaw:jt,set:Nt,remove:zt}),attrs:g({get:be,set:fe,remove:ye,copyTo:(e,t)=>{const o=we(e);ve(t,o)}}),insert:g({before:Be,after:Fe,afterAll:Ze,append:Ue,appendAll:We,prepend:He,wrap:Ve}),remove:g({unwrap:Xe,remove:Ge}),create:g({nu:Ce.fromTag,clone:e=>Ce.fromDom(e.dom.cloneNode(!1)),text:Ce.fromText}),query:g({comparePosition:(e,t)=>e.dom.compareDocumentPosition(t.dom),prevSibling:Pe,nextSibling:Re}),property:g({children:je,name:ie,parent:Oe,document:e=>De(e).dom,isText:ue,isComment:le,isElement:de,isSpecial:e=>{const t=ie(e);return A(["script","noscript","iframe","noframes","noembed","title","style","textarea","xmp"],t)},getLanguage:e=>de(e)?xe(e,"lang"):_.none(),getText:br,setText:yr,isBoundary:e=>!!de(e)&&("body"===ie(e)||A(Mi,ie(e))),isEmptyTag:e=>!!de(e)&&A(["br","img","hr","input"],ie(e)),isNonEditable:e=>de(e)&&"false"===be(e,"contenteditable")}),eq:Me,is:Ie});const Ii=(e,t,o,n)=>{const r=t(e,o);return N(n,((o,n)=>{const r=t(e,n);return Ei(e,o,r)}),r)},Ei=(e,t,o)=>t.bind((t=>o.filter(v(e.eq,t)))),Di=(e,t,o)=>o.length>0?((e,t,o,n)=>n(e,t,o[0],o.slice(1)))(e,t,o,Ii):_.none(),Oi=(e,t,o,n=y)=>{const r=[t].concat(e.up().all(t)),i=[o].concat(e.up().all(o)),a=e=>R(e,n).fold((()=>e),(t=>e.slice(0,t+1))),s=a(r),l=a(i),c=P(s,(t=>M(l,((e,t)=>v(e.eq,t))(e,t))));return{firstpath:s,secondpath:l,shared:c}},Ni=Ti(),Li=(e,t)=>Di(Ni,((t,o)=>e(o)),t),Pi=e=>bt(e,"table"),Ri=(e,t,o)=>{const n=e=>t=>void 0!==o&&o(t)||Me(t,e);return Me(e,t)?_.some({boxes:_.some([e]),start:e,finish:t}):Pi(e).bind((r=>Pi(t).bind((i=>{if(Me(r,i))return _.some({boxes:Si(r,e,t),start:e,finish:t});if(Te(r,i)){const o=ht(t,"td,th",n(r)),a=o.length>0?o[o.length-1]:t;return _.some({boxes:ki(r,e,r,t,i),start:e,finish:a})}if(Te(i,r)){const o=ht(e,"td,th",n(i)),a=o.length>0?o[o.length-1]:e;return _.some({boxes:ki(i,e,r,t,i),start:e,finish:a})}return((e,t,o)=>Oi(Ni,e,t,o))(e,t).shared.bind((a=>wt(a,"table",o).bind((o=>{const a=ht(t,"td,th",n(o)),s=a.length>0?a[a.length-1]:t,l=ht(e,"td,th",n(o)),c=l.length>0?l[l.length-1]:e;return _.some({boxes:ki(o,e,r,t,i),start:c,finish:s})}))))}))))},ji=(e,t)=>{const o=gt(e,t);return o.length>0?_.some(o):_.none()},zi=(e,t,o)=>yt(e,t).bind((t=>yt(e,o).bind((e=>Li(Pi,[t,e]).map((o=>({first:t,last:e,table:o}))))))),Bi=(e,t,o,n,r)=>((e,t)=>P(e,(e=>Se(e,t))))(e,r).bind((e=>Ci(e,t,o).bind((e=>((e,t)=>bt(e,"table").bind((o=>yt(o,t).bind((t=>Ri(t,e).bind((e=>e.boxes.map((t=>({boxes:t,start:e.start,finish:e.finish}))))))))))(e,n))))),Fi=(e,t)=>ji(e,t),Hi=(e,t,o)=>zi(e,t,o).bind((t=>{const o=t=>Me(e,t),n="thead,tfoot,tbody,table",r=bt(t.first,n,o),i=bt(t.last,n,o);return r.bind((e=>i.bind((o=>Me(e,o)?((e,t,o)=>{const n=Ai(e);return yi(n,t,o)})(t.table,t.first,t.last):_.none()))))})),Ui=p,Vi=e=>{const t=(e,t)=>xe(e,t).exists((e=>parseInt(e,10)>1));return e.length>0&&B(e,(e=>t(e,"rowspan")||t(e,"colspan")))?_.some(e):_.none()},Zi=(e,t,o)=>t.length<=1?_.none():Hi(e,o.firstSelectedSelector,o.lastSelectedSelector).map((e=>({bounds:e,cells:t}))),Wi="data-mce-selected",Yi="td["+Wi+"],th["+Wi+"]",Gi="["+Wi+"]",Xi="data-mce-first-selected",Ji="td["+Xi+"],th["+Xi+"]",Qi="data-mce-last-selected",qi="td["+Qi+"],th["+Qi+"]",Ki=Gi,$i={selected:Wi,selectedSelector:Yi,firstSelected:Xi,firstSelectedSelector:Ji,lastSelected:Qi,lastSelectedSelector:qi},ea=(e,t,o)=>({element:o,mergable:Zi(t,e,$i),unmergable:Vi(e),selection:Ui(e)}),ta=e=>(t,o)=>{const n=ie(t),r="col"===n||"colgroup"===n?Qt(i=t).bind((e=>Fi(e,$i.firstSelectedSelector))).fold(g(i),(e=>e[0])):t;var i;return wt(r,e,o)},oa=ta("th,td,caption"),na=ta("th,td"),ra=e=>{return t=e.model.table.getSelectedCells(),I(t,Ce.fromDom);var t},ia=(e,t)=>{const o=e.getDoc(),n=it(Ce.fromDom(e.getBody())),r=Ce.fromTag("div",o);fe(r,"data-mce-bogus","all"),Lt(r,{position:"fixed",left:"-9999999px",top:"0",overflow:"hidden",opacity:"0"});const i=(e=>rt(e)?e:Ce.fromDom(De(e).dom.body))(n);We(r,t),Ue(i,r);const a=r.dom.innerText;return Ge(r),a},aa=(e,t)=>{e.on("BeforeGetContent",(t=>{const o=o=>{t.preventDefault(),(e=>Qt(e[0]).map((e=>{const t=fr(e,Ki);return ci(t),[t]})))(o).each((o=>{const n="text"===t.format?ia(e,o):((e,t)=>I(t,(t=>e.selection.serializer.serialize(t.dom,{}))).join(""))(e,o);t.content=n}))};if(!0===t.selection){const t=(e=>O(ra(e),(e=>Se(e,$i.selectedSelector))))(e);t.length>=1&&o(t)}})),e.on("BeforeSetContent",(o=>{if(!0===o.selection&&!0===o.paste){const n=ra(e);U(n).each((n=>{Qt(n).each((r=>{const i=O(((e,t)=>{const o=(t||document).createElement("div");return o.innerHTML=e,je(Ce.fromDom(o))})(o.content),(e=>"meta"!==ie(e))),a=ge("table");if(Qr(e)&&1===i.length&&a(i[0])){o.preventDefault();const a=Ce.fromDom(e.getDoc()),s=Pr(a),l=((e,t,o)=>({element:e,clipboard:t,generators:o}))(n,i[0],s);t.pasteCells(r,l).each((()=>{e.focus()}))}}))}))}}))},sa=(e,t)=>({element:e,offset:t}),la=(e,t,o)=>e.property().isText(t)&&0===e.property().getText(t).trim().length||e.property().isComment(t)?o(t).bind((t=>la(e,t,o).orThunk((()=>_.some(t))))):_.none(),ca=(e,t)=>{if(e.property().isText(t))return e.property().getText(t).length;return e.property().children(t).length},da=(e,t)=>{const o=la(e,t,e.query().prevSibling).getOr(t);if(e.property().isText(o))return sa(o,ca(e,o));const n=e.property().children(o);return n.length>0?da(e,n[n.length-1]):sa(o,ca(e,o))},ua=da,ha=Ti(),ma=(e,t)=>{if(!Ht(e)){const o=(e=>Gn(e).bind((e=>Pn(e,["fixed","relative","empty"]))))(e);o.each((o=>{const n=o.value/2;qn(e,n,o.unit),qn(t,n,o.unit)}))}},ga=e=>I(e,g(0)),pa=(e,t,o,n,r)=>r(e.slice(0,t)).concat(n).concat(r(e.slice(o))),fa=e=>(t,o,n,r)=>{if(e(n)){const e=Math.max(r,t[o]-Math.abs(n)),i=Math.abs(e-t[o]);return n>=0?i:-i}return n},va=fa((e=>e<0)),ba=fa(w),xa=()=>{const e=(e,t,o,n)=>{const r=(100+o)/100,i=Math.max(n,(e[t]+o)/r);return I(e,((e,o)=>(o===t?i:e/r)-e))},t=(t,o,n,r,i,a)=>a?e(t,o,r,i):((e,t,o,n,r)=>{const i=va(e,t,n,r);return pa(e,t,o+1,[i,0],ga)})(t,o,n,r,i);return{resizeTable:(e,t)=>e(t),clampTableDelta:va,calcLeftEdgeDeltas:t,calcMiddleDeltas:(e,o,n,r,i,a,s)=>t(e,n,r,i,a,s),calcRightEdgeDeltas:(t,o,n,r,i,a)=>{if(a)return e(t,n,r,i);{const e=va(t,n,r,i);return ga(t.slice(0,n)).concat([e])}},calcRedestributedWidths:(e,t,o,n)=>{if(n){const n=(t+o)/t,r=I(e,(e=>e/n));return{delta:100*n-100,newSizes:r}}return{delta:o,newSizes:e}}}},ya=()=>{const e=(e,t,o,n,r)=>{const i=ba(e,n>=0?o:t,n,r);return pa(e,t,o+1,[i,-i],ga)};return{resizeTable:(e,t,o)=>{o&&e(t)},clampTableDelta:(e,t,o,n,r)=>{if(r){if(o>=0)return o;{const t=L(e,((e,t)=>e+t-n),0);return Math.max(-t,o)}}return va(e,t,o,n)},calcLeftEdgeDeltas:e,calcMiddleDeltas:(t,o,n,r,i,a)=>e(t,n,r,i,a),calcRightEdgeDeltas:(e,t,o,n,r,i)=>{if(i)return ga(e);{const t=n/e.length;return I(e,g(t))}},calcRedestributedWidths:(e,t,o,n)=>({delta:0,newSizes:e})}},wa=e=>nn.fromTable(e).grid,_a=ge("th"),Ca=e=>B(e,(e=>_a(e.element))),Sa=(e,t)=>e&&t?"sectionCells":e?"section":"cells",ka=e=>{const t="thead"===e.section,o=_t(Aa(e.cells),"th");return"tfoot"===e.section?{type:"footer"}:t||o?{type:"header",subType:Sa(t,o)}:{type:"body"}},Aa=e=>{const t=O(e,(e=>_a(e.element)));return 0===t.length?_.some("td"):t.length===e.length?_.some("th"):_.none()},Ma=(e,t,o)=>ot(o(e.element,t),!0,e.isLocked),Ta=(e,t)=>e.section!==t?nt(e.element,e.cells,t,e.isNew):e,Ia=()=>({transformRow:Ta,transformCell:(e,t,o)=>{const n=o(e.element,t),r="td"!==ie(n)?((e,t)=>{const o=Ke(e,t);Fe(e,o);const n=je(e);return We(o,n),Ge(e),o})(n,"td"):n;return ot(r,e.isNew,e.isLocked)}}),Ea=()=>({transformRow:Ta,transformCell:Ma}),Da=()=>({transformRow:(e,t)=>Ta(e,"thead"===t?"tbody":t),transformCell:Ma}),Oa=(e,t)=>{const o=(e=>Z(e.all,(e=>{const t=ka(e);return"header"===t.type?_.from(t.subType):_.none()})))(nn.fromTable(e)).getOr(t);switch(o){case"section":return Ia();case"sectionCells":return Ea();case"cells":return Da()}},Na=Ia,La=Ea,Pa=Da,Ra=()=>({transformRow:p,transformCell:Ma}),ja=(e,t,o,n)=>{o===n?ye(e,t):fe(e,t,o)},za=(e,t,o)=>{V(mt(e,t)).fold((()=>He(e,o)),(e=>Fe(e,o)))},Ba=(e,t)=>{const o=[],n=[],r=e=>I(e,(e=>{e.isNew&&o.push(e.element);const t=e.element;return Ye(t),E(e.cells,(e=>{e.isNew&&n.push(e.element),ja(e.element,"colspan",e.colspan,1),ja(e.element,"rowspan",e.rowspan,1),Ue(t,e.element)})),t})),i=e=>z(e,(e=>I(e.cells,(e=>(ja(e.element,"span",e.colspan,1),e.element))))),a=(t,o)=>{const n=((e,t)=>{const o=xt(e,t).getOrThunk((()=>{const o=Ce.fromTag(t,Ee(e).dom);return"thead"===t?za(e,"caption,colgroup",o):"colgroup"===t?za(e,"caption",o):Ue(e,o),o}));return Ye(o),o})(e,o),a=("colgroup"===o?i:r)(t);We(n,a)},s=(t,o)=>{t.length>0?a(t,o):(t=>{xt(e,t).each(Ge)})(o)},l=[],c=[],d=[],u=[];return E(t,(e=>{switch(e.section){case"thead":l.push(e);break;case"tbody":c.push(e);break;case"tfoot":d.push(e);break;case"colgroup":u.push(e)}})),s(u,"colgroup"),s(l,"thead"),s(c,"tbody"),s(d,"tfoot"),{newRows:o,newCells:n}},Fa=(e,t)=>{if(0===e.length)return 0;const o=e[0];return R(e,(e=>!t(o.element,e.element))).getOr(e.length)},Ha=(e,t,o,n)=>{const r=((e,t)=>e[t])(e,t),i="colgroup"===r.section,a=Fa(r.cells.slice(o),n),s=i?1:Fa(((e,t)=>I(e,(e=>Yo(e,t))))(e.slice(t),o),n);return{colspan:a,rowspan:s}},Ua=(e,t)=>{const o=I(e,(e=>I(e.cells,y)));return I(e,((n,r)=>{const i=z(n.cells,((n,i)=>{if(!1===o[r][i]){const d=Ha(e,r,i,t);return((e,t,n,r)=>{for(let i=e;i({element:e,cells:t,section:o,isNew:n}))(n.element,i,n.section,n.isNew)}))},Va=(e,t,o)=>{const n=[];E(e.colgroups,(r=>{const i=[];for(let n=0;not(e.element,o,!1))).getOrThunk((()=>ot(t.colGap(),!0,!1)));i.push(r)}n.push(nt(r.element,i,"colgroup",o))}));for(let r=0;rot(e.element,o,e.isLocked))).getOrThunk((()=>ot(t.gap(),!0,!1)));i.push(a)}const a=e.all[r],s=nt(a.element,i,a.section,o);n.push(s)}return n},Za=e=>Ua(e,Me),Wa=(e,t)=>Z(e.all,(e=>P(e.cells,(e=>Me(t,e.element))))),Ya=(e,t,o)=>{const n=I(t.selection,(t=>Gt(t).bind((t=>Wa(e,t))).filter(o))),r=Ct(n);return St(r.length>0,r)},Ga=(e,t,o,n,r)=>(i,a,s,l)=>{const c=nn.fromTable(i),d=_.from(null==l?void 0:l.section).getOrThunk(Ra);return t(c,a).map((t=>{const o=((e,t)=>Va(e,t,!1))(c,s),n=e(o,t,Me,r(s),d),i=$o(n.grid);return{info:t,grid:Za(n.grid),cursor:n.cursor,lockedColumns:i}})).bind((e=>{const t=Ba(i,e.grid),r=_.from(null==l?void 0:l.sizing).getOrThunk((()=>hr(i))),a=_.from(null==l?void 0:l.resize).getOrThunk(ya);return o(i,e.grid,e.info,{sizing:r,resize:a,section:d}),n(i),ye(i,qo),e.lockedColumns.length>0&&fe(i,qo,e.lockedColumns.join(",")),_.some({cursor:e.cursor,newRows:t.newRows,newCells:t.newCells})}))},Xa=(e,t)=>Ya(e,t,w).map((e=>({cells:e,generators:t.generators,clipboard:t.clipboard}))),Ja=(e,t)=>Ya(e,t,w),Qa=(e,t)=>Ya(e,t,(e=>!e.isLocked)),qa=(e,t)=>B(t,(t=>((e,t)=>Wa(e,t).exists((e=>!e.isLocked)))(e,t))),Ka=(e,t,o,n)=>{const r=Jo(e).rows;let i=!0;for(let e=0;e{const r=Jo(e).rows;if(t>0&&tL(e,((e,o)=>M(e,(e=>t(e.element,o.element)))?e:e.concat([o])),[]))(r[t-1].cells,o);E(e,(e=>{let i=_.none();for(let a=t;a{Zo(s,t,ot(e,!0,l.isLocked))})))}}))}return e},es=e=>{const t=t=>t(e),o=g(e),n=()=>r,r={tag:!0,inner:e,fold:(t,o)=>o(e),isValue:w,isError:y,map:t=>os.value(t(e)),mapError:n,bind:t,exists:t,forall:t,getOr:o,or:n,getOrThunk:o,orThunk:n,getOrDie:o,each:t=>{t(e)},toOptional:()=>_.some(e)};return r},ts=e=>{const t=()=>o,o={tag:!1,inner:e,fold:(t,o)=>t(e),isValue:y,isError:w,map:t,mapError:t=>os.error(t(e)),bind:t,exists:y,forall:w,getOr:p,or:p,getOrThunk:x,orThunk:x,getOrDie:(n=String(e),()=>{throw new Error(n)}),each:m,toOptional:_.none};var n;return o},os={value:es,error:ts,fromOption:(e,t)=>e.fold((()=>ts(t)),es)},ns=(e,t)=>({rowDelta:0,colDelta:Xo(e[0])-Xo(t[0])}),rs=(e,t)=>({rowDelta:e.length-t.length,colDelta:0}),is=(e,t,o,n)=>{const r="colgroup"===t.section?o.col:o.cell;return T(e,(e=>ot(r(),!0,n(e))))},as=(e,t,o,n)=>{const r=e[e.length-1];return e.concat(T(t,(()=>{const e="colgroup"===r.section?o.colgroup:o.row,t=Qo(r,e,p),i=is(t.cells.length,t,o,(e=>$(n,e.toString())));return Wo(t,i)})))},ss=(e,t,o,n)=>I(e,(e=>{const r=is(t,e,o,y);return Uo(e,n,r)})),ls=(e,t,o)=>{const n=t.colDelta<0?ss:p,r=t.rowDelta<0?as:p,i=$o(e),a=Xo(e[0]),s=M(i,(e=>e===a-1)),l=n(e,Math.abs(t.colDelta),o,s?a-1:a),c=$o(l);return r(l,Math.abs(t.rowDelta),o,F(c,w))},cs=(e,t,o,n)=>{const r=v(n,Yo(e[t],o).element),i=e[t];return e.length>1&&Xo(i)>1&&(o>0&&r(Go(i,o-1))||o0&&r(Go(e[t-1],o))||tO(o,(o=>o>=e.column&&o<=Xo(t[0])+e.column)),us=(e,t,o,n,r)=>{const i=$o(t),a=((e,t,o)=>{const n=Xo(t[0]),r=Jo(t).cols.length+e.row,i=T(n-e.column,(t=>t+e.column)),a=P(i,(e=>B(o,(t=>t!==e)))).getOr(n-1);return{row:r,column:a}})(e,t,i),s=Jo(o).rows,l=ds(a,s,i),c=((e,t,o)=>{if(e.row>=t.length||e.column>Xo(t[0]))return os.error("invalid start address out of table bounds, row: "+e.row+", column: "+e.column);const n=t.slice(e.row),r=n[0].cells.slice(e.column),i=Xo(o[0]),a=o.length;return os.value({rowDelta:n.length-a,colDelta:r.length-i})})(a,t,s);return c.map((e=>{const o={...e,colDelta:e.colDelta-l.length},i=ls(t,o,n),c=$o(i),d=ds(a,s,c);return((e,t,o,n,r,i)=>{const a=e.row,s=e.column,l=a+o.length,c=s+Xo(o[0])+i.length,d=F(i,w);for(let e=a;e{((e,t,o,n)=>{t>0&&t{const r=e.cells[t-1];let i=0;const a=n();for(;e.cells.length>t+i&&o(r.element,e.cells[t+i].element);)Zo(e,t+i,ot(a,!0,e.cells[t+i].isLocked)),i++}))})(t,e,r,n.cell);const i=rs(o,t),a=ls(o,i,n),s=rs(t,a),l=ls(t,s,n);return I(l,((t,o)=>Uo(t,e,a[o].cells)))},ms=(e,t,o,n,r)=>{$a(t,e,r,n.cell);const i=$o(t),a=ns(t,o),s={...a,colDelta:a.colDelta-i.length},l=ls(t,s,n),{cols:c,rows:d}=Jo(l),u=$o(l),h=ns(o,t),m={...h,colDelta:h.colDelta+u.length},g=((e,t,o)=>I(e,(e=>L(o,((o,n)=>{const r=is(1,e,t,w)[0];return Vo(o,n,r)}),e))))(o,n,u),p=ls(g,m,n);return[...c,...d.slice(0,e),...p,...d.slice(e,d.length)]},gs=(e,t,o,n,r)=>{const{rows:i,cols:a}=Jo(e),s=i.slice(0,t),l=i.slice(t),c=((e,t,o,n)=>Qo(e,(e=>n(e,o)),t))(i[o],((e,o)=>t>0&&tI(e,(e=>{const i=t>0&&t{if("colgroup"!==o&&n)return Yo(e,t);{const t=Yo(e,r);return ot(a(t.element,i),!0,!1)}})(e,t,e.section,i,o,n,r);return Vo(e,t,a)})),fs=(e,t,o,n)=>((e,t,o,n)=>void 0!==Go(e[t],o)&&t>0&&n(Go(e[t-1],o),Go(e[t],o)))(e,t,o,n)||((e,t,o)=>t>0&&o(Go(e,t-1),Go(e,t)))(e[t],o,n),vs=(e,t,o,n)=>{const r=e=>"row"===e?(e=>Ft(e,"rowspan")>1)(t):Ht(t),i=e=>r(e)?`${e}group`:e;if(e)return _a(t)?i(o):null;if(n&&_a(t)){return i("row"===o?"col":"row")}return null},bs=(e,t,o)=>ot(o(e.element,t),!0,e.isLocked),xs=(e,t,o,n,r,i,a)=>I(e,((e,s)=>((e,t)=>{const o=e.cells,n=I(o,t);return nt(e.element,n,e.section,e.isNew)})(e,((e,l)=>{if((e=>M(t,(t=>o(e.element,t.element))))(e)){const t=a(e,s,l)?r(e,o,n):e;return i(t,s,l).each((e=>{var o,n;o=t.element,n={scope:_.from(e)},G(n,((e,t)=>{e.fold((()=>{ye(o,t)}),(e=>{pe(o.dom,t,e)}))}))})),t}return e})))),ys=(e,t,o)=>z(e,((n,r)=>fs(e,r,t,o)?[]:[Yo(n,t)])),ws=(e,t,o,n,r)=>{const i=Jo(e).rows,a=z(t,(e=>ys(i,e,n))),s=I(i,(e=>Ca(e.cells))),l=((e,t)=>B(t,p)&&Ca(e)?w:(e,o,n)=>!("th"===ie(e.element)&&t[o]))(a,s),c=((e,t)=>(o,n)=>_.some(vs(e,o.element,"row",t[n])))(o,s);return xs(e,a,n,r,bs,c,l)},_s=(e,t,o,n,r,i,a)=>{const{cols:s,rows:l}=Jo(e),c=l[t[0]],d=z(t,(e=>((e,t,o)=>{const n=e[t];return z(n.cells,((n,r)=>fs(e,t,r,o)?[]:[n]))})(l,e,r))),u=I(c.cells,((e,t)=>Ca(ys(l,t,r)))),h=[...l];E(t,(e=>{h[e]=a.transformRow(l[e],o)}));const m=[...s,...h],g=((e,t)=>B(t,p)&&Ca(e.cells)?w:(e,o,n)=>!("th"===ie(e.element)&&t[n]))(c,u),f=((e,t)=>(o,n,r)=>_.some(vs(e,o.element,"col",t[r])))(n,u);return xs(m,d,r,i,a.transformCell,f,g)},Cs=(e,t,o,n)=>{const r=Jo(e).rows,i=I(t,(e=>Yo(r[e.row],e.column)));return xs(e,i,o,n,bs,_.none,w)},Ss=e=>{if(!a(e))throw new Error("cases must be an array");if(0===e.length)throw new Error("there must be at least one case");const t=[],o={};return E(e,((n,r)=>{const i=W(n);if(1!==i.length)throw new Error("one and only one name per case");const s=i[0],l=n[s];if(void 0!==o[s])throw new Error("duplicate key detected:"+s);if("cata"===s)throw new Error("cannot have a case named cata (sorry)");if(!a(l))throw new Error("case arguments must be an array");t.push(s),o[s]=(...o)=>{const n=o.length;if(n!==l.length)throw new Error("Wrong number of arguments to case "+s+". Expected "+l.length+" ("+l+"), got "+n);return{fold:(...t)=>{if(t.length!==e.length)throw new Error("Wrong number of arguments to fold. Expected "+e.length+", got "+t.length);return t[r].apply(null,o)},match:e=>{const n=W(e);if(t.length!==n.length)throw new Error("Wrong number of arguments to match. Expected: "+t.join(",")+"\nActual: "+n.join(","));if(!B(t,(e=>A(n,e))))throw new Error("Not all branches were specified when using match. Specified: "+n.join(", ")+"\nRequired: "+t.join(", "));return e[s].apply(null,o)},log:e=>{console.log(e,{constructors:t,constructor:s,params:o})}}}})),o},ks={...Ss([{none:[]},{only:["index"]},{left:["index","next"]},{middle:["prev","index","next"]},{right:["prev","index"]}])},As=(e,t,o,n,r)=>{const i=e.slice(0),a=((e,t)=>0===e.length?ks.none():1===e.length?ks.only(0):0===t?ks.left(0,1):t===e.length-1?ks.right(t-1,t):t>0&&tn.singleColumnWidth(i[e],o)),((e,t)=>r.calcLeftEdgeDeltas(i,e,t,o,n.minCellWidth(),n.isRelative)),((e,t,a)=>r.calcMiddleDeltas(i,e,t,a,o,n.minCellWidth(),n.isRelative)),((e,t)=>r.calcRightEdgeDeltas(i,e,t,o,n.minCellWidth(),n.isRelative)))},Ms=(e,t)=>nn.hasColumns(e)?((e,t)=>{const o=nn.justColumns(e);return I(o,((e,o)=>({element:e.element,width:t[o],colspan:e.colspan})))})(e,t):((e,t)=>{const o=nn.justCells(e);return I(o,(e=>{const o=((e,t,o)=>{let n=0;for(let r=e;r{const n=Ms(e,t);E(n,(e=>{o.setElementWidth(e.element,e.width)}))},Is=(e,t,o,n,r)=>{const i=nn.fromTable(e),a=r.getCellDelta(t),s=r.getWidths(i,r),l=o===i.grid.columns-1,c=n.clampTableDelta(s,o,a,r.minCellWidth(),l),d=As(s,o,c,r,n),u=I(d,((e,t)=>e+s[t]));Ts(i,u,r),n.resizeTable(r.adjustTableWidth,c,l)},Es=(e,t,o)=>{const n=nn.fromTable(e),r=((e,t)=>sr(e,t,Qn,(e=>e.getOrThunk(Zt))))(n,e),i=I(r,((e,n)=>o===n?Math.max(t+e,Zt()):e)),a=((e,t)=>I(e.all,((e,o)=>({element:e.element,height:t[o]}))))(n,i);E(a,(e=>{Vn(e.element,e.height)})),E(nn.justCells(n),(e=>{(e=>{zt(e,"height")})(e.element)}));const s=N(i,((e,t)=>e+t),0);Vn(e,s)},Ds=e=>L(e,((e,t)=>M(e,(e=>e.column===t.column))?e:e.concat([t])),[]).sort(((e,t)=>e.column-t.column)),Os=ge("col"),Ns=ge("colgroup"),Ls=e=>"tr"===ie(e)||Ns(e),Ps=e=>({element:e,colspan:Bt(e,"colspan",1),rowspan:Bt(e,"rowspan",1)}),Rs=e=>xe(e,"scope").map((e=>e.substr(0,3))),js=(e,t=Ps)=>{const o=o=>{if(Ls(o))return Ns((r={element:o}).element)?e.colgroup(r):e.row(r);{const r=o,i=(t=>Os(t.element)?e.col(t):e.cell(t))(t(r));return n=_.some({item:r,replacement:i}),i}var r};let n=_.none();return{getOrInit:(e,t)=>n.fold((()=>o(e)),(n=>t(e,n.item)?n.replacement:o(e)))}},zs=e=>t=>{const o=[],n=n=>{const r="td"===e?{scope:null}:{},i=t.replace(n,e,r);return o.push({item:n,sub:i}),i};return{replaceOrInit:(e,t)=>{if(Ls(e)||Os(e))return e;{const r=e;return((e,t)=>P(o,(o=>t(o.item,e))))(r,t).fold((()=>n(r)),(o=>t(e,o.item)?o.sub:n(r)))}}}},Bs=e=>({unmerge:t=>{const o=Rs(t);return o.each((e=>fe(t,"scope",e))),()=>{const n=e.cell({element:t,colspan:1,rowspan:1});return zt(n,"width"),zt(t,"width"),o.each((e=>fe(n,"scope",e))),n}},merge:e=>(zt(e[0],"width"),(()=>{const t=Ct(I(e,Rs));if(0===t.length)return _.none();{const e=t[0],o=["row","col"];return M(t,(t=>t!==e&&A(o,t)))?_.none():_.from(e)}})().fold((()=>ye(e[0],"scope")),(t=>fe(e[0],"scope",t+"group"))),g(e[0]))}),Fs=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","table","thead","tfoot","tbody","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"],Hs=Ti(),Us=e=>((e,t)=>{const o=e.property().name(t);return A(Fs,o)})(Hs,e),Vs=e=>((e,t)=>{const o=e.property().name(t);return A(["ol","ul"],o)})(Hs,e),Zs=e=>((e,t)=>A(["br","img","hr","input"],e.property().name(t)))(Hs,e),Ws=e=>{const t=ge("br"),o=e=>kr(e).bind((o=>{const n=Re(o).map((e=>!!Us(e)||!!Zs(e)&&"img"!==ie(e))).getOr(!1);return Oe(o).map((r=>!0===n||(e=>"li"===ie(e)||ft(e,Vs).isSome())(r)||t(o)||Us(r)&&!Me(e,r)?[]:[Ce.fromTag("br")]))})).getOr([]),n=(()=>{const n=z(e,(e=>{const n=je(e);return(e=>B(e,(e=>t(e)||ue(e)&&0===br(e).trim().length)))(n)?[]:n.concat(o(e))}));return 0===n.length?[Ce.fromTag("br")]:n})();Ye(e[0]),We(e[0],n)},Ys=e=>ii(e,!0),Gs=e=>{0===Xt(e).length&&Ge(e)},Xs=(e,t)=>({grid:e,cursor:t}),Js=(e,t,o)=>{var n,r;const i=Jo(e).rows;return _.from(null===(r=null===(n=i[t])||void 0===n?void 0:n.cells[o])||void 0===r?void 0:r.element).filter(Ys).orThunk((()=>(e=>Z(e,(e=>Z(e.cells,(e=>{const t=e.element;return St(Ys(t),t)})))))(i)))},Qs=(e,t,o)=>{const n=Js(e,t,o);return Xs(e,n)},qs=e=>L(e,((e,t)=>M(e,(e=>e.row===t.row))?e:e.concat([t])),[]).sort(((e,t)=>e.row-t.row)),Ks=(e,t)=>(o,n,r,i,a)=>{const s=qs(n),l=I(s,(e=>e.row)),c=_s(o,l,e,t,r,i.replaceOrInit,a);return Qs(c,n[0].row,n[0].column)},$s=Ks("thead",!0),el=Ks("tbody",!1),tl=Ks("tfoot",!1),ol=(e,t,o)=>{const n=((e,t)=>$t(e,(()=>t)))(e,o.section),r=nn.generate(n);return Va(r,t,!0)},nl=(e,t,o,n)=>((e,t,o,n)=>{const r=nn.generate(t),i=n.getWidths(r,n);Ts(r,i,n)})(0,t,0,n.sizing),rl=(e,t,o,n)=>((e,t,o,n,r)=>{const i=nn.generate(t),a=n.getWidths(i,n),s=n.pixelWidth(),{newSizes:l,delta:c}=r.calcRedestributedWidths(a,s,o.pixelDelta,n.isRelative);Ts(i,l,n),n.adjustTableWidth(c)})(0,t,o,n.sizing,n.resize),il=(e,t)=>M(t,(e=>0===e.column&&e.isLocked)),al=(e,t)=>M(t,(t=>t.column+t.colspan>=e.grid.columns&&t.isLocked)),sl=(e,t)=>{const o=rn(e),n=Ds(t);return L(n,((e,t)=>e+o[t.column].map(Bo).getOr(0)),0)},ll=e=>(t,o)=>Ja(t,o).filter((o=>!(e?il:al)(t,o))).map((e=>({details:e,pixelDelta:sl(t,e)}))),cl=e=>(t,o)=>Xa(t,o).filter((o=>!(e?il:al)(t,o.cells))),dl=zs("th"),ul=zs("td"),hl=Ga(((e,t,o,n)=>{const r=t[0].row,i=qs(t),a=N(i,((e,t)=>({grid:gs(e.grid,r,t.row+e.delta,o,n.getOrInit),delta:e.delta+1})),{grid:e,delta:0}).grid;return Qs(a,r,t[0].column)}),Ja,m,m,js),ml=Ga(((e,t,o,n)=>{const r=qs(t),i=r[r.length-1],a=i.row+i.rowspan,s=N(r,((e,t)=>gs(e,a,t.row,o,n.getOrInit)),e);return Qs(s,a,t[0].column)}),Ja,m,m,js),gl=Ga(((e,t,o,n)=>{const r=t.details,i=Ds(r),a=i[0].column,s=N(i,((e,t)=>({grid:ps(e.grid,a,t.column+e.delta,o,n.getOrInit),delta:e.delta+1})),{grid:e,delta:0}).grid;return Qs(s,r[0].row,a)}),ll(!0),rl,m,js),pl=Ga(((e,t,o,n)=>{const r=t.details,i=r[r.length-1],a=i.column+i.colspan,s=Ds(r),l=N(s,((e,t)=>ps(e,a,t.column,o,n.getOrInit)),e);return Qs(l,r[0].row,a)}),ll(!1),rl,m,js),fl=Ga(((e,t,o,n)=>{const r=Ds(t.details),i=((e,t)=>z(e,(e=>{const o=e.cells,n=N(t,((e,t)=>t>=0&&t0?[nt(e.element,n,e.section,e.isNew)]:[]})))(e,I(r,(e=>e.column))),a=i.length>0?i[0].cells.length-1:0;return Qs(i,r[0].row,Math.min(r[0].column,a))}),((e,t)=>Qa(e,t).map((t=>({details:t,pixelDelta:-sl(e,t)})))),rl,Gs,js),vl=Ga(((e,t,o,n)=>{const r=qs(t),i=((e,t,o)=>{const{rows:n,cols:r}=Jo(e);return[...r,...n.slice(0,t),...n.slice(o+1)]})(e,r[0].row,r[r.length-1].row),a=Math.max(Jo(i).rows.length-1,0);return Qs(i,Math.min(t[0].row,a),t[0].column)}),Ja,m,Gs,js),bl=Ga(((e,t,o,n)=>{const r=Ds(t),i=I(r,(e=>e.column)),a=ws(e,i,!0,o,n.replaceOrInit);return Qs(a,t[0].row,t[0].column)}),Qa,m,m,dl),xl=Ga(((e,t,o,n)=>{const r=Ds(t),i=I(r,(e=>e.column)),a=ws(e,i,!1,o,n.replaceOrInit);return Qs(a,t[0].row,t[0].column)}),Qa,m,m,ul),yl=Ga($s,Ja,m,m,dl),wl=Ga(el,Ja,m,m,ul),_l=Ga(tl,Ja,m,m,ul),Cl=Ga(((e,t,o,n)=>{const r=Cs(e,t,o,n.replaceOrInit);return Qs(r,t[0].row,t[0].column)}),Qa,m,m,dl),Sl=Ga(((e,t,o,n)=>{const r=Cs(e,t,o,n.replaceOrInit);return Qs(r,t[0].row,t[0].column)}),Qa,m,m,ul),kl=Ga(((e,t,o,n)=>{const r=t.cells;Ws(r);const i=((e,t,o,n)=>{const r=Jo(e).rows;if(0===r.length)return e;for(let e=t.startRow;e<=t.finishRow;e++)for(let o=t.startCol;o<=t.finishCol;o++){const t=r[e],i=Yo(t,o).isLocked;Zo(t,o,ot(n(),!1,i))}return e})(e,t.bounds,0,n.merge(r));return Xs(i,_.from(r[0]))}),((e,t)=>((e,t)=>t.mergable)(0,t).filter((t=>qa(e,t.cells)))),nl,m,Bs),Al=Ga(((e,t,o,n)=>{const r=N(t,((e,t)=>Ka(e,t,o,n.unmerge(t))),e);return Xs(r,_.from(t[0]))}),((e,t)=>((e,t)=>t.unmergable)(0,t).filter((t=>qa(e,t)))),nl,m,Bs),Ml=Ga(((e,t,o,n)=>{const r=((e,t)=>{const o=nn.fromTable(e);return Va(o,t,!0)})(t.clipboard,t.generators),i=((e,t)=>({row:e,column:t}))(t.row,t.column);return us(i,e,r,t.generators,o).fold((()=>Xs(e,_.some(t.element))),(e=>Qs(e,t.row,t.column)))}),((e,t)=>Gt(t.element).bind((o=>Wa(e,o).map((e=>({...e,generators:t.generators,clipboard:t.clipboard})))))),nl,m,js),Tl=Ga(((e,t,o,n)=>{const r=Jo(e).rows,i=t.cells[0].column,a=r[t.cells[0].row],s=ol(t.clipboard,t.generators,a),l=hs(i,e,s,t.generators,o);return Qs(l,t.cells[0].row,t.cells[0].column)}),cl(!0),m,m,js),Il=Ga(((e,t,o,n)=>{const r=Jo(e).rows,i=t.cells[t.cells.length-1].column+t.cells[t.cells.length-1].colspan,a=r[t.cells[0].row],s=ol(t.clipboard,t.generators,a),l=hs(i,e,s,t.generators,o);return Qs(l,t.cells[0].row,i)}),cl(!1),m,m,js),El=Ga(((e,t,o,n)=>{const r=Jo(e).rows,i=t.cells[0].row,a=r[i],s=ol(t.clipboard,t.generators,a),l=ms(i,e,s,t.generators,o);return Qs(l,t.cells[0].row,t.cells[0].column)}),Xa,m,m,js),Dl=Ga(((e,t,o,n)=>{const r=Jo(e).rows,i=t.cells[t.cells.length-1].row+t.cells[t.cells.length-1].rowspan,a=r[t.cells[0].row],s=ol(t.clipboard,t.generators,a),l=ms(i,e,s,t.generators,o);return Qs(l,i,t.cells[0].column)}),Xa,m,m,js),Ol=(e,t)=>{const o=nn.fromTable(e);return Ja(o,t).bind((e=>{const t=e[e.length-1],n=e[0].column,r=t.column+t.colspan,i=j(I(o.all,(e=>O(e.cells,(e=>e.column>=n&&e.column{const o=nn.fromTable(e);return Ja(o,t).bind(Aa).getOr("")},Ll=(e,t)=>{const o=nn.fromTable(e);return Ja(o,t).bind((e=>{const t=e[e.length-1],n=e[0].row,r=t.row+t.rowspan;return(e=>{const t=I(e,(e=>ka(e).type)),o=A(t,"header"),n=A(t,"footer");if(o||n){const e=A(t,"body");return!o||e||n?o||e||!n?_.none():_.some("footer"):_.some("header")}return _.some("body")})(o.all.slice(n,r))})).getOr("")},Pl=(e,t)=>e.dispatch("NewRow",{node:t}),Rl=(e,t)=>e.dispatch("NewCell",{node:t}),jl=(e,t,o)=>{e.dispatch("TableModified",{...o,table:t})},zl={structure:!1,style:!0},Bl={structure:!0,style:!1},Fl={structure:!0,style:!0},Hl=(e,t)=>Wr(e)?gr(t):Yr(e)?mr(t):hr(t),Ul=(e,t,o)=>{const n=e=>"table"===ie(si(e)),r=Br(e),i=Vr(e)?m:ma,a=t=>{switch(Fr(e)){case"section":return Na();case"sectionCells":return La();case"cells":return Pa();default:return Oa(t,"section")}},s=(t,n)=>n.cursor.fold((()=>{const n=Xt(t);return U(n).filter(lt).map((n=>{o.clearSelectedCells(t.dom);const r=e.dom.createRng();return r.selectNode(n.dom),e.selection.setRng(r),fe(n,"data-mce-selected","1"),r}))}),(n=>{const r=ua(ha,n);const i=e.dom.createRng();return i.setStart(r.element.dom,r.offset),i.setEnd(r.element.dom,r.offset),e.selection.setRng(i),o.clearSelectedCells(t.dom),_.some(i)})),l=(o,n,i,l)=>(c,d,u=!1)=>{ci(c);const h=Ce.fromDom(e.getDoc()),m=Lr(i,h,r),g={sizing:Hl(e,c),resize:Vr(e)?xa():ya(),section:a(c)};return n(c)?o(c,d,m,g).bind((o=>{t.refresh(c.dom),E(o.newRows,(t=>{Pl(e,t.dom)})),E(o.newCells,(t=>{Rl(e,t.dom)}));const n=s(c,o);return lt(c)&&(ci(c),u||jl(e,c.dom,l)),n.map((e=>({rng:e,effect:l})))})):_.none()},c=l(vl,(t=>!n(e)||wa(t).rows>1),m,Bl),d=l(fl,(t=>!n(e)||wa(t).columns>1),m,Bl);return{deleteRow:c,deleteColumn:d,insertRowsBefore:l(hl,w,m,Bl),insertRowsAfter:l(ml,w,m,Bl),insertColumnsBefore:l(gl,w,i,Bl),insertColumnsAfter:l(pl,w,i,Bl),mergeCells:l(kl,w,m,Bl),unmergeCells:l(Al,w,m,Bl),pasteColsBefore:l(Tl,w,m,Bl),pasteColsAfter:l(Il,w,m,Bl),pasteRowsBefore:l(El,w,m,Bl),pasteRowsAfter:l(Dl,w,m,Bl),pasteCells:l(Ml,w,m,Fl),makeCellsHeader:l(Cl,w,m,Bl),unmakeCellsHeader:l(Sl,w,m,Bl),makeColumnsHeader:l(bl,w,m,Bl),unmakeColumnsHeader:l(xl,w,m,Bl),makeRowsHeader:l(yl,w,m,Bl),makeRowsBody:l(wl,w,m,Bl),makeRowsFooter:l(_l,w,m,Bl),getTableRowType:Ll,getTableCellType:Nl,getTableColType:Ol}},Vl=(e,t,o)=>{const n=Bt(e,t,1);1===o||n<=1?ye(e,t):fe(e,t,Math.min(o,n))},Zl=(e,t)=>o=>{const n=o.column+o.colspan-1,r=o.column;return n>=e&&r{const o=nn.fromTable(e);return Qa(o,t).map((e=>{const t=e[e.length-1],n=e[0].column,r=t.column+t.colspan,i=((e,t,o)=>{if(nn.hasColumns(e)){const n=O(nn.justColumns(e),Zl(t,o)),r=I(n,(e=>{const n=qe(e.element);return Vl(n,"span",o-t),n})),i=Ce.fromTag("colgroup");return We(i,r),[i]}return[]})(o,n,r),a=((e,t,o)=>I(e.all,(e=>{const n=O(e.cells,Zl(t,o)),r=I(n,(e=>{const n=qe(e.element);return Vl(n,"colspan",o-t),n})),i=Ce.fromTag("tr");return We(i,r),i})))(o,n,r);return[...i,...a]}))},Yl=(e,t,o)=>{const n=nn.fromTable(e);return Ja(n,t).bind((e=>{const t=Va(n,o,!1),r=Jo(t).rows.slice(e[0].row,e[e.length-1].row+e[e.length-1].rowspan),i=z(r,(e=>{const t=O(e.cells,(e=>!e.isLocked));return t.length>0?[{...e,cells:t}]:[]})),a=Za(i);return St(a.length>0,a)})).map((e=>(e=>I(e,(e=>{const t=Qe(e.element);return E(e.cells,(e=>{const o=qe(e.element);ja(o,"colspan",e.colspan,1),ja(o,"rowspan",e.rowspan,1),Ue(t,o)})),t})))(e)))},Gl=Ss([{invalid:["raw"]},{pixels:["value"]},{percent:["value"]}]),Xl=(e,t,o)=>{const n=o.substring(0,o.length-e.length),r=parseFloat(n);return n===r.toString()?t(r):Gl.invalid(o)},Jl={...Gl,from:e=>Tt(e,"%")?Xl("%",Gl.percent,e):Tt(e,"px")?Xl("px",Gl.pixels,e):Gl.invalid(e)},Ql=(e,t,o)=>e.fold((()=>t),(e=>((e,t,o)=>{const n=o/t;return I(e,(e=>Jl.from(e).fold((()=>e),(e=>e*n+"px"),(e=>e/100*o+"px"))))})(t,o,e)),(e=>((e,t)=>I(e,(e=>Jl.from(e).fold((()=>e),(e=>e/t*100+"%"),(e=>e+"%")))))(t,o))),ql=(e,t,o)=>{const n=Jl.from(o),r=B(e,(e=>"0px"===e))?((e,t)=>{const o=e.fold((()=>g("")),(e=>g(e/t+"px")),(()=>g(100/t+"%")));return T(t,o)})(n,e.length):Ql(n,e,t);return ec(r)},Kl=(e,t)=>0===e.length?t:N(e,((e,t)=>Jl.from(t).fold(g(0),p,p)+e),0),$l=(e,t)=>Jl.from(e).fold(g(e),(e=>e+t+"px"),(e=>e+t+"%")),ec=e=>{if(0===e.length)return e;const t=N(e,((e,t)=>{const o=Jl.from(t).fold((()=>({value:t,remainder:0})),(e=>((e,t)=>{const o=Math.floor(e);return{value:o+t,remainder:e-o}})(e,"px")),(e=>({value:e+"%",remainder:0})));return{output:[o.value].concat(e.output),remainder:e.remainder+o.remainder}}),{output:[],remainder:0}),o=t.output;return o.slice(0,o.length-1).concat([$l(o[o.length-1],Math.round(t.remainder))])},tc=Jl.from,oc=(e,t,o)=>{const n=nn.fromTable(e),r=n.all,i=nn.justCells(n),a=nn.justColumns(n);t.each((t=>{const o=tc(t).fold(g("px"),g("px"),g("%"));const r=zo(e),s=((e,t)=>rr(e,t,tr,ir))(n,e),l=ql(s,r,t);nn.hasColumns(n)?((e,t,o)=>{E(t,((t,n)=>{const r=Kl([e[n]],Vt());Nt(t.element,"width",r+o)}))})(l,a,o):((e,t,o)=>{E(t,(t=>{const n=e.slice(t.column,t.colspan+t.column),r=Kl(n,Vt());Nt(t.element,"width",r+o)}))})(l,i,o),Nt(e,"width",t)})),o.each((t=>{const o=hn(e),a=((e,t)=>sr(e,t,or,ir))(n,e);((e,t,o)=>{E(o,(e=>{zt(e.element,"height")})),E(t,((t,o)=>{Nt(t.element,"height",e[o])}))})(ql(a,o,t),r,i),Nt(e,"height",t)}))},nc=e=>Gn(e).exists((e=>Rn.test(e))),rc=e=>Gn(e).exists((e=>jn.test(e))),ic=e=>Gn(e).isNone(),ac=e=>{ye(e,"width"),ye(e,"height")},sc=e=>{const t=Kn(e);oc(e,_.some(t),_.none()),ac(e)},lc=e=>{const t=(e=>zo(e)+"px")(e);oc(e,_.some(t),_.none()),ac(e)},cc=e=>{const t=(e=>hn(e)+"px")(e);oc(e,_.none(),_.some(t)),ac(e)},dc=e=>{zt(e,"width");const t=Jt(e),o=t.length>0?t:Xt(e);E(o,(e=>{zt(e,"width"),ac(e)})),ac(e)},uc={styles:{"border-collapse":"collapse",width:"100%"},attributes:{border:"1"},colGroups:!1},hc=e=>{const t=Ce.fromTag("colgroup");return T(e,(()=>Ue(t,Ce.fromTag("col")))),t},mc=(e,t,o,n)=>T(e,(e=>((e,t,o,n)=>{const r=Ce.fromTag("tr");for(let i=0;i{e.selection.select(t.dom,!0),e.selection.collapse(!0)},pc=(e,t,o,n,i)=>{const a=Kr(e),s={styles:a,attributes:qr(e),colGroups:$r(e)};return e.undoManager.ignore((()=>{const r=((e,t,o,n,r,i=uc)=>{const a=Ce.fromTag("table"),s="cells"!==r;Lt(a,i.styles),ve(a,i.attributes),i.colGroups&&Ue(a,hc(t));const l=Math.min(e,o);if(s&&o>0){const e=Ce.fromTag("thead");Ue(a,e);const i=mc(o,t,"sectionCells"===r?l:0,n);We(e,i)}const c=Ce.fromTag("tbody");Ue(a,c);const d=mc(s?e-l:e,t,s?0:o,n);return We(c,d),a})(o,t,i,n,Fr(e),s);fe(r,"data-mce-id","__mce");const a=(e=>{const t=Ce.fromTag("div"),o=Ce.fromDom(e.dom.cloneNode(!0));return Ue(t,o),(e=>e.dom.innerHTML)(t)})(r);e.insertContent(a),e.addVisual()})),yt(si(e),'table[data-mce-id="__mce"]').map((t=>(Yr(e)?lc(t):Gr(e)?dc(t):(Wr(e)||(e=>r(e)&&-1!==e.indexOf("%"))(a.width))&&sc(t),ci(t),ye(t,"data-mce-id"),((e,t)=>{E(gt(t,"tr"),(t=>{Pl(e,t.dom),E(gt(t,"th,td"),(t=>{Rl(e,t.dom)}))}))})(e,t),((e,t)=>{yt(t,"td,th").each(v(gc,e))})(e,t),t.dom))).getOrNull()};var fc=tinymce.util.Tools.resolve("tinymce.FakeClipboard");const vc="x-tinymce/dom-table-",bc=vc+"rows",xc=vc+"columns",yc=e=>{const t=fc.FakeClipboardItem(e);fc.write([t])},wc=e=>{var t;const o=null!==(t=fc.read())&&void 0!==t?t:[];return Z(o,(t=>_.from(t.getType(e))))},_c=e=>{wc(e).isSome()&&fc.clear()},Cc=e=>{e.fold(kc,(e=>yc({[bc]:e})))},Sc=()=>wc(bc),kc=()=>_c(bc),Ac=e=>{e.fold(Tc,(e=>yc({[xc]:e})))},Mc=()=>wc(xc),Tc=()=>_c(xc),Ic=e=>oa(di(e),li(e)).filter(fi),Ec=(e,t)=>{const o=li(e),n=e=>Qt(e,o),a=t=>(e=>na(di(e),li(e)).filter(fi))(e).bind((e=>n(e).map((o=>t(o,e))))),s=t=>{e.focus()},l=(t,o=!1)=>a(((n,r)=>{const i=ea(ra(e),n,r);t(n,i,o).each(s)})),c=()=>a(((t,o)=>{const n=ea(ra(e),t,o),r=Lr(m,Ce.fromDom(e.getDoc()),_.none());return Yl(t,n,r)})),d=()=>a(((t,o)=>{const n=ea(ra(e),t,o);return Wl(t,n)})),u=(t,o)=>o().each((o=>{const n=I(o,(e=>qe(e)));a(((o,r)=>{const i=Pr(Ce.fromDom(e.getDoc())),a=((e,t,o,n)=>({selection:Ui(e),clipboard:o,generators:n}))(ra(e),0,n,i);t(o,a).each(s)}))})),g=e=>(t,o)=>((e,t)=>$(e,t)?_.from(e[t]):_.none())(o,"type").each((t=>{l(e(t),o.no_events)}));G({mceTableSplitCells:()=>l(t.unmergeCells),mceTableMergeCells:()=>l(t.mergeCells),mceTableInsertRowBefore:()=>l(t.insertRowsBefore),mceTableInsertRowAfter:()=>l(t.insertRowsAfter),mceTableInsertColBefore:()=>l(t.insertColumnsBefore),mceTableInsertColAfter:()=>l(t.insertColumnsAfter),mceTableDeleteCol:()=>l(t.deleteColumn),mceTableDeleteRow:()=>l(t.deleteRow),mceTableCutCol:()=>d().each((e=>{Ac(e),l(t.deleteColumn)})),mceTableCutRow:()=>c().each((e=>{Cc(e),l(t.deleteRow)})),mceTableCopyCol:()=>d().each((e=>Ac(e))),mceTableCopyRow:()=>c().each((e=>Cc(e))),mceTablePasteColBefore:()=>u(t.pasteColsBefore,Mc),mceTablePasteColAfter:()=>u(t.pasteColsAfter,Mc),mceTablePasteRowBefore:()=>u(t.pasteRowsBefore,Sc),mceTablePasteRowAfter:()=>u(t.pasteRowsAfter,Sc),mceTableDelete:()=>Ic(e).each((t=>{Qt(t,o).filter(b(o)).each((t=>{const o=Ce.fromText("");if(Fe(t,o),Ge(t),e.dom.isEmpty(e.getBody()))e.setContent(""),e.selection.setCursorLocation();else{const t=e.dom.createRng();t.setStart(o.dom,0),t.setEnd(o.dom,0),e.selection.setRng(t),e.nodeChanged()}}))})),mceTableCellToggleClass:(t,o)=>{a((t=>{const n=ra(e),r=B(n,(t=>e.formatter.match("tablecellclass",{value:o},t.dom))),i=r?e.formatter.remove:e.formatter.apply;E(n,(e=>i("tablecellclass",{value:o},e.dom))),jl(e,t.dom,zl)}))},mceTableToggleClass:(t,o)=>{a((t=>{e.formatter.toggle("tableclass",{value:o},t.dom),jl(e,t.dom,zl)}))},mceTableToggleCaption:()=>{Ic(e).each((t=>{Qt(t,o).each((o=>{xt(o,"caption").fold((()=>{const t=Ce.fromTag("caption");Ue(t,Ce.fromText("Caption")),((e,t,o)=>{ze(e,o).fold((()=>{Ue(e,t)}),(e=>{Be(e,t)}))})(o,t,0),e.selection.setCursorLocation(t.dom,0)}),(n=>{ge("caption")(t)&&Ae("td",o).each((t=>e.selection.setCursorLocation(t.dom,0))),Ge(n)})),jl(e,o.dom,Bl)}))}))},mceTableSizingMode:(t,n)=>(t=>Ic(e).each((n=>{Gr(e)||Yr(e)||Wr(e)||Qt(n,o).each((o=>{"relative"!==t||nc(o)?"fixed"!==t||rc(o)?"responsive"!==t||ic(o)||dc(o):lc(o):sc(o),ci(o),jl(e,o.dom,Bl)}))})))(n),mceTableCellType:g((e=>"th"===e?t.makeCellsHeader:t.unmakeCellsHeader)),mceTableColType:g((e=>"th"===e?t.makeColumnsHeader:t.unmakeColumnsHeader)),mceTableRowType:g((e=>{switch(e){case"header":return t.makeRowsHeader;case"footer":return t.makeRowsFooter;default:return t.makeRowsBody}}))},((t,o)=>e.addCommand(o,t))),e.addCommand("mceInsertTable",((t,o)=>{((e,t,o,n={})=>{const r=e=>h(e)&&e>0;if(r(t)&&r(o)){const r=n.headerRows||0,i=n.headerColumns||0;return pc(e,o,t,i,r)}console.error("Invalid values for mceInsertTable - rows and columns values are required to insert a table.")})(e,o.rows,o.columns,o.options)})),e.addCommand("mceTableApplyCellStyle",((t,o)=>{const a=e=>"tablecell"+e.toLowerCase().replace("-","");if(!i(o))return;const s=O(ra(e),fi);if(0===s.length)return;const l=Q(o,((t,o)=>e.formatter.has(a(o))&&r(t)));(e=>{for(const t in e)if(Y.call(e,t))return!1;return!0})(l)||(G(l,((t,o)=>{const n=a(o);E(s,(o=>{""===t?e.formatter.remove(n,{value:null},o.dom,!0):e.formatter.apply(n,{value:t},o.dom)}))})),n(s[0]).each((t=>jl(e,t.dom,zl))))}))},Dc=Ss([{before:["element"]},{on:["element","offset"]},{after:["element"]}]),Oc={before:Dc.before,on:Dc.on,after:Dc.after,cata:(e,t,o,n)=>e.fold(t,o,n),getStart:e=>e.fold(p,p,p)},Nc=(e,t)=>({selection:e,kill:t}),Lc=(e,t)=>{const o=e.document.createRange();return o.selectNode(t.dom),o},Pc=(e,t)=>{const o=e.document.createRange();return Rc(o,t),o},Rc=(e,t)=>e.selectNodeContents(t.dom),jc=(e,t,o)=>{const n=e.document.createRange();var r;return r=n,t.fold((e=>{r.setStartBefore(e.dom)}),((e,t)=>{r.setStart(e.dom,t)}),(e=>{r.setStartAfter(e.dom)})),((e,t)=>{t.fold((t=>{e.setEndBefore(t.dom)}),((t,o)=>{e.setEnd(t.dom,o)}),(t=>{e.setEndAfter(t.dom)}))})(n,o),n},zc=(e,t,o,n,r)=>{const i=e.document.createRange();return i.setStart(t.dom,o),i.setEnd(n.dom,r),i},Bc=e=>({left:e.left,top:e.top,right:e.right,bottom:e.bottom,width:e.width,height:e.height}),Fc=Ss([{ltr:["start","soffset","finish","foffset"]},{rtl:["start","soffset","finish","foffset"]}]),Hc=(e,t,o)=>t(Ce.fromDom(o.startContainer),o.startOffset,Ce.fromDom(o.endContainer),o.endOffset),Uc=(e,t)=>{const o=((e,t)=>t.match({domRange:e=>({ltr:g(e),rtl:_.none}),relative:(t,o)=>({ltr:oo((()=>jc(e,t,o))),rtl:oo((()=>_.some(jc(e,o,t))))}),exact:(t,o,n,r)=>({ltr:oo((()=>zc(e,t,o,n,r))),rtl:oo((()=>_.some(zc(e,n,r,t,o))))})}))(e,t);return((e,t)=>{const o=t.ltr();if(o.collapsed)return t.rtl().filter((e=>!1===e.collapsed)).map((e=>Fc.rtl(Ce.fromDom(e.endContainer),e.endOffset,Ce.fromDom(e.startContainer),e.startOffset))).getOrThunk((()=>Hc(0,Fc.ltr,o)));return Hc(0,Fc.ltr,o)})(0,o)},Vc=(e,t)=>Uc(e,t).match({ltr:(t,o,n,r)=>{const i=e.document.createRange();return i.setStart(t.dom,o),i.setEnd(n.dom,r),i},rtl:(t,o,n,r)=>{const i=e.document.createRange();return i.setStart(n.dom,r),i.setEnd(t.dom,o),i}});Fc.ltr,Fc.rtl;const Zc=(e,t,o,n)=>({start:e,soffset:t,finish:o,foffset:n}),Wc=(e,t,o,n)=>({start:Oc.on(e,t),finish:Oc.on(o,n)}),Yc=(e,t)=>{const o=Vc(e,t);return Zc(Ce.fromDom(o.startContainer),o.startOffset,Ce.fromDom(o.endContainer),o.endOffset)},Gc=Wc,Xc=(e,t,o,n,r)=>Me(o,n)?_.none():Ri(o,n,t).bind((t=>{const n=t.boxes.getOr([]);return n.length>1?(r(e,n,t.start,t.finish),_.some(Nc(_.some(Gc(o,0,o,wr(o))),!0))):_.none()})),Jc=(e,t)=>({item:e,mode:t}),Qc=(e,t,o,n=qc)=>e.property().parent(t).map((e=>Jc(e,n))),qc=(e,t,o,n=Kc)=>o.sibling(e,t).map((e=>Jc(e,n))),Kc=(e,t,o,n=Kc)=>{const r=e.property().children(t);return o.first(r).map((e=>Jc(e,n)))},$c=[{current:Qc,next:qc,fallback:_.none()},{current:qc,next:Kc,fallback:_.some(Qc)},{current:Kc,next:Kc,fallback:_.some(qc)}],ed=(e,t,o,n,r=$c)=>P(r,(e=>e.current===o)).bind((o=>o.current(e,t,n,o.next).orThunk((()=>o.fallback.bind((o=>ed(e,t,o,n))))))),td=()=>({sibling:(e,t)=>e.query().prevSibling(t),first:e=>e.length>0?_.some(e[e.length-1]):_.none()}),od=()=>({sibling:(e,t)=>e.query().nextSibling(t),first:e=>e.length>0?_.some(e[0]):_.none()}),nd=(e,t,o,n,r,i)=>ed(e,t,n,r).bind((t=>i(t.item)?_.none():o(t.item)?_.some(t.item):nd(e,t.item,o,t.mode,r,i))),rd=e=>t=>0===e.property().children(t).length,id=(e,t,o,n)=>nd(e,t,o,qc,td(),n),ad=(e,t,o,n)=>nd(e,t,o,qc,od(),n),sd=Ti(),ld=(e,t)=>((e,t,o)=>id(e,t,rd(e),o))(sd,e,t),cd=(e,t)=>((e,t,o)=>ad(e,t,rd(e),o))(sd,e,t),dd=Ss([{none:["message"]},{success:[]},{failedUp:["cell"]},{failedDown:["cell"]}]),ud=e=>wt(e,"tr"),hd={...dd,verify:(e,t,o,n,r,i,a)=>wt(n,"td,th",a).bind((o=>wt(t,"td,th",a).map((t=>Me(o,t)?Me(n,o)&&wr(o)===r?i(t):dd.none("in same cell"):Li(ud,[o,t]).fold((()=>((e,t,o)=>{const n=e.getRect(t),r=e.getRect(o);return r.right>n.left&&r.lefti(t))))))).getOr(dd.none("default")),cata:(e,t,o,n,r)=>e.fold(t,o,n,r)},md=(e,t)=>R(e,v(Me,t)),gd=ge("br"),pd=(e,t,o)=>t(e,o).bind((e=>ue(e)&&0===br(e).trim().length?pd(e,t,o):_.some(e))),fd=(e,t,o,n)=>((e,t)=>ze(e,t).filter(gd).orThunk((()=>ze(e,t-1).filter(gd))))(t,o).bind((t=>n.traverse(t).fold((()=>pd(t,n.gather,e).map(n.relative)),(e=>(e=>Oe(e).bind((t=>{const o=je(t);return md(o,e).map((n=>((e,t,o,n)=>({parent:e,children:t,element:o,index:n}))(t,o,e,n)))})))(e).map((e=>Oc.on(e.parent,e.index))))))),vd=(e,t,o,n)=>{const r=gd(t)?((e,t,o)=>o.traverse(t).orThunk((()=>pd(t,o.gather,e))).map(o.relative))(e,t,n):fd(e,t,o,n);return r.map((e=>({start:e,finish:e})))},bd=(e,t)=>({left:e.left,top:e.top+t,right:e.right,bottom:e.bottom+t}),xd=(e,t)=>({left:e.left,top:e.top-t,right:e.right,bottom:e.bottom-t}),yd=(e,t,o)=>({left:e.left+t,top:e.top+o,right:e.right+t,bottom:e.bottom+o}),wd=e=>({left:e.left,top:e.top,right:e.right,bottom:e.bottom}),_d=(e,t)=>_.some(e.getRect(t)),Cd=(e,t,o)=>de(t)?_d(e,t).map(wd):ue(t)?((e,t,o)=>o>=0&&o0?e.getRangedRect(t,o-1,t,o):_.none())(e,t,o).map(wd):_.none(),Sd=(e,t)=>de(t)?_d(e,t).map(wd):ue(t)?e.getRangedRect(t,0,t,wr(t)).map(wd):_.none(),kd=Ss([{none:[]},{retry:["caret"]}]),Ad=(e,t,o)=>vt(t,Us).fold(y,(t=>Sd(e,t).exists((e=>((e,t)=>e.leftt.right)(o,e))))),Md={point:e=>e.bottom,adjuster:(e,t,o,n,r)=>{const i=bd(r,5);return Math.abs(o.bottom-n.bottom)<1||o.top>r.bottom?kd.retry(i):o.top===r.bottom?kd.retry(bd(r,1)):Ad(e,t,r)?kd.retry(yd(i,5,0)):kd.none()},move:bd,gather:cd},Td=(e,t,o,n,r)=>0===r?_.some(n):((e,t,o)=>e.elementFromPoint(t,o).filter((e=>"table"===ie(e))).isSome())(e,n.left,t.point(n))?((e,t,o,n,r)=>Td(e,t,o,t.move(n,5),r))(e,t,o,n,r-1):e.situsFromPoint(n.left,t.point(n)).bind((i=>i.start.fold(_.none,(i=>Sd(e,i).bind((a=>t.adjuster(e,i,a,o,n).fold(_.none,(n=>Td(e,t,o,n,r-1))))).orThunk((()=>_.some(n)))),_.none))),Id=(e,t,o)=>{const n=e.move(o,5),r=Td(t,e,o,n,100).getOr(n);return((e,t,o)=>e.point(t)>o.getInnerHeight()?_.some(e.point(t)-o.getInnerHeight()):e.point(t)<0?_.some(-e.point(t)):_.none())(e,r,t).fold((()=>t.situsFromPoint(r.left,e.point(r))),(o=>(t.scrollBy(0,o),t.situsFromPoint(r.left,e.point(r)-o))))},Ed={tryUp:v(Id,{point:e=>e.top,adjuster:(e,t,o,n,r)=>{const i=xd(r,5);return Math.abs(o.top-n.top)<1||o.bottome.getSelection().bind((n=>vd(t,n.finish,n.foffset,o).fold((()=>_.some(sa(n.finish,n.foffset))),(r=>{const i=e.fromSitus(r);return(e=>hd.cata(e,(e=>_.none()),(()=>_.none()),(e=>_.some(sa(e,0))),(e=>_.some(sa(e,wr(e))))))(hd.verify(e,n.finish,n.foffset,i.finish,i.foffset,o.failure,t))})))),Od=(e,t,o,n,r,i)=>0===i?_.none():Pd(e,t,o,n,r).bind((a=>{const s=e.fromSitus(a),l=hd.verify(e,o,n,s.finish,s.foffset,r.failure,t);return hd.cata(l,(()=>_.none()),(()=>_.some(a)),(a=>Me(o,a)&&0===n?Nd(e,o,n,xd,r):Od(e,t,a,0,r,i-1)),(a=>Me(o,a)&&n===wr(a)?Nd(e,o,n,bd,r):Od(e,t,a,wr(a),r,i-1)))})),Nd=(e,t,o,n,r)=>Cd(e,t,o).bind((t=>Ld(e,r,n(t,Ed.getJumpSize())))),Ld=(e,t,o)=>{const n=Oo().browser;return n.isChromium()||n.isSafari()||n.isFirefox()?t.retry(e,o):_.none()},Pd=(e,t,o,n,r)=>Cd(e,o,n).bind((t=>Ld(e,r,t))),Rd=(e,t)=>{return ft(e,(e=>Oe(e).exists((e=>Me(e,t)))),o).isSome();var o},jd=(e,t,o,n,r)=>wt(n,"td,th",t).bind((n=>wt(n,"table",t).bind((i=>Rd(r,i)?((e,t,o)=>Dd(e,t,o).bind((n=>Od(e,t,n.element,n.offset,o,20).map(e.fromSitus))))(e,t,o).bind((e=>wt(e.finish,"td,th",t).map((t=>({start:n,finish:t,range:e}))))):_.none())))),zd=(e,t,o,n,r,i)=>i(n,t).orThunk((()=>jd(e,t,o,n,r).map((e=>{const t=e.range;return Nc(_.some(Gc(t.start,t.soffset,t.finish,t.foffset)),!0)})))),Bd=(e,t)=>wt(e,"tr",t).bind((e=>wt(e,"table",t).bind((o=>{const n=gt(o,"tr");return Me(e,n[0])?((e,t,o)=>id(sd,e,t,o))(o,(e=>kr(e).isSome()),t).map((e=>{const t=wr(e);return Nc(_.some(Gc(e,t,e,t)),!0)})):_.none()})))),Fd=(e,t)=>wt(e,"tr",t).bind((e=>wt(e,"table",t).bind((o=>{const n=gt(o,"tr");return Me(e,n[n.length-1])?((e,t,o)=>ad(sd,e,t,o))(o,(e=>Sr(e).isSome()),t).map((e=>Nc(_.some(Gc(e,0,e,0)),!0))):_.none()})))),Hd=(e,t,o,n,r,i,a)=>jd(e,o,n,r,i).bind((e=>Xc(t,o,e.start,e.finish,a))),Ud=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}},Vd=()=>{const e=(e=>{const t=Ud(_.none()),o=()=>t.get().each(e);return{clear:()=>{o(),t.set(_.none())},isSet:()=>t.get().isSome(),get:()=>t.get(),set:e=>{o(),t.set(_.some(e))}}})(m);return{...e,on:t=>e.get().each(t)}},Zd=(e,t)=>wt(e,"td,th",t),Wd=e=>Ne(e).exists(ii),Yd={traverse:Re,gather:cd,relative:Oc.before,retry:Ed.tryDown,failure:hd.failedDown},Gd={traverse:Pe,gather:ld,relative:Oc.before,retry:Ed.tryUp,failure:hd.failedUp},Xd=e=>t=>t===e,Jd=Xd(38),Qd=Xd(40),qd=e=>e>=37&&e<=40,Kd={isBackward:Xd(37),isForward:Xd(39)},$d={isBackward:Xd(39),isForward:Xd(37)},eu=Ss([{domRange:["rng"]},{relative:["startSitu","finishSitu"]},{exact:["start","soffset","finish","foffset"]}]),tu={domRange:eu.domRange,relative:eu.relative,exact:eu.exact,exactFromRange:e=>eu.exact(e.start,e.soffset,e.finish,e.foffset),getWin:e=>{const t=(e=>e.match({domRange:e=>Ce.fromDom(e.startContainer),relative:(e,t)=>Oc.getStart(e),exact:(e,t,o,n)=>e}))(e);return o=t,Ce.fromDom(De(o).dom.defaultView);var o},range:Zc},ou=(e,t,o)=>e.caretPositionFromPoint?((e,t,o)=>{var n;return _.from(null===(n=e.caretPositionFromPoint)||void 0===n?void 0:n.call(e,t,o)).bind((t=>{if(null===t.offsetNode)return _.none();const o=e.createRange();return o.setStart(t.offsetNode,t.offset),o.collapse(),_.some(o)}))})(e,t,o):e.caretRangeFromPoint?((e,t,o)=>{var n;return _.from(null===(n=e.caretRangeFromPoint)||void 0===n?void 0:n.call(e,t,o))})(e,t,o):_.none(),nu=(e,t)=>{const o=ie(e);return"input"===o?Oc.after(e):A(["br","img"],o)?0===t?Oc.before(e):Oc.after(e):Oc.on(e,t)},ru=(e,t,o,n)=>{const r=((e,t,o,n)=>{const r=Ee(e).dom.createRange();return r.setStart(e.dom,t),r.setEnd(o.dom,n),r})(e,t,o,n),i=Me(e,o)&&t===n;return r.collapsed&&!i},iu=e=>_.from(e.getSelection()),au=(e,t)=>{iu(e).each((e=>{e.removeAllRanges(),e.addRange(t)}))},su=(e,t,o,n,r)=>{const i=zc(e,t,o,n,r);au(e,i)},lu=(e,t)=>Uc(e,t).match({ltr:(t,o,n,r)=>{su(e,t,o,n,r)},rtl:(t,o,n,r)=>{iu(e).each((i=>{if(i.setBaseAndExtent)i.setBaseAndExtent(t.dom,o,n.dom,r);else if(i.extend)try{((e,t,o,n,r,i)=>{t.collapse(o.dom,n),t.extend(r.dom,i)})(0,i,t,o,n,r)}catch(i){su(e,n,r,t,o)}else su(e,n,r,t,o)}))}}),cu=(e,t,o,n,r)=>{const i=((e,t,o,n)=>{const r=nu(e,t),i=nu(o,n);return tu.relative(r,i)})(t,o,n,r);lu(e,i)},du=(e,t,o)=>{const n=((e,t)=>{const o=e.fold(Oc.before,nu,Oc.after),n=t.fold(Oc.before,nu,Oc.after);return tu.relative(o,n)})(t,o);lu(e,n)},uu=e=>{if(e.rangeCount>0){const t=e.getRangeAt(0),o=e.getRangeAt(e.rangeCount-1);return _.some(Zc(Ce.fromDom(t.startContainer),t.startOffset,Ce.fromDom(o.endContainer),o.endOffset))}return _.none()},hu=e=>{if(null===e.anchorNode||null===e.focusNode)return uu(e);{const t=Ce.fromDom(e.anchorNode),o=Ce.fromDom(e.focusNode);return ru(t,e.anchorOffset,o,e.focusOffset)?_.some(Zc(t,e.anchorOffset,o,e.focusOffset)):uu(e)}},mu=(e,t,o=!0)=>{const n=(o?Pc:Lc)(e,t);au(e,n)},gu=e=>(e=>iu(e).filter((e=>e.rangeCount>0)).bind(hu))(e).map((e=>tu.exact(e.start,e.soffset,e.finish,e.foffset))),pu=(e,t)=>(e=>{const t=e.getClientRects(),o=t.length>0?t[0]:e.getBoundingClientRect();return o.width>0||o.height>0?_.some(o).map(Bc):_.none()})(Vc(e,t)),fu=(e,t,o)=>((e,t,o)=>{const n=e.document;return ou(n,t,o).map((e=>Zc(Ce.fromDom(e.startContainer),e.startOffset,Ce.fromDom(e.endContainer),e.endOffset)))})(e,t,o),vu=e=>({elementFromPoint:(t,o)=>Ce.fromPoint(Ce.fromDom(e.document),t,o),getRect:e=>e.dom.getBoundingClientRect(),getRangedRect:(t,o,n,r)=>{const i=tu.exact(t,o,n,r);return pu(e,i)},getSelection:()=>gu(e).map((t=>Yc(e,t))),fromSitus:t=>{const o=tu.relative(t.start,t.finish);return Yc(e,o)},situsFromPoint:(t,o)=>fu(e,t,o).map((e=>Wc(e.start,e.soffset,e.finish,e.foffset))),clearSelection:()=>{(e=>{iu(e).each((e=>e.removeAllRanges()))})(e)},collapseSelection:(t=!1)=>{gu(e).each((o=>o.fold((e=>e.collapse(t)),((o,n)=>{const r=t?o:n;du(e,r,r)}),((o,n,r,i)=>{const a=t?o:r,s=t?n:i;cu(e,a,s,a,s)}))))},setSelection:t=>{cu(e,t.start,t.soffset,t.finish,t.foffset)},setRelativeSelection:(t,o)=>{du(e,t,o)},selectNode:t=>{mu(e,t,!1)},selectContents:t=>{mu(e,t)},getInnerHeight:()=>e.innerHeight,getScrollY:()=>(e=>{const t=void 0!==e?e.dom:document,o=t.body.scrollLeft||t.documentElement.scrollLeft,n=t.body.scrollTop||t.documentElement.scrollTop;return fn(o,n)})(Ce.fromDom(e.document)).top,scrollBy:(t,o)=>{((e,t,o)=>{const n=(void 0!==o?o.dom:document).defaultView;n&&n.scrollBy(e,t)})(t,o,Ce.fromDom(e.document))}}),bu=(e,t)=>({rows:e,cols:t}),xu=(e,t,o,n)=>{const r=((e,t,o,n)=>{const r=Vd(),i=r.clear,a=i=>{r.on((r=>{n.clearBeforeUpdate(t),Zd(i.target,o).each((a=>{Ri(r,a,o).each((o=>{const r=o.boxes.getOr([]);if(1===r.length){const e=r[0],o="false"===ai(e),a=_t(ri(i.target),e,Me);o&&a&&n.selectRange(t,r,e,e)}else r.length>1&&(n.selectRange(t,r,o.start,o.finish),e.selectContents(a))}))}))}))};return{clearstate:i,mousedown:e=>{n.clear(t),Zd(e.target,o).filter(Wd).each(r.set)},mouseover:e=>{a(e)},mouseup:e=>{a(e),i()}}})(vu(e),t,o,n);return{clearstate:r.clearstate,mousedown:r.mousedown,mouseover:r.mouseover,mouseup:r.mouseup}},yu=e=>vt(e,ce).exists(ii),wu=(e,t)=>yu(e)||yu(t),_u=(e,t,o,n)=>{const r=vu(e),i=()=>(n.clear(t),_.none());return{keydown:(e,a,s,l,c,d)=>{const u=e.raw,h=u.which,m=!0===u.shiftKey,g=ji(t,n.selectedSelector).fold((()=>(qd(h)&&!m&&n.clearBeforeUpdate(t),qd(h)&&m&&!wu(a,l)?_.none:Qd(h)&&m?v(Hd,r,t,o,Yd,l,a,n.selectRange):Jd(h)&&m?v(Hd,r,t,o,Gd,l,a,n.selectRange):Qd(h)?v(zd,r,o,Yd,l,a,Fd):Jd(h)?v(zd,r,o,Gd,l,a,Bd):_.none)),(e=>{const o=o=>()=>{const i=Z(o,(o=>((e,t,o,n,r)=>Bi(n,e,t,r.firstSelectedSelector,r.lastSelectedSelector).map((e=>(r.clearBeforeUpdate(o),r.selectRange(o,e.boxes,e.start,e.finish),e.boxes))))(o.rows,o.cols,t,e,n)));return i.fold((()=>zi(t,n.firstSelectedSelector,n.lastSelectedSelector).map((e=>{const o=Qd(h)||d.isForward(h)?Oc.after:Oc.before;return r.setRelativeSelection(Oc.on(e.first,0),o(e.table)),n.clear(t),Nc(_.none(),!0)}))),(e=>_.some(Nc(_.none(),!0))))};return qd(h)&&m&&!wu(a,l)?_.none:Qd(h)&&m?o([bu(1,0)]):Jd(h)&&m?o([bu(-1,0)]):d.isBackward(h)&&m?o([bu(0,-1),bu(-1,0)]):d.isForward(h)&&m?o([bu(0,1),bu(1,0)]):qd(h)&&!m?i:_.none}));return g()},keyup:(e,r,i,a,s)=>ji(t,n.selectedSelector).fold((()=>{const l=e.raw,c=l.which;return!0===l.shiftKey&&qd(c)&&wu(r,a)?((e,t,o,n,r,i,a)=>Me(o,r)&&n===i?_.none():wt(o,"td,th",t).bind((o=>wt(r,"td,th",t).bind((n=>Xc(e,t,o,n,a))))))(t,o,r,i,a,s,n.selectRange):_.none()}),_.none)}},Cu=(e,t)=>{const o=be(e,t);return void 0===o||""===o?[]:o.split(" ")},Su=e=>void 0!==e.dom.classList,ku=(e,t)=>((e,t,o)=>{const n=Cu(e,t).concat([o]);return fe(e,t,n.join(" ")),!0})(e,"class",t),Au=(e,t)=>{Su(e)?e.dom.classList.add(t):ku(e,t)},Mu=(e,t)=>Su(e)&&e.dom.classList.contains(t),Tu=(e,t,o)=>{const n=t=>{ye(t,e.selected),ye(t,e.firstSelected),ye(t,e.lastSelected)},r=t=>{fe(t,e.selected,"1")},i=e=>{a(e),o()},a=t=>{const o=gt(t,`${e.selectedSelector},${e.firstSelectedSelector},${e.lastSelectedSelector}`);E(o,n)};return{clearBeforeUpdate:a,clear:i,selectRange:(o,n,a,s)=>{i(o),E(n,r),fe(a,e.firstSelected,"1"),fe(s,e.lastSelected,"1"),t(n,a,s)},selectedSelector:e.selectedSelector,firstSelectedSelector:e.firstSelectedSelector,lastSelectedSelector:e.lastSelectedSelector}},Iu=()=>({tag:"none"}),Eu=e=>({tag:"multiple",elements:e}),Du=e=>({tag:"single",element:e}),Ou=(e,t,o)=>{const n=nn.fromTable(e);return Ja(n,t).map((e=>{const t=Va(n,o,!1),{rows:r}=Jo(t),i=((e,t)=>{const o=e.slice(0,t[t.length-1].row+1),n=Za(o);return z(n,(e=>{const o=e.cells.slice(0,t[t.length-1].column+1);return I(o,(e=>e.element))}))})(r,e),a=((e,t)=>{const o=e.slice(t[0].row+t[0].rowspan-1,e.length),n=Za(o);return z(n,(e=>{const o=e.cells.slice(t[0].column+t[0].colspan-1,e.cells.length);return I(o,(e=>e.element))}))})(r,e);return{upOrLeftCells:i,downOrRightCells:a}}))},Nu=e=>{const t=Ce.fromDom((e=>{if(d(e.target)){const t=Ce.fromDom(e.target);if(de(t)&&st(t)&&e.composed&&e.composedPath){const t=e.composedPath();if(t)return U(t)}}return _.from(e.target)})(e).getOr(e.target)),o=()=>e.stopPropagation(),n=()=>e.preventDefault(),r=(i=n,a=o,(...e)=>i(a.apply(null,e)));var i,a;return((e,t,o,n,r,i,a)=>({target:e,x:t,y:o,stop:n,prevent:r,kill:i,raw:a}))(t,e.clientX,e.clientY,o,n,r,e)},Lu=(e,t,o,n,r)=>{const i=((e,t)=>o=>{e(o)&&t(Nu(o))})(o,n);return e.dom.addEventListener(t,i,r),{unbind:v(Pu,e,t,i,r)}},Pu=(e,t,o,n)=>{e.dom.removeEventListener(t,o,n)},Ru=w,ju=(e,t,o)=>((e,t,o,n)=>Lu(e,t,o,n,!1))(e,t,Ru,o),zu=Nu,Bu=e=>!Mu(Ce.fromDom(e.target),"ephox-snooker-resizer-bar"),Fu=(e,t)=>{const o=((e,t,o)=>({get:()=>Fi(e(),o).fold((()=>t().fold(Iu,Du)),Eu)}))((()=>Ce.fromDom(e.getBody())),(()=>na(di(e),li(e))),$i.selectedSelector),n=Tu($i,((t,o,n)=>{Qt(o).each((r=>{const i=I(t,(e=>e.dom)),a=Br(e),s=Lr(m,Ce.fromDom(e.getDoc()),a),l=ra(e),c=Ou(r,{selection:l},s).map((e=>X(e,(e=>I(e,(e=>e.dom)))))).getOrUndefined();((e,t,o,n,r)=>{e.dispatch("TableSelectionChange",{cells:t,start:o,finish:n,otherCells:r})})(e,i,o.dom,n.dom,c)}))}),(()=>(e=>{e.dispatch("TableSelectionClear")})(e)));e.on("init",(o=>{const r=e.getWin(),i=si(e),a=li(e),s=xu(r,i,a,n),l=_u(r,i,a,n),c=((e,t,o,n)=>{const r=vu(e);return(e,i)=>{n.clearBeforeUpdate(t),Ri(e,i,o).each((e=>{const o=e.boxes.getOr([]);n.selectRange(t,o,e.start,e.finish),r.selectContents(i),r.collapseSelection()}))}})(r,i,a,n);e.on("TableSelectorChange",(e=>c(e.start,e.finish)));const d=(t,o)=>{(e=>!0===e.raw.shiftKey)(t)&&(o.kill&&t.kill(),o.selection.each((t=>{const o=tu.relative(t.start,t.finish),n=Vc(r,o);e.selection.setRng(n)})))},u=e=>0===e.button,h=(()=>{const e=Ud(Ce.fromDom(i)),t=Ud(0);return{touchEnd:o=>{const n=Ce.fromDom(o.target);if(ge("td")(n)||ge("th")(n)){const r=e.get(),i=t.get();Me(r,n)&&o.timeStamp-i<300&&(o.preventDefault(),c(n,n))}e.set(n),t.set(o.timeStamp)}}})();e.on("dragstart",(e=>{s.clearstate()})),e.on("mousedown",(e=>{u(e)&&Bu(e)&&s.mousedown(zu(e))})),e.on("mouseover",(e=>{var t;(void 0===(t=e).buttons||1&t.buttons)&&Bu(e)&&s.mouseover(zu(e))})),e.on("mouseup",(e=>{u(e)&&Bu(e)&&s.mouseup(zu(e))})),e.on("touchend",h.touchEnd),e.on("keyup",(t=>{const o=zu(t);if(o.raw.shiftKey&&qd(o.raw.which)){const t=e.selection.getRng(),n=Ce.fromDom(t.startContainer),r=Ce.fromDom(t.endContainer);l.keyup(o,n,t.startOffset,r,t.endOffset).each((e=>{d(o,e)}))}})),e.on("keydown",(o=>{const n=zu(o);t.hide();const r=e.selection.getRng(),i=Ce.fromDom(r.startContainer),a=Ce.fromDom(r.endContainer),s=cn(Kd,$d)(Ce.fromDom(e.selection.getStart()));l.keydown(n,i,r.startOffset,a,r.endOffset,s).each((e=>{d(n,e)})),t.show()})),e.on("NodeChange",(()=>{const t=e.selection,o=Ce.fromDom(t.getStart()),r=Ce.fromDom(t.getEnd());Li(Qt,[o,r]).fold((()=>n.clear(i)),m)}))})),e.on("PreInit",(()=>{e.serializer.addTempAttr($i.firstSelected),e.serializer.addTempAttr($i.lastSelected)}));return{getSelectedCells:()=>((e,t,o,n)=>{switch(e.tag){case"none":return t();case"single":return n(e.element);case"multiple":return o(e.elements)}})(o.get(),g([]),(e=>I(e,(e=>e.dom))),(e=>[e.dom])),clearSelectedCells:e=>n.clear(Ce.fromDom(e))}},Hu=e=>{let t=[];return{bind:e=>{if(void 0===e)throw new Error("Event bind error: undefined handler");t.push(e)},unbind:e=>{t=O(t,(t=>t!==e))},trigger:(...o)=>{const n={};E(e,((e,t)=>{n[e]=o[t]})),E(t,(e=>{e(n)}))}}},Uu=e=>({registry:X(e,(e=>({bind:e.bind,unbind:e.unbind}))),trigger:X(e,(e=>e.trigger))}),Vu=e=>e.slice(0).sort(),Zu=(e,t,o)=>{if(0===t.length)throw new Error("You must specify at least one required field.");return((e,t)=>{if(!a(t))throw new Error("The "+e+" fields must be an array. Was: "+t+".");E(t,(t=>{if(!r(t))throw new Error("The value "+t+" in the "+e+" fields was not a string.")}))})("required",t),(e=>{const t=Vu(e);P(t,((e,o)=>o{throw new Error("The field: "+e+" occurs more than once in the combined fields: ["+t.join(", ")+"].")}))})(t),n=>{const r=W(n);B(t,(e=>A(r,e)))||((e,t)=>{throw new Error("All required keys ("+Vu(e).join(", ")+") were not specified. Specified keys were: "+Vu(t).join(", ")+".")})(t,r),e(t,r);const i=O(t,(e=>!o.validate(n[e],e)));return i.length>0&&((e,t)=>{throw new Error("All values need to be of type: "+t+". Keys ("+Vu(e).join(", ")+") were not.")})(i,o.label),n}},Wu=(e,t)=>{const o=O(t,(t=>!A(e,t)));o.length>0&&(e=>{throw new Error("Unsupported keys for object: "+Vu(e).join(", "))})(o)},Yu=e=>((e,t)=>Zu(e,t,{validate:u,label:"function"}))(Wu,e),Gu=Yu(["compare","extract","mutate","sink"]),Xu=Yu(["element","start","stop","destroy"]),Ju=Yu(["forceDrop","drop","move","delayDrop"]),Qu=()=>{let e=_.none();const t=Uu({move:Hu(["info"])});return{onEvent:(o,n)=>{n.extract(o).each((o=>{const r=((t,o)=>{const n=e.map((e=>t.compare(e,o)));return e=_.some(o),n})(n,o);r.each((e=>{t.trigger.move(e)}))}))},reset:()=>{e=_.none()},events:t.registry}},qu=()=>{const e=(()=>{const e=Uu({move:Hu(["info"])});return{onEvent:m,reset:m,events:e.registry}})(),t=Qu();let o=e;return{on:()=>{o.reset(),o=t},off:()=>{o.reset(),o=e},isOn:()=>o===t,onEvent:(e,t)=>{o.onEvent(e,t)},events:t.events}},Ku=(e,t,o)=>{let n=!1;const r=Uu({start:Hu([]),stop:Hu([])}),i=qu(),a=()=>{d.stop(),i.isOn()&&(i.off(),r.trigger.stop())},l=((e,t)=>{let o=null;const n=()=>{s(o)||(clearTimeout(o),o=null)};return{cancel:n,throttle:(...r)=>{n(),o=setTimeout((()=>{o=null,e.apply(null,r)}),t)}}})(a,200);i.events.move.bind((o=>{t.mutate(e,o.info)}));const c=e=>(...t)=>{n&&e.apply(null,t)},d=t.sink(Ju({forceDrop:a,drop:c(a),move:c((e=>{l.cancel(),i.onEvent(e,t)})),delayDrop:c(l.throttle)}),o);return{element:d.element,go:e=>{d.start(e),i.on(),r.trigger.start()},on:()=>{n=!0},off:()=>{n=!1},isActive:()=>n,destroy:()=>{d.destroy()},events:r.registry}},$u=e=>{const t=e.replace(/\./g,"-");return{resolve:e=>t+"-"+e}},eh=$u("ephox-dragster").resolve;var th=Gu({compare:(e,t)=>fn(t.left-e.left,t.top-e.top),extract:e=>_.some(fn(e.x,e.y)),sink:(e,t)=>{const o=(e=>{const t={layerClass:eh("blocker"),...e},o=Ce.fromTag("div");return fe(o,"role","presentation"),Lt(o,{position:"fixed",left:"0px",top:"0px",width:"100%",height:"100%"}),Au(o,eh("blocker")),Au(o,t.layerClass),{element:g(o),destroy:()=>{Ge(o)}}})(t),n=ju(o.element(),"mousedown",e.forceDrop),r=ju(o.element(),"mouseup",e.drop),i=ju(o.element(),"mousemove",e.move),a=ju(o.element(),"mouseout",e.delayDrop);return Xu({element:o.element,start:e=>{Ue(e,o.element())},stop:()=>{Ge(o.element())},destroy:()=>{o.destroy(),r.unbind(),i.unbind(),a.unbind(),n.unbind()}})},mutate:(e,t)=>{e.mutate(t.left,t.top)}});const oh=$u("ephox-snooker").resolve,nh=()=>{const e=Uu({drag:Hu(["xDelta","yDelta","target"])});let t=_.none();const o=(()=>{const e=Uu({drag:Hu(["xDelta","yDelta"])});return{mutate:(t,o)=>{e.trigger.drag(t,o)},events:e.registry}})();o.events.drag.bind((o=>{t.each((t=>{e.trigger.drag(o.xDelta,o.yDelta,t)}))}));return{assign:e=>{t=_.some(e)},get:()=>t,mutate:o.mutate,events:e.registry}},rh=oh("resizer-bar"),ih=oh("resizer-rows"),ah=oh("resizer-cols"),sh=e=>{const t=gt(e.parent(),"."+rh);E(t,Ge)},lh=(e,t,o)=>{const n=e.origin();E(t,(t=>{t.each((t=>{const r=o(n,t);Au(r,rh),Ue(e.parent(),r)}))}))},ch=(e,t,o,n)=>{lh(e,t,((e,t)=>{const r=((e,t,o,n,r)=>{const i=Ce.fromTag("div");return Lt(i,{position:"absolute",left:t-n/2+"px",top:o+"px",height:r+"px",width:n+"px"}),ve(i,{"data-column":e,role:"presentation"}),i})(t.col,t.x-e.left,o.top-e.top,7,n);return Au(r,ah),r}))},dh=(e,t,o,n)=>{lh(e,t,((e,t)=>{const r=((e,t,o,n,r)=>{const i=Ce.fromTag("div");return Lt(i,{position:"absolute",left:t+"px",top:o-r/2+"px",height:r+"px",width:n+"px"}),ve(i,{"data-row":e,role:"presentation"}),i})(t.row,o.left-e.left,t.y-e.top,n,7);return Au(r,ih),r}))},uh=(e,t,o,n,r)=>{const i=bn(o),a=t.isResizable,s=n.length>0?En.positions(n,o):[],l=s.length>0?((e,t)=>z(e.all,((e,o)=>t(e.element)?[o]:[])))(e,a):[],c=O(s,((e,t)=>M(l,(e=>t===e))));dh(t,c,i,Bo(o));const d=r.length>0?On.positions(r,o):[],u=d.length>0?((e,t)=>{const o=[];return T(e.grid.columns,(n=>{const r=nn.getColumnAt(e,n).map((e=>e.element));r.forall(t)&&o.push(n)})),O(o,(o=>{const n=nn.filterItems(e,(e=>e.column===o));return B(n,(e=>t(e.element)))}))})(e,a):[],h=O(d,((e,t)=>M(u,(e=>t===e))));ch(t,h,i,mn(o))},hh=(e,t)=>{if(sh(e),e.isResizable(t)){const o=nn.fromTable(t),n=sn(o),r=rn(o);uh(o,e,t,n,r)}},mh=(e,t)=>{const o=gt(e.parent(),"."+rh);E(o,t)},gh=e=>{mh(e,(e=>{Nt(e,"display","none")}))},ph=e=>{mh(e,(e=>{Nt(e,"display","block")}))},fh=oh("resizer-bar-dragging"),vh=e=>{const t=nh(),o=((e,t={})=>{var o;const n=null!==(o=t.mode)&&void 0!==o?o:th;return Ku(e,n,t)})(t,{});let n=_.none();const r=(e,t)=>_.from(be(e,t));t.events.drag.bind((e=>{r(e.target,"data-row").each((t=>{const o=Ut(e.target,"top");Nt(e.target,"top",o+e.yDelta+"px")})),r(e.target,"data-column").each((t=>{const o=Ut(e.target,"left");Nt(e.target,"left",o+e.xDelta+"px")}))}));const i=(e,t)=>Ut(e,t)-Bt(e,"data-initial-"+t,0);o.events.stop.bind((()=>{t.get().each((t=>{n.each((o=>{r(t,"data-row").each((e=>{const n=i(t,"top");ye(t,"data-initial-top"),d.trigger.adjustHeight(o,n,parseInt(e,10))})),r(t,"data-column").each((e=>{const n=i(t,"left");ye(t,"data-initial-left"),d.trigger.adjustWidth(o,n,parseInt(e,10))})),hh(e,o)}))}))}));const a=(n,r)=>{d.trigger.startAdjust(),t.assign(n),fe(n,"data-initial-"+r,Ut(n,r)),Au(n,fh),Nt(n,"opacity","0.2"),o.go(e.dragContainer())},s=ju(e.parent(),"mousedown",(e=>{var t;t=e.target,Mu(t,ih)&&a(e.target,"top"),(e=>Mu(e,ah))(e.target)&&a(e.target,"left")})),l=t=>Me(t,e.view()),c=ju(e.view(),"mouseover",(t=>{var r;(r=t.target,wt(r,"table",l).filter(ii)).fold((()=>{lt(t.target)&&sh(e)}),(t=>{o.isActive()&&(n=_.some(t),hh(e,t))}))})),d=Uu({adjustHeight:Hu(["table","delta","row"]),adjustWidth:Hu(["table","delta","column"]),startAdjust:Hu([])});return{destroy:()=>{s.unbind(),c.unbind(),o.destroy(),sh(e)},refresh:t=>{hh(e,t)},on:o.on,off:o.off,hideBars:v(gh,e),showBars:v(ph,e),events:d.registry}},bh=(e,t,o)=>{const n=En,r=On,i=vh(e),a=Uu({beforeResize:Hu(["table","type"]),afterResize:Hu(["table","type"]),startDrag:Hu([])});return i.events.adjustHeight.bind((e=>{const t=e.table;a.trigger.beforeResize(t,"row");const o=n.delta(e.delta,t);Es(t,o,e.row),a.trigger.afterResize(t,"row")})),i.events.startAdjust.bind((e=>{a.trigger.startDrag()})),i.events.adjustWidth.bind((e=>{const n=e.table;a.trigger.beforeResize(n,"col");const i=r.delta(e.delta,n),s=o(n);Is(n,i,e.column,t,s),a.trigger.afterResize(n,"col")})),{on:i.on,off:i.off,refreshBars:i.refresh,hideBars:i.hideBars,showBars:i.showBars,destroy:i.destroy,events:a.registry}};let xh=0;const yh=e=>{const t=(new Date).getTime(),o=Math.floor(window.crypto.getRandomValues(new Uint32Array(1))[0]/4294967295*1e9);return xh++,e+"_"+o+xh+String(t)},wh=(e,t)=>{const o=he(e)?(e=>Ce.fromDom(De(e).dom.documentElement))(e):e;return{parent:g(o),view:g(e),dragContainer:g(o),origin:g(fn(0,0)),isResizable:t}},_h=(e,t,o)=>({parent:g(t),view:g(e),dragContainer:g(t),origin:g(fn(0,0)),isResizable:o}),Ch=(e,t,o,n)=>({parent:g(t),view:g(e),dragContainer:g(o),origin:()=>bn(t),isResizable:n}),Sh=(e,t)=>{const o=(e=>!oi(e)&&"split"===ni(e))(e),n=Ce.fromDom(e.getBody()),r=(e=>{const t=yh("resizer-container"),o=Ce.fromTag("div");return fe(o,"id",t),Lt(o,{position:e,height:"0",width:"0",padding:"0",margin:"0",border:"0"}),o})(o?"relative":"static"),i=ct();return o?(Fe(n,r),Ch(n,r,i,t)):(Ue(i,r),_h(n,r,t))},kh=e=>d(e)&&"TABLE"===e.nodeName,Ah="bar-",Mh=e=>"false"!==be(e,"data-mce-resize"),Th=e=>{return Mt(t=e,o="corner-")?((e,t)=>e.substring(t))(t,o.length):t;var t,o},Ih=e=>{const t=Vd(),o=Vd(),n=Vd();let r,i,a,s;const l=t=>Hl(e,t),c=()=>Ur(e)?ya():xa(),d=(t,o,n,d)=>{const u=Th(o),h=Tt(u,"e"),m=Mt(u,"n");if(""===i&&sc(t),""===s&&cc(t),n!==r&&""!==i){Nt(t,"width",i);const o=c(),a=l(t),s=Ur(e)||h?(e=>wa(e).columns)(t)-1:0;Is(t,n-r,s,o,a)}else if((e=>/^(\d+(\.\d+)?)%$/.test(e))(i)){const e=parseFloat(i.replace("%",""));Nt(t,"width",n*e/r+"%")}if((e=>/^(\d+(\.\d+)?)px$/.test(e))(i)&&(e=>{const t=nn.fromTable(e);nn.hasColumns(t)||E(Xt(e),(e=>{const t=Pt(e,"width");Nt(e,"width",t),ye(e,"width")}))})(t),d!==a&&""!==s){Nt(t,"height",s);const e=m?0:(e=>wa(e).rows)(t)-1;Es(t,d-a,e)}},u=()=>{o.on((e=>{e.destroy()})),n.on((t=>{((e,t)=>{e.inline&&Ge(t.parent())})(e,t)}))};e.on("init",(()=>{const r=((e,t)=>e.inline?Sh(e,t):wh(Ce.fromDom(e.getDoc()),t))(e,Mh);if(n.set(r),(e=>{const t=e.options.get("object_resizing");return A(t.split(","),"table")})(e)&&Xr(e)){const n=c(),i=bh(r,n,l);e.mode.isReadOnly()||i.on(),i.events.startDrag.bind((o=>{t.set(e.selection.getRng())})),i.events.beforeResize.bind((t=>{const o=t.table.dom;((e,t,o,n,r)=>{e.dispatch("ObjectResizeStart",{target:t,width:o,height:n,origin:r})})(e,o,ui(o),hi(o),Ah+t.type)})),i.events.afterResize.bind((o=>{const n=o.table,r=n.dom;ci(n),t.on((t=>{e.selection.setRng(t),e.focus()})),((e,t,o,n,r)=>{e.dispatch("ObjectResized",{target:t,width:o,height:n,origin:r})})(e,r,ui(r),hi(r),Ah+o.type),e.undoManager.add()})),o.set(i)}})),e.on("ObjectResizeStart",(t=>{const o=t.target;if(kh(o)&&!e.mode.isReadOnly()){const n=Ce.fromDom(o);E(e.dom.select(".mce-clonedresizable"),(t=>{e.dom.addClass(t,"mce-"+Hr(e)+"-columns")})),!rc(n)&&Yr(e)?lc(n):!nc(n)&&Wr(e)&&sc(n),ic(n)&&Mt(t.origin,Ah)&&sc(n),r=t.width,i=Gr(e)?"":gi(e,o).getOr(""),a=t.height,s=pi(e,o).getOr("")}})),e.on("ObjectResized",(t=>{const o=t.target;if(kh(o)){const n=Ce.fromDom(o),r=t.origin;(e=>Mt(e,"corner-"))(r)&&d(n,r,t.width,t.height),ci(n),jl(e,n.dom,zl)}}));const h=()=>{o.on((e=>{e.on(),e.showBars()}))},m=()=>{o.on((e=>{e.off(),e.hideBars()}))};e.on("DisabledStateChange",(e=>{e.state?m():h()})),e.on("SwitchMode",(()=>{e.mode.isReadOnly()?m():h()})),e.on("dragstart dragend",(e=>{"dragstart"===e.type?m():h()})),e.on("remove",(()=>{u()}));return{refresh:e=>{o.on((t=>t.refreshBars(Ce.fromDom(e))))},hide:()=>{o.on((e=>e.hideBars()))},show:()=>{o.on((e=>e.showBars()))}}},Eh=e=>{(e=>{const t=e.options.register;t("table_clone_elements",{processor:"string[]"}),t("table_use_colgroups",{processor:"boolean",default:!0}),t("table_header_type",{processor:e=>{const t=A(["section","cells","sectionCells","auto"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be one of: section, cells, sectionCells or auto."}},default:"section"}),t("table_sizing_mode",{processor:"string",default:"auto"}),t("table_default_attributes",{processor:"object",default:{border:"1"}}),t("table_default_styles",{processor:"object",default:{"border-collapse":"collapse"}}),t("table_column_resizing",{processor:e=>{const t=A(["preservetable","resizetable"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be preservetable, or resizetable."}},default:"preservetable"}),t("table_resize_bars",{processor:"boolean",default:!0}),t("table_style_by_css",{processor:"boolean",default:!0}),t("table_merge_content_on_paste",{processor:"boolean",default:!0})})(e);const t=Ih(e),o=Fu(e,t),n=Ul(e,t,o);return Ec(e,n),((e,t)=>{const o=li(e),n=t=>na(di(e)).bind((n=>Qt(n,o).map((o=>{const r=ea(ra(e),o,n);return t(o,r)})))).getOr("");G({mceTableRowType:()=>n(t.getTableRowType),mceTableCellType:()=>n(t.getTableCellType),mceTableColType:()=>n(t.getTableColType)},((t,o)=>e.addQueryValueHandler(o,t)))})(e,n),aa(e,n),{getSelectedCells:o.getSelectedCells,clearSelectedCells:o.clearSelectedCells}},Dh=e=>({table:Eh(e)});e.add("dom",Dh)}()},1627(e,t,o){o(9504)},9504(){!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=(e,t,o)=>{const n="UL"===t?"InsertUnorderedList":"InsertOrderedList";e.execCommand(n,!1,!1===o?null:{"list-style-type":o})},o=e=>t=>t.options.get(e),n=o("advlist_number_styles"),r=o("advlist_bullet_styles"),i=e=>null==e,a=e=>!i(e);class s{constructor(e,t){this.tag=e,this.value=t}static some(e){return new s(!0,e)}static none(){return s.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?s.some(e(this.value)):s.none()}bind(e){return this.tag?e(this.value):s.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:s.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return a(e)?s.some(e):s.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}s.singletonNone=new s(!1);const l=Array.prototype.indexOf,c=(e,t)=>{return o=e,n=t,l.call(o,n)>-1;var o,n},d=Object.keys,u=(e,t)=>{const o={};return((e,t)=>{const o=d(e);for(let n=0,r=o.length;n{const r=t(e,n);o[r.k]=r.v})),o};var h=tinymce.util.Tools.resolve("tinymce.util.Tools");const m=e=>t=>a(t)&&e.test(t.nodeName),g=m(/^(OL|UL|DL)$/),p=m(/^(TH|TD)$/),f=(e,t,o)=>((e,t,o)=>{for(let n=0,r=e.length;ng(e)&&!/\btox\-/.test(e.className)),p).exists((t=>t.nodeName===o&&((e,t)=>e.dom.isChildOf(t,e.getBody()))(e,t))),v=e=>i(e)||"default"===e?"":e,b=(e,t)=>o=>((e,t)=>{const o=e.selection.getNode();return t({parents:e.dom.getParents(o),element:o}),e.on("NodeChange",t),()=>e.off("NodeChange",t)})(e,(n=>((e,n)=>{const r=e.selection.getStart(!0);o.setActive(f(e,n,t)),o.setEnabled(!((e,t)=>{const o=e.dom.getParent(t,"ol,ul,dl");return((e,t)=>null!==t&&!e.dom.isEditable(t))(e,o)||!e.selection.isEditable()})(e,r))})(e,n.parents))),x=(e,o,n,r,i,a)=>{const l={"lower-latin":"lower-alpha","upper-latin":"upper-alpha","lower-alpha":"lower-latin","upper-alpha":"upper-latin"},d=(m=e=>c(a,e),u(l,((e,t)=>({k:t,v:m(e,t)}))));var m;e.ui.registry.addSplitButton(o,{tooltip:n,icon:"OL"===i?"ordered-list":"unordered-list",presets:"listpreview",columns:3,fetch:e=>{e(h.map(a,(e=>{const t="OL"===i?"num":"bull",o="disc"===e||"decimal"===e?"default":e,n=v(e),r=(e=>e.replace(/\-/g," ").replace(/\b\w/g,(e=>e.toUpperCase())))(e);return{type:"choiceitem",value:n,icon:"list-"+t+"-"+o,text:r}})))},onAction:()=>e.execCommand(r),onItemAction:(o,n)=>{t(e,i,n)},select:t=>{const o=(e=>{const t=e.dom.getParent(e.selection.getNode(),"ol,ul"),o=e.dom.getStyle(t,"listStyleType");return s.from(o)})(e);return o.exists((e=>t===e||l[e]===t&&!d[t]))},onSetup:b(e,i)})},y=(e,o,n,r,i,a)=>{a.length>1?x(e,o,n,r,i,a):((e,o,n,r,i,a)=>{e.ui.registry.addToggleButton(o,{active:!1,tooltip:n,icon:"OL"===i?"ordered-list":"unordered-list",onSetup:b(e,i),onAction:()=>e.queryCommandState(r)||""===a?e.execCommand(r):t(e,i,a)})})(e,o,n,r,i,v(a[0]))};e.add("advlist",(e=>{e.hasPlugin("lists")?((e=>{const t=e.options.register;t("advlist_number_styles",{processor:"string[]",default:"default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman".split(",")}),t("advlist_bullet_styles",{processor:"string[]",default:"default,circle,square".split(",")})})(e),(e=>{y(e,"numlist","Numbered list","InsertOrderedList","OL",n(e)),y(e,"bullist","Bullet list","InsertUnorderedList","UL",r(e))})(e),(e=>{e.addCommand("ApplyUnorderedListStyle",((o,n)=>{t(e,"UL",n["list-style-type"])})),e.addCommand("ApplyOrderedListStyle",((o,n)=>{t(e,"OL",n["list-style-type"])}))})(e)):console.error("Please use the Lists plugin together with the List Styles plugin.")}))}()},2205(e,t,o){o(9914)},9914(){!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),o=t("autolink_pattern"),n=t("link_default_target"),r=t("link_default_protocol"),i=t("allow_unsafe_link_target"),a=(s="string",e=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=n=e,(r=String).prototype.isPrototypeOf(o)||(null===(i=n.constructor)||void 0===i?void 0:i.name)===r.name)?"string":t;var o,n,r,i})(e)===s);var s;const l=(c=void 0,e=>c===e);var c;const d=e=>!(e=>null==e)(e),u=Object.hasOwnProperty,h=e=>"\ufeff"===e;var m=tinymce.util.Tools.resolve("tinymce.dom.TextSeeker");const g=e=>3===e.nodeType,p=e=>/^[(\[{ \u00a0]$/.test(e),f=(e,t,o)=>{for(let n=t-1;n>=0;n--){const t=e.charAt(n);if(!h(t)&&o(t))return n}return-1},v=(e,t)=>{var n;const i=e.schema.getVoidElements(),a=o(e),{dom:s,selection:c}=e;if(null!==s.getParent(c.getNode(),"a[href]")||e.mode.isReadOnly())return null;const d=c.getRng(),h=m(s,(e=>{return s.isBlock(e)||(t=i,o=e.nodeName.toLowerCase(),u.call(t,o))||"false"===s.getContentEditable(e);var t,o})),{container:v,offset:b}=((e,t)=>{let o=e,n=t;for(;1===o.nodeType&&o.childNodes[n];)o=o.childNodes[n],n=g(o)?o.data.length:o.childNodes.length;return{container:o,offset:n}})(d.endContainer,d.endOffset),x=null!==(n=s.getParent(v,s.isBlock))&&void 0!==n?n:s.getRoot(),y=h.backwards(v,b+t,((e,t)=>{const o=e.data,n=f(o,t,(r=p,e=>!r(e)));var r,i;return-1===n||(i=o[n],/[?!,.;:]/.test(i))?n:n+1}),x);if(!y)return null;let w=y.container;const _=h.backwards(y.container,y.offset,((e,t)=>{w=e;const o=f(e.data,t,p);return-1===o?o:o+1}),x),C=s.createRng();_?C.setStart(_.container,_.offset):C.setStart(w,0),C.setEnd(y.container,y.offset);const S=C.toString().replace(/\uFEFF/g,"").match(a);if(S){let t=S[0];if(((e,t,o)=>""===t||e.length>=t.length&&e.substr(o,o+t.length)===t)(t,"www.",0)){t=r(e)+"://"+t}else((e,t,o=0,n)=>{const r=e.indexOf(t,o);return-1!==r&&(!!l(n)||r+t.length<=n)})(t,"@")&&!(e=>/^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(e))(t)&&(t="mailto:"+t);return{rng:C,url:t}}return null},b=(e,t)=>{const{dom:o,selection:r}=e,{rng:s,url:l}=t,c=r.getBookmark();r.setRng(s);const d="createlink",u={command:d,ui:!1,value:l};if(!e.dispatch("BeforeExecCommand",u).isDefaultPrevented()){e.getDoc().execCommand(d,!1,l),e.dispatch("ExecCommand",u);const t=n(e);if(a(t)){const n=r.getNode();o.setAttrib(n,"target",t),"_blank"!==t||i(e)||o.setAttrib(n,"rel","noopener")}}r.moveToBookmark(c),e.nodeChanged()},x=e=>{const t=v(e,-1);d(t)&&b(e,t)},y=x,w=e=>{e.on("keydown",(t=>{13!==t.keyCode||t.isDefaultPrevented()||(e=>{const t=v(e,0);d(t)&&b(e,t)})(e)})),e.on("keyup",(t=>{32===t.keyCode?x(e):(48===t.keyCode&&t.shiftKey||221===t.keyCode)&&y(e)}))};e.add("autolink",(e=>{(e=>{const t=e.options.register;t("autolink_pattern",{processor:"regexp",default:new RegExp("^"+/(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g.source+"$","i")}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"})})(e),w(e)}))}()},3847(e,t,o){o(1148)},1148(){!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");e.add("code",(e=>((e=>{e.addCommand("mceCodeEditor",(()=>{(e=>{const t=(e=>e.getContent({source_view:!0}))(e);e.windowManager.open({title:"Source Code",size:"large",body:{type:"panel",items:[{type:"textarea",name:"code"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{code:t},onSubmit:t=>{((e,t)=>{e.focus(),e.undoManager.transact((()=>{e.setContent(t)})),e.selection.setCursorLocation(),e.nodeChanged()})(e,t.getData().code),t.close()}})})(e)}))})(e),(e=>{const t=()=>e.execCommand("mceCodeEditor");e.ui.registry.addButton("code",{icon:"sourcecode",tooltip:"Source code",onAction:t}),e.ui.registry.addMenuItem("code",{icon:"sourcecode",text:"Source code",onAction:t})})(e),{})))}()},378(e,t,o){o(95)},95(){!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=r=e,n=(i=String).prototype,n.isPrototypeOf(o)||(null===(a=r.constructor)||void 0===a?void 0:a.name)===i.name)?"string":t;var o,n;var r,i,a})(t)===e,o=e=>t=>typeof t===e,n=t("string"),r=t("object"),i=t("array"),a=(s=null,e=>s===e);var s;const l=o("boolean"),c=e=>!(e=>null==e)(e),d=o("function"),u=(e,t)=>{if(i(e)){for(let o=0,n=e.length;o{},m=(e,t)=>e===t;class g{constructor(e,t){this.tag=e,this.value=t}static some(e){return new g(!0,e)}static none(){return g.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?g.some(e(this.value)):g.none()}bind(e){return this.tag?e(this.value):g.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:g.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return c(e)?g.some(e):g.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}g.singletonNone=new g(!1);const p=Array.prototype.indexOf,f=Array.prototype.push,v=(e,t)=>((e,t)=>p.call(e,t))(e,t)>-1,b=e=>{const t=[];for(let o=0,n=e.length;ob(((e,t)=>{const o=e.length,n=new Array(o);for(let r=0;r{for(let o=0;oe.exists((e=>o(e,t))),_=e=>{const t=[],o=e=>{t.push(e)};for(let t=0;te?g.some(t):g.none(),S=e=>t=>t.options.get(e),k=S("link_assume_external_targets"),A=S("link_context_toolbar"),M=S("link_list"),T=S("link_default_target"),I=S("link_default_protocol"),E=S("link_target_list"),D=S("link_rel_list"),O=S("link_class_list"),N=S("link_title"),L=S("allow_unsafe_link_target"),P=S("link_quicklink"),R=S("link_attributes_postprocess"),j=Object.keys,z=Object.hasOwnProperty,B=(e,t,o,n)=>{((e,t)=>{const o=j(e);for(let n=0,r=o.length;n{(t(e,r)?o:n)(e,r)}))},F=(e,t)=>z.call(e,t);var H=tinymce.util.Tools.resolve("tinymce.util.URI"),U=tinymce.util.Tools.resolve("tinymce.dom.TreeWalker"),V=tinymce.util.Tools.resolve("tinymce.util.Tools");const Z=e=>c(e)&&"a"===e.nodeName.toLowerCase(),W=e=>Z(e)&&!!X(e),Y=(e,t)=>{if(e.collapsed)return[];{const o=e.cloneContents(),n=o.firstChild,r=new U(n,o),i=[];let a=n;do{t(a)&&i.push(a)}while(a=r.next());return i}},G=e=>/^\w+:/i.test(e),X=e=>{var t,o;return null!==(o=null!==(t=e.getAttribute("data-mce-href"))&&void 0!==t?t:e.getAttribute("href"))&&void 0!==o?o:""},J=(e,t)=>{const o=["noopener"],n=e?e.split(/\s+/):[],r=e=>e.filter((e=>-1===V.inArray(o,e))),i=t?(e=>(e=r(e)).length>0?e.concat(o):o)(n):r(n);return i.length>0?(e=>V.trim(e.sort().join(" ")))(i):""},Q=(e,t)=>(t=t||$(e.selection.getRng())[0]||e.selection.getNode(),ne(t)?g.from(e.dom.select("a[href]",t)[0]):g.from(e.dom.getParent(t,"a[href]"))),q=(e,t)=>Q(e,t).isSome(),K=(e,t)=>(e=>e.replace(/\uFEFF/g,""))(t.fold((()=>e.getContent({format:"text"})),(e=>e.innerText||e.textContent||""))),$=e=>Y(e,W),ee=e=>V.grep(e,W),te=e=>ee(e).length>0,oe=e=>{const t=e.schema.getTextInlineElements(),o=e=>1===e.nodeType&&!Z(e)&&!F(t,e.nodeName.toLowerCase());if(Q(e).exists((e=>e.hasAttribute("data-mce-block"))))return!1;const n=e.selection.getRng();if(n.collapsed)return!0;return 0===Y(n,o).length},ne=e=>c(e)&&"FIGURE"===e.nodeName&&/\bimage\b/i.test(e.className),re=(e,t)=>{const o={...t};if(0===D(e).length&&!L(e)){const e=J(o.rel,"_blank"===o.target);o.rel=e||null}return g.from(o.target).isNone()&&!1===E(e)&&(o.target=T(e)),o.href=((e,t)=>"http"!==t&&"https"!==t||G(e)?e:t+"://"+e)(o.href,k(e)),o},ie=(e,t,o)=>{const n=e.selection.getNode(),r=Q(e,n),i=re(e,(e=>{return t=["title","rel","class","target"],o=(t,o)=>(e[o].each((e=>{t[o]=e.length>0?e:null})),t),n={href:e.href},((e,t)=>{for(let o=0,n=e.length;o{n=o(n,e,t)})),n;var t,o,n})(o)),a=R(e);c(a)&&a(i),e.undoManager.transact((()=>{o.href===t.href&&t.attach(),r.fold((()=>{((e,t,o,n)=>{const r=e.dom;ne(t)?de(r,t,n):o.fold((()=>{e.execCommand("mceInsertLink",!1,n);const t=e.selection.getEnd(),o=r.createRng();o.setStartAfter(t),o.setEndAfter(t),e.selection.setRng(o)}),(t=>{e.insertContent(r.createHTML("a",n,r.encode(t)))}))})(e,n,o.text,i)}),(t=>{e.focus(),((e,t,o,n)=>{o.each((e=>{F(t,"innerText")?t.innerText=e:t.textContent=e})),e.dom.setAttribs(t,n);const r=e.dom.createRng();r.setStartAfter(t),r.setEndAfter(t),e.selection.setRng(r)})(e,t,o.text,i)}))}))},ae=e=>{const{class:t,href:o,rel:n,target:r,text:i,title:s}=e;return((e,t)=>{const o={};var n;return B(e,t,(n=o,(e,t)=>{n[t]=e}),h),o})({class:t.getOrNull(),href:o,rel:n.getOrNull(),target:r.getOrNull(),text:i.getOrNull(),title:s.getOrNull()},((e,t)=>!1===a(e)))},se=(e,t,o)=>{const n=((e,t)=>{const o=e.options.get,n={allow_html_data_urls:o("allow_html_data_urls"),allow_script_urls:o("allow_script_urls"),allow_svg_data_urls:o("allow_svg_data_urls")},r=t.href;return{...t,href:H.isDomSafe(r,"a",n)?r:""}})(e,o);e.hasPlugin("rtc",!0)?e.execCommand("createlink",!1,ae(n)):ie(e,t,n)},le=e=>{e.hasPlugin("rtc",!0)?e.execCommand("unlink"):(e=>{e.undoManager.transact((()=>{const t=e.selection.getNode();ne(t)?ce(e,t):(e=>{const t=e.dom,o=e.selection,n=o.getBookmark(),r=o.getRng().cloneRange(),i=t.getParent(r.startContainer,"a[href]",e.getBody()),a=t.getParent(r.endContainer,"a[href]",e.getBody());i&&r.setStartBefore(i),a&&r.setEndAfter(a),o.setRng(r),e.execCommand("unlink"),o.moveToBookmark(n)})(e),e.focus()}))})(e)},ce=(e,t)=>{var o;const n=e.dom.select("img",t)[0];if(n){const r=e.dom.getParents(n,"a[href]",t)[0];r&&(null===(o=r.parentNode)||void 0===o||o.insertBefore(n,r),e.dom.remove(r))}},de=(e,t,o)=>{var n;const r=e.select("img",t)[0];if(r){const t=e.create("a",o);null===(n=r.parentNode)||void 0===n||n.insertBefore(t,r),t.appendChild(r)}},ue=e=>n(e.value)?e.value:"",he=(e,t)=>{const o=[];return V.each(e,(e=>{const r=(e=>n(e.text)?e.text:n(e.title)?e.title:"")(e);if(void 0!==e.menu){const n=he(e.menu,t);o.push({text:r,items:n})}else{const n=t(e);o.push({text:r,value:n})}})),o},me=(e=ue)=>t=>g.from(t).map((t=>he(t,e))),ge={sanitize:e=>me(ue)(e),sanitizeWith:me,createUi:(e,t)=>o=>({name:e,type:"listbox",label:t,items:o}),getValue:ue},pe=e=>{return F(t=e,o="items")&&void 0!==t[o]&&null!==t[o];var t,o},fe=(e,t)=>y(t,(t=>pe(t)?fe(e,t.items):C(t.value===e,t))),ve=(e,t,o,n)=>{const r=n[t],i=e.length>0;return void 0!==r?fe(r,o).map((t=>({url:{value:t.value,meta:{text:i?e:t.text,attach:h}},text:i?e:t.text}))):g.none()},be=(e,t)=>{const o={text:e.text,title:e.title},n=e=>{const t=(n=e.url,C(o.text.length<=0,g.from(null===(r=n.meta)||void 0===r?void 0:r.text).getOr(n.value)));var n,r;const i=(e=>{var t;return C(o.title.length<=0,g.from(null===(t=e.meta)||void 0===t?void 0:t.title).getOr(""))})(e.url);return t.isSome()||i.isSome()?g.some({...t.map((e=>({text:e}))).getOr({}),...i.map((e=>({title:e}))).getOr({})}):g.none()},r=(e,n)=>{const r=(i=t,a=n,"link"===a?i.link:"anchor"===a?i.anchor:g.none()).getOr([]);var i,a;return ve(o.text,n,r,e)};return{onChange:(e,t)=>{const i=t.name;return"url"===i?n(e()):v(["anchor","link"],i)?r(e(),i):"text"===i||"title"===i?(o[i]=e()[i],g.none()):g.none()}}};var xe=tinymce.util.Tools.resolve("tinymce.util.Delay");const ye=e=>{const t=e.href;return t.indexOf("@")>0&&-1===t.indexOf("/")&&-1===t.indexOf("mailto:")?g.some({message:"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",preprocess:e=>({...e,href:"mailto:"+t})}):g.none()},we=(e,t)=>o=>{const n=o.href;return 1===e&&!G(n)||0===e&&/^\s*www(\.|\d\.)/i.test(n)?g.some({message:`The URL you entered seems to be an external link. Do you want to add the required ${t}:// prefix?`,preprocess:e=>({...e,href:t+"://"+n})}):g.none()},_e=(e,t)=>y([ye,we(k(e),I(e))],(e=>e(t))).fold((()=>Promise.resolve(t)),(o=>new Promise((n=>{((e,t,o)=>{const n=e.selection.getRng();xe.setEditorTimeout(e,(()=>{e.windowManager.confirm(t,(t=>{e.selection.setRng(n),o(t)}))}))})(e,o.message,(e=>{n(e?o.preprocess(t):t)}))})))),Ce=e=>{const t=e.dom.select("a:not([href])"),o=x(t,(e=>{const t=e.name||e.id;return t?[{text:t,value:"#"+t}]:[]}));return o.length>0?g.some([{text:"None",value:""}].concat(o)):g.none()},Se=e=>{const t=O(e);return t.length>0?ge.sanitize(t):g.none()},ke=e=>{try{return g.some(JSON.parse(e))}catch(e){return g.none()}},Ae=e=>{const t=t=>e.convertURL(t.value||t.url||"","href"),o=M(e);return new Promise((e=>{n(o)?fetch(o).then((e=>e.ok?e.text().then(ke):Promise.reject())).then(e,(()=>e(g.none()))):d(o)?o((t=>e(g.some(t)))):e(g.from(o))})).then((e=>e.bind(ge.sanitizeWith(t)).map((e=>{if(e.length>0){return[{text:"None",value:""}].concat(e)}return e}))))},Me=(e,t)=>{const o=D(e);if(o.length>0){const n=w(t,"_blank"),r=e=>J(ge.getValue(e),n);return(!1===L(e)?ge.sanitizeWith(r):ge.sanitize)(o)}return g.none()},Te=[{text:"Current window",value:""},{text:"New window",value:"_blank"}],Ie=e=>{const t=E(e);return i(t)?ge.sanitize(t).orThunk((()=>g.some(Te))):!1===t?g.none():g.some(Te)},Ee=(e,t,o)=>{const n=e.getAttrib(t,o);return null!==n&&n.length>0?g.some(n):g.none()},De=(e,t)=>Ae(e).then((o=>{const n=((e,t)=>{const o=e.dom,n=oe(e)?g.some(K(e.selection,t)):g.none(),r=t.bind((e=>g.from(o.getAttrib(e,"href")))),i=t.bind((e=>g.from(o.getAttrib(e,"target")))),a=t.bind((e=>Ee(o,e,"rel"))),s=t.bind((e=>Ee(o,e,"class")));return{url:r,text:n,title:t.bind((e=>Ee(o,e,"title"))),target:i,rel:a,linkClass:s}})(e,t);return{anchor:n,catalogs:{targets:Ie(e),rels:Me(e,n.target),classes:Se(e),anchor:Ce(e),link:o},optNode:t,flags:{titleEnabled:N(e)}}})),Oe=e=>{const t=(e=>{const t=Q(e);return De(e,t)})(e);t.then((t=>{const o=((e,t)=>o=>{const n=o.getData();if(!n.url.value)return le(e),void o.close();const r=e=>g.from(n[e]).filter((o=>!w(t.anchor[e],o))),i={href:n.url.value,text:r("text"),target:r("target"),rel:r("rel"),class:r("linkClass"),title:r("title")},a={href:n.url.value,attach:void 0!==n.url.meta&&n.url.meta.attach?n.url.meta.attach:h};_e(e,i).then((t=>{se(e,a,t)})),o.close()})(e,t);return((e,t,o)=>{const n=e.anchor.text.map((()=>({name:"text",type:"input",label:"Text to display"}))).toArray(),r=e.flags.titleEnabled?[{name:"title",type:"input",label:"Title"}]:[],i=((e,t)=>{const o=e.anchor,n=o.url.getOr("");return{url:{value:n,meta:{original:{value:n}}},text:o.text.getOr(""),title:o.title.getOr(""),anchor:n,link:n,rel:o.rel.getOr(""),target:o.target.or(t).getOr(""),linkClass:o.linkClass.getOr("")}})(e,g.from(T(o))),a=e.catalogs,s=be(i,a);return{title:"Insert/Edit Link",size:"normal",body:{type:"panel",items:b([[{name:"url",type:"urlinput",filetype:"file",label:"URL",picker_text:"Browse links"}],n,r,_([a.anchor.map(ge.createUi("anchor","Anchors")),a.rels.map(ge.createUi("rel","Rel")),a.targets.map(ge.createUi("target","Open link in...")),a.link.map(ge.createUi("link","Link list")),a.classes.map(ge.createUi("linkClass","Class"))])])},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:i,onChange:(e,{name:t})=>{s.onChange(e.getData,{name:t}).each((t=>{e.setData(t)}))},onSubmit:t}})(t,o,e)})).then((t=>{e.windowManager.open(t)}))},Ne=()=>{const e=(e=>{const t=(e=>{let t=e;return{get:()=>t,set:e=>{t=e}}})(g.none()),o=()=>t.get().each(e);return{clear:()=>{o(),t.set(g.none())},isSet:()=>t.get().isSome(),get:()=>t.get(),set:e=>{o(),t.set(g.some(e))}}})(h);return{...e,on:t=>e.get().each(t)}},Le=(e,t)=>((e,t,o)=>""===t||e.length>=t.length&&e.substr(o,o+t.length)===t)(e,t,0);var Pe=tinymce.util.Tools.resolve("tinymce.util.VK");const Re=e=>{const t=document.createElement("a");t.target="_blank",t.href=e,t.rel="noreferrer noopener";const o=new MouseEvent("click",{bubbles:!0,cancelable:!0,view:window});document.dispatchEvent(o),((e,t)=>{document.body.appendChild(e),e.dispatchEvent(t),document.body.removeChild(e)})(t,o)},je=(e,t)=>{if(t){const r=X(t);if(/^#/.test(r)){const t=e.dom.select(`${r},[name="${o=r,n="#",Le(o,n)?((e,t)=>e.substring(t))(o,n.length):o}"]`);t.length&&e.selection.scrollIntoView(t[0],!0)}else Re(t.href)}var o,n},ze=(e,t)=>{const o=ee(e.dom.getParents(t));return C(1===o.length,o[0])},Be=e=>e.selection.isCollapsed()||(e=>{const t=e.selection.getRng(),o=t.startContainer;return W(o)&&t.startContainer===t.endContainer&&1===e.dom.select("img",o).length})(e)?ze(e,e.selection.getStart()):(e=>{const t=$(e.selection.getRng());return C(t.length>0,t[0]).or(ze(e,e.selection.getNode()))})(e),Fe=e=>()=>{e.execCommand("mceLink",!1,{dialog:!0})},He=(e,t)=>(e.on("NodeChange",t),()=>e.off("NodeChange",t)),Ue=e=>t=>{const o=()=>{t.setActive(!e.mode.isReadOnly()&&q(e,e.selection.getNode())),t.setEnabled(e.selection.isEditable())};return o(),He(e,o)},Ve=e=>t=>{const o=()=>{t.setEnabled(e.selection.isEditable())};return o(),He(e,o)},Ze=e=>t=>{const o=t=>{return te(t)||(o=e.selection.getRng(),$(o).length>0);var o},n=e.dom.getParents(e.selection.getStart()),r=n=>{t.setEnabled(o(n)&&e.selection.isEditable())};return r(n),He(e,(e=>r(e.parents)))},We=(e,t)=>{const o=t=>{const o=e.selection.getNode();return t.setEnabled(q(e,o)&&e.selection.isEditable()),h};e.ui.registry.addContextForm("quicklink",{launch:{type:"contextformtogglebutton",icon:"link",tooltip:"Link",onSetup:Ue(e)},label:"Link",predicate:t=>A(e)&&q(e,t),initValue:()=>Q(e).fold((e=>()=>e)(""),X),commands:[{type:"contextformtogglebutton",icon:"link",tooltip:"Link",primary:!0,onSetup:t=>{const o=e.selection.getNode();return t.setActive(q(e,o)),Ue(e)(t)},onAction:t=>{const o=t.getValue(),n=(t=>{const o=Q(e),n=oe(e);if(o.isNone()&&n){const n=K(e.selection,o);return C(0===n.length,t)}return g.none()})(o);se(e,{href:o,attach:h},{href:o,text:n,title:g.none(),rel:g.none(),target:g.from(T(e)),class:g.none()}),(e=>{e.selection.collapse(!1)})(e),t.hide()}},{type:"contextformbutton",icon:"unlink",tooltip:"Remove link",onSetup:o,onAction:t=>{le(e),t.hide()}},{type:"contextformbutton",icon:"new-tab",tooltip:"Open link",onSetup:o,onAction:e=>{t.gotoSelectedLink(),e.hide()}}]})},Ye=e=>{const t=(e=>{const t=Ne(),o=()=>t.get().or(Be(e));return e.on("contextmenu",(o=>{ze(e,o.target).each(t.set)})),e.on("SelectionChange",(()=>{t.isSet()||Be(e).each(t.set)})),e.on("click",(o=>{t.clear();const n=ee(e.dom.getParents(o.target));1===n.length&&Pe.metaKeyPressed(o)&&(o.preventDefault(),je(e,n[0]))})),e.on("keydown",(n=>{t.clear(),!n.isDefaultPrevented()&&13===n.keyCode&&(e=>!0===e.altKey&&!1===e.shiftKey&&!1===e.ctrlKey&&!1===e.metaKey)(n)&&o().each((t=>{n.preventDefault(),je(e,t)}))})),{gotoSelectedLink:()=>o().each((t=>je(e,t)))}})(e);((e,t)=>{e.ui.registry.addToggleButton("link",{icon:"link",tooltip:"Insert/edit link",shortcut:"Meta+K",onAction:Fe(e),onSetup:Ue(e)}),e.ui.registry.addButton("openlink",{icon:"new-tab",tooltip:"Open link",onAction:t.gotoSelectedLink,onSetup:Ze(e)}),e.ui.registry.addButton("unlink",{icon:"unlink",tooltip:"Remove link",onAction:()=>le(e),onSetup:Ze(e)})})(e,t),((e,t)=>{e.ui.registry.addMenuItem("openlink",{text:"Open link",icon:"new-tab",onAction:t.gotoSelectedLink,onSetup:Ze(e)}),e.ui.registry.addMenuItem("link",{icon:"link",text:"Link...",shortcut:"Meta+K",onAction:Fe(e),onSetup:Ve(e)}),e.ui.registry.addMenuItem("unlink",{icon:"unlink",text:"Remove link",onAction:()=>le(e),onSetup:Ze(e)})})(e,t),(e=>{e.ui.registry.addContextMenu("link",{update:t=>e.dom.isEditable(t)?te(e.dom.getParents(t,"a"))?"link unlink openlink":"link":""})})(e),We(e,t)};e.add("link",(e=>{(e=>{const t=e.options.register;t("link_assume_external_targets",{processor:e=>{const t=n(e)||l(e);return t?!0===e?{value:1,valid:t}:"http"===e||"https"===e?{value:e,valid:t}:{value:0,valid:t}:{valid:!1,message:"Must be a string or a boolean."}},default:!1}),t("link_context_toolbar",{processor:"boolean",default:!1}),t("link_list",{processor:e=>n(e)||d(e)||u(e,r)}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"}),t("link_target_list",{processor:e=>l(e)||u(e,r),default:!0}),t("link_rel_list",{processor:"object[]",default:[]}),t("link_class_list",{processor:"object[]",default:[]}),t("link_title",{processor:"boolean",default:!0}),t("allow_unsafe_link_target",{processor:"boolean",default:!1}),t("link_quicklink",{processor:"boolean",default:!1}),t("link_attributes_postprocess",{processor:"function"})})(e),(e=>{e.addCommand("mceLink",((t,o)=>{!0!==(null==o?void 0:o.dialog)&&P(e)?e.dispatch("contexttoolbar-show",{toolbarKey:"quicklink"}):Oe(e)}))})(e),Ye(e),(e=>{e.addShortcut("Meta+K","",(()=>{e.execCommand("mceLink")}))})(e)}))}()},5775(e,t,o){o(7524)},7524(){!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=r=e,n=(i=String).prototype,n.isPrototypeOf(o)||(null===(a=r.constructor)||void 0===a?void 0:a.name)===i.name)?"string":t;var o,n;var r,i,a})(t)===e,o=e=>t=>typeof t===e,n=t("string"),r=t("object"),i=t("array"),a=o("boolean"),s=e=>!(e=>null==e)(e),l=o("function"),c=o("number"),d=()=>{},u=e=>()=>e,h=(e,t)=>e===t;const m=e=>t=>!e(t),g=u(!1);class p{constructor(e,t){this.tag=e,this.value=t}static some(e){return new p(!0,e)}static none(){return p.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?p.some(e(this.value)):p.none()}bind(e){return this.tag?e(this.value):p.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:p.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return s(e)?p.some(e):p.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}p.singletonNone=new p(!1);const f=Array.prototype.slice,v=Array.prototype.indexOf,b=Array.prototype.push,x=(e,t)=>{return o=e,n=t,v.call(o,n)>-1;var o,n},y=(e,t)=>{for(let o=0,n=e.length;o{const o=e.length,n=new Array(o);for(let r=0;r{for(let o=0,n=e.length;o{const o=[];for(let n=0,r=e.length;n(_(e,((e,n)=>{o=t(o,e,n)})),o),k=(e,t,o)=>{for(let n=0,r=e.length;nk(e,t,g),M=(e,t)=>(e=>{const t=[];for(let o=0,n=e.length;o{const t=f.call(e,0);return t.reverse(),t},I=(e,t)=>t>=0&&tI(e,0),D=e=>I(e,e.length-1),O=(e,t)=>{const o=[],n=l(t)?e=>y(o,(o=>t(o,e))):e=>x(o,e);for(let t=0,r=e.length;te.exists((e=>o(e,t))),L=(e,t,o)=>e.isSome()&&t.isSome()?p.some(o(e.getOrDie(),t.getOrDie())):p.none(),P=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},R={fromHtml:(e,t)=>{const o=(t||document).createElement("div");if(o.innerHTML=e,!o.hasChildNodes()||o.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return P(o.childNodes[0])},fromTag:(e,t)=>{const o=(t||document).createElement(e);return P(o)},fromText:(e,t)=>{const o=(t||document).createTextNode(e);return P(o)},fromDom:P,fromPoint:(e,t,o)=>p.from(e.dom.elementFromPoint(t,o)).map(P)},j=(e,t)=>{const o=e.dom;if(1!==o.nodeType)return!1;{const e=o;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},z=(e,t)=>e.dom===t.dom,B=j,F="undefined"!=typeof window?window:Function("return this;")(),H=(e,t)=>((e,t)=>{let o=null!=t?t:F;for(let t=0;t{const o=((e,t)=>H(e,t))(e,t);if(null==o)throw new Error(e+" not available on this browser");return o},V=Object.getPrototypeOf,Z=e=>{const t=H("ownerDocument.defaultView",e);return r(e)&&((e=>U("HTMLElement",e))(t).prototype.isPrototypeOf(e)||/^HTML\w*Element$/.test(V(e).constructor.name))},W=e=>e.dom.nodeName.toLowerCase(),Y=e=>e.dom.nodeType,G=e=>t=>Y(t)===e,X=e=>J(e)&&Z(e.dom),J=G(1),Q=G(3),q=G(11),K=e=>t=>J(t)&&W(t)===e,$=e=>p.from(e.dom.parentNode).map(R.fromDom),ee=e=>w(e.dom.childNodes,R.fromDom),te=(e,t)=>{const o=e.dom.childNodes;return p.from(o[t]).map(R.fromDom)},oe=e=>te(e,0),ne=e=>te(e,e.dom.childNodes.length-1),re=e=>{const t=(e=>R.fromDom(e.dom.getRootNode()))(e);return q(o=t)&&s(o.dom.host)?p.some(t):p.none();var o},ie=e=>R.fromDom(e.dom.host),ae=e=>{const t=Q(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const o=t.ownerDocument;return re(R.fromDom(t)).fold((()=>o.body.contains(t)),(n=ae,r=ie,e=>n(r(e))));var n,r};var se=(e,t,o,n,r)=>e(o,n)?p.some(o):l(r)&&r(o)?p.none():t(o,n,r);const le=(e,t,o)=>{let n=e.dom;const r=l(o)?o:g;for(;n.parentNode;){n=n.parentNode;const e=R.fromDom(n);if(t(e))return p.some(e);if(r(e))break}return p.none()},ce=(e,t,o)=>se(((e,t)=>t(e)),le,e,t,o),de=(e,t,o)=>le(e,(e=>j(e,t)),o),ue=e=>{return se(((e,t)=>j(e,t)),de,e,"[contenteditable]",t);var t},he=e=>e.dom.contentEditable,me=(e,t)=>{$(e).each((o=>{o.dom.insertBefore(t.dom,e.dom)}))},ge=(e,t)=>{const o=(e=>p.from(e.dom.nextSibling).map(R.fromDom))(e);o.fold((()=>{$(e).each((e=>{pe(e,t)}))}),(e=>{me(e,t)}))},pe=(e,t)=>{e.dom.appendChild(t.dom)},fe=(e,t)=>{_(t,(t=>{pe(e,t)}))},ve=e=>{e.dom.textContent="",_(ee(e),(e=>{be(e)}))},be=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)};var xe=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),ye=tinymce.util.Tools.resolve("tinymce.dom.TreeWalker"),we=tinymce.util.Tools.resolve("tinymce.util.VK");const _e=e=>w(e,R.fromDom),Ce=Object.keys,Se=(e,t)=>{const o=Ce(e);for(let n=0,r=o.length;n{const o={};var n;return((e,t,o,n)=>{Se(e,((e,r)=>{(t(e,r)?o:n)(e,r)}))})(e,t,(n=o,(e,t)=>{n[t]=e}),d),o},Ae=(e,t)=>{const o=e.dom;Se(t,((e,t)=>{((e,t,o)=>{if(!(n(o)||a(o)||c(o)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",o,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,o+"")})(o,t,e)}))},Me=e=>S(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}),Te=e=>((e,t)=>R.fromDom(e.dom.cloneNode(t)))(e,!0),Ie=(e,t)=>{const o=((e,t)=>{const o=R.fromTag(t),n=Me(e);return Ae(o,n),o})(e,t);ge(e,o);const n=ee(e);return fe(o,n),be(e),o};var Ee=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),De=tinymce.util.Tools.resolve("tinymce.util.Tools");const Oe=e=>t=>s(t)&&t.nodeName.toLowerCase()===e,Ne=e=>t=>s(t)&&e.test(t.nodeName),Le=e=>s(e)&&3===e.nodeType,Pe=e=>s(e)&&1===e.nodeType,Re=Ne(/^(OL|UL|DL)$/),je=Ne(/^(OL|UL)$/),ze=Oe("ol"),Be=Ne(/^(LI|DT|DD)$/),Fe=Ne(/^(DT|DD)$/),He=Ne(/^(TH|TD)$/),Ue=Oe("br"),Ve=(e,t)=>s(t)&&t.nodeName in e.schema.getTextBlockElements(),Ze=(e,t)=>s(e)&&e.nodeName in t,We=(e,t)=>s(t)&&t.nodeName in e.schema.getVoidElements(),Ye=(e,t,o)=>{const n=e.isEmpty(t);return!(o&&e.select("span[data-mce-type=bookmark]",t).length>0)&&n},Ge=(e,t)=>e.isChildOf(t,e.getRoot()),Xe=e=>t=>t.options.get(e),Je=Xe("lists_indent_on_tab"),Qe=Xe("forced_root_block"),qe=Xe("forced_root_block_attrs"),Ke=(e,t,o={})=>{const n=e.dom,r=e.schema.getBlockElements(),i=n.createFragment(),a=Qe(e),s=qe(e);let l,c,d=!1;for(c=n.create(a,{...s,...o.style?{style:o.style}:{}}),Ze(t.firstChild,r)||i.appendChild(c);l=t.firstChild;){const e=l.nodeName;d||"SPAN"===e&&"bookmark"===l.getAttribute("data-mce-type")||(d=!0),Ze(l,r)?(i.appendChild(l),c=null):(c||(c=n.create(a,s),i.appendChild(c)),c.appendChild(l))}return!d&&c&&c.appendChild(n.create("br",{"data-mce-bogus":"1"})),i},$e=Ee.DOM,et=(e,t,o)=>{const n=$e.select('span[data-mce-type="bookmark"]',t),r=Ke(e,o),i=$e.createRng();i.setStartAfter(o),i.setEndAfter(t);const a=i.extractContents();for(let t=a.firstChild;t;t=t.firstChild)if("LI"===t.nodeName&&e.dom.isEmpty(t)){$e.remove(t);break}e.dom.isEmpty(a)||$e.insertAfter(a,t),$e.insertAfter(r,t);const s=o.parentElement;s&&Ye(e.dom,s)&&(e=>{const t=e.parentNode;t&&De.each(n,(e=>{t.insertBefore(e,o.parentNode)})),$e.remove(e)})(s),$e.remove(o),Ye(e.dom,t)&&$e.remove(t)},tt=K("dd"),ot=K("dt"),nt=(e,t)=>{var o;tt(t)?Ie(t,"dt"):ot(t)&&(o=t,p.from(o.dom.parentElement).map(R.fromDom)).each((o=>et(e,o.dom,t.dom)))},rt=e=>{ot(e)&&Ie(e,"dd")},it=(e,t)=>{if(Le(e))return{container:e,offset:t};const o=xe.getNode(e,t);return Le(o)?{container:o,offset:t>=e.childNodes.length?o.data.length:0}:o.previousSibling&&Le(o.previousSibling)?{container:o.previousSibling,offset:o.previousSibling.data.length}:o.nextSibling&&Le(o.nextSibling)?{container:o.nextSibling,offset:0}:{container:e,offset:t}},at=e=>{const t=e.cloneRange(),o=it(e.startContainer,e.startOffset);t.setStart(o.container,o.offset);const n=it(e.endContainer,e.endOffset);return t.setEnd(n.container,n.offset),t},st=["OL","UL","DL"],lt=st.join(","),ct=(e,t)=>{const o=t||e.selection.getStart(!0);return e.dom.getParent(o,lt,mt(e,o))},dt=e=>{const t=ct(e),o=e.selection.getSelectedBlocks();return((e,t)=>s(e)&&1===t.length&&t[0]===e)(t,o)?(e=>C(e.querySelectorAll(lt),Re))(t):C(o,(e=>Re(e)&&t!==e))},ut=e=>{const t=e.selection.getSelectedBlocks();return C(((e,t)=>{const o=De.map(t,(t=>e.dom.getParent(t,"li,dd,dt",mt(e,t))||t));return O(o)})(e,t),Be)},ht=(e,t)=>{const o=e.dom.getParents(t,"TD,TH");return o.length>0?o[0]:e.getBody()},mt=(e,t)=>{const o=e.dom.getParents(t,e.dom.isBlock),n=A(o,(t=>{return(t=>t.nodeName.toLowerCase()!==Qe(e))(t)&&(o=e.schema,!Re(n=t)&&!Be(n)&&y(st,(e=>o.isValidChild(n.nodeName,e))));var o,n}));return n.getOr(e.getBody())},gt=(e,t)=>{const o=e.dom.getParents(t,"ol,ul",mt(e,t));return D(o)},pt=e=>{const t=(e=>{const t=gt(e,e.selection.getStart()),o=C(e.selection.getSelectedBlocks(),je);return t.toArray().concat(o)})(e),o=(e=>{const t=e.selection.getStart();return e.dom.getParents(t,"ol,ul",mt(e,t))})(e);return A(o,(e=>{return t=R.fromDom(e),$(t).exists((e=>Be(e.dom)&&oe(e).exists((e=>!Re(e.dom)))&&ne(e).exists((e=>!Re(e.dom)))));var t})).fold((()=>ft(e,t)),(e=>[e]))},ft=(e,t)=>{const o=w(t,(t=>gt(e,t).getOr(t)));return O(o)},vt=e=>/\btox\-/.test(e.className),bt=(e,t)=>k(e,Re,He).exists((e=>e.nodeName===t&&!vt(e))),xt=(e,t)=>null!==t&&!e.dom.isEditable(t),yt=(e,t)=>{const o=e.dom.getParent(t,"ol,ul,dl");return xt(e,o)||!e.selection.isEditable()},wt=(e,t)=>{const o=e.selection.getNode();return t({parents:e.dom.getParents(o),element:o}),e.on("NodeChange",t),()=>e.off("NodeChange",t)},_t=(e,t)=>{const o=(t||document).createDocumentFragment();return _(e,(e=>{o.appendChild(e.dom)})),R.fromDom(o)},Ct=(e,t,o)=>e.dispatch("ListMutation",{action:t,element:o}),St=(kt=/^\s+|\s+$/g,e=>e.replace(kt,""));var kt;const At=(e,t,o)=>{if(!n(o))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",o,":: Element ",e),new Error("CSS value must be a string: "+o);(e=>void 0!==e.style&&l(e.style.getPropertyValue))(e)&&e.style.setProperty(t,o)},Mt=(e,t,o)=>{const n=e.dom;At(n,t,o)},Tt=e=>B(e,"OL,UL"),It=e=>oe(e).exists(Tt),Et=e=>"listAttributes"in e,Dt=e=>"isComment"in e,Ot=e=>e.depth>0,Nt=e=>e.isSelected,Lt=e=>{const t=ee(e),o=ne(e).exists(Tt)?t.slice(0,-1):t;return w(o,Te)},Pt=(e,t)=>{pe(e.item,t.list)},Rt=(e,t)=>{const o={list:R.fromTag(t,e),item:R.fromTag("li",e)};return pe(o.list,o.item),o},jt=(e,t,o)=>{const n=t.slice(0,o.depth);return D(n).each((t=>{if(Et(o)){const n=((e,t,o)=>{const n=R.fromTag("li",e);return Ae(n,t),fe(n,o),n})(e,o.itemAttributes,o.content);((e,t)=>{pe(e.list,t),e.item=t})(t,n),((e,t)=>{W(e.list)!==t.listType&&(e.list=Ie(e.list,t.listType)),Ae(e.list,t.listAttributes)})(t,o)}else if((e=>"isFragment"in e)(o))fe(t.item,o.content);else{const e=R.fromHtml(`\x3c!--${o.content}--\x3e`);pe(t.list,e)}})),n},zt=(e,t,o)=>{const n=((e,t,o)=>{const n=[];for(let r=0;r{for(let t=1;t{for(let t=0;t{Et(t)&&(Ae(e.list,t.listAttributes),Ae(e.item,t.itemAttributes)),fe(e.item,t.content)}))})(n,o),r=n,L(D(t),E(r),Pt),t.concat(n)},Bt=(e,t)=>{let o=p.none();const n=S(t,((t,n,r)=>Dt(n)?0===r?(o=p.some(n),t):jt(e,t,n):n.depth>t.length?zt(e,t,n):jt(e,t,n)),[]);return o.each((e=>{const t=R.fromHtml(`\x3c!--${e.content}--\x3e`);E(n).each((e=>{((e,t)=>{oe(e).fold((()=>{pe(e,t)}),(o=>{e.dom.insertBefore(t.dom,o.dom)}))})(e.list,t)}))})),E(n).map((e=>e.list))},Ft=e=>(_(e,((t,o)=>{((e,t)=>{const o=e[t].depth,n=e=>e.depth===o&&!e.dirty,r=e=>e.depthk(e.slice(t+1),n,r)))})(e,o).fold((()=>{t.dirty&&Et(t)&&(e=>{e.listAttributes=ke(e.listAttributes,((e,t)=>"start"!==t))})(t)}),(e=>{return n=e,void(Et(o=t)&&Et(n)&&(o.listType=n.listType,o.listAttributes={...n.listAttributes}));var o,n}))})),e),Ht=(e,t,o,n)=>{var r,i;if(8===Y(i=n)||"#comment"===W(i))return[{depth:e+1,content:null!==(r=n.dom.nodeValue)&&void 0!==r?r:"",dirty:!1,isSelected:!1,isComment:!0}];t.each((e=>{z(e.start,n)&&o.set(!0)}));const a=((e,t,o)=>$(e).filter(J).map((n=>({depth:t,dirty:!1,isSelected:o,content:Lt(e),itemAttributes:Me(e),listAttributes:Me(n),listType:W(n),isInPreviousLi:!1}))))(n,e,o.get());t.each((e=>{z(e.end,n)&&o.set(!1)}));const s=ne(n).filter(Tt).map((n=>Vt(e,t,o,n))).getOr([]);return a.toArray().concat(s)},Ut=(e,t,o,n)=>oe(n).filter(Tt).fold((()=>Ht(e,t,o,n)),(r=>{const i=S(ee(n),((n,i,a)=>{if(0===a)return n;if(B(i,"LI"))return n.concat(Ht(e,t,o,i));{const t={isFragment:!0,depth:e,content:[i],isSelected:!1,dirty:!1,parentListType:W(r)};return n.concat(t)}}),[]);return Vt(e,t,o,r).concat(i)})),Vt=(e,t,o,n)=>M(ee(n),(n=>(Tt(n)?Vt:Ut)(e+1,t,o,n))),Zt=(e,t)=>M(((e,t)=>{if(0===e.length)return[];{let o=t(e[0]);const n=[];let r=[];for(let i=0,a=e.length;iE(t).exists(Ot)?((e,t)=>{const o=Ft(t);return Bt(e.contentDocument,o).toArray()})(e,t):((e,t)=>{const o=Ft(t);return w(o,(t=>{const o=Dt(t)?_t([R.fromHtml(`\x3c!--${t.content}--\x3e`)]):_t(t.content),n=Et(t)?t.itemAttributes:{};return R.fromDom(Ke(e,o.dom,n))}))})(e,t))),Wt=(e,t,o)=>{const n=((e,t)=>{const o=(()=>{let e=!1;return{get:()=>e,set:t=>{e=t}}})();return w(e,(e=>({sourceList:e,entries:Vt(0,t,o,e)})))})(t,(e=>{const t=w(ut(e),R.fromDom);return L(A(t,m(It)),A(T(t),m(It)),((e,t)=>({start:e,end:t})))})(e));_(n,(t=>{((e,t)=>{_(C(e,Nt),(e=>((e,t)=>{switch(e){case"Indent":t.depth++;break;case"Outdent":t.depth--;break;case"Flatten":t.depth=0}t.dirty=!0})(t,e)))})(t.entries,o);const n=Zt(e,t.entries);var r;_(n,(t=>{Ct(e,"Indent"===o?"IndentList":"OutdentList",t.dom)})),r=t.sourceList,_(n,(e=>{me(r,e)})),be(t.sourceList)}))},Yt=(e,t)=>{const o=_e(pt(e)),n=_e((e=>C(ut(e),Fe))(e));let r=!1;if(o.length||n.length){const i=e.selection.getBookmark();Wt(e,o,t),((e,t,o)=>{_(o,"Indent"===t?rt:t=>nt(e,t))})(e,t,n),e.selection.moveToBookmark(i),e.selection.setRng(at(e.selection.getRng())),e.nodeChanged(),r=!0}return r},Gt=(e,t)=>!(e=>{const t=ct(e);return xt(e,t)||!e.selection.isEditable()})(e)&&Yt(e,t),Xt=e=>Gt(e,"Indent"),Jt=e=>Gt(e,"Outdent"),Qt=e=>Gt(e,"Flatten"),qt=e=>"\ufeff"===e,Kt=(e,t)=>{return o=e,n=function(e,...t){return(...o)=>{const n=t.concat(o);return e.apply(null,n)}}(z,t),le(o,n,r).isSome();var o,n,r};var $t=tinymce.util.Tools.resolve("tinymce.dom.BookmarkManager");const eo=Ee.DOM,to=e=>{const t={},o=o=>{let n=e[o?"startContainer":"endContainer"],r=e[o?"startOffset":"endOffset"];if(Pe(n)){const e=eo.create("span",{"data-mce-type":"bookmark"});n.hasChildNodes()?(r=Math.min(r,n.childNodes.length-1),o?n.insertBefore(e,n.childNodes[r]):eo.insertAfter(e,n.childNodes[r])):n.appendChild(e),n=e,r=0}t[o?"startContainer":"endContainer"]=n,t[o?"startOffset":"endOffset"]=r};return o(!0),e.collapsed||o(),t},oo=e=>{const t=t=>{let o=e[t?"startContainer":"endContainer"],n=e[t?"startOffset":"endOffset"];if(o){if(Pe(o)&&o.parentNode){const e=o;n=(e=>{var t;let o=null===(t=e.parentNode)||void 0===t?void 0:t.firstChild,n=0;for(;o;){if(o===e)return n;Pe(o)&&"bookmark"===o.getAttribute("data-mce-type")||n++,o=o.nextSibling}return-1})(o),o=o.parentNode,eo.remove(e),!o.hasChildNodes()&&eo.isBlock(o)&&o.appendChild(eo.create("br"))}e[t?"startContainer":"endContainer"]=o,e[t?"startOffset":"endOffset"]=n}};t(!0),t();const o=eo.createRng();return o.setStart(e.startContainer,e.startOffset),e.endContainer&&o.setEnd(e.endContainer,e.endOffset),at(o)},no=e=>{switch(e){case"UL":return"ToggleUlList";case"OL":return"ToggleOlList";case"DL":return"ToggleDLList"}},ro=(e,t)=>{De.each(t,((t,o)=>{e.setAttribute(o,t)}))},io=(e,t,o)=>{((e,t,o)=>{const n=o["list-style-type"]?o["list-style-type"]:null;e.setStyle(t,"list-style-type",n)})(e,t,o),((e,t,o)=>{ro(t,o["list-attributes"]),De.each(e.select("li",t),(e=>{ro(e,o["list-item-attributes"])}))})(e,t,o)},ao=(e,t)=>s(t)&&!Ze(t,e.schema.getBlockElements()),so=(e,t,o,n)=>{let r=t[o?"startContainer":"endContainer"];const i=t[o?"startOffset":"endOffset"];Pe(r)&&(r=r.childNodes[Math.min(i,r.childNodes.length-1)]||r),!o&&Ue(r.nextSibling)&&(r=r.nextSibling);const a=(t,o)=>{var r;const i=new ye(t,(t=>{for(;!e.dom.isBlock(t)&&t.parentNode&&n!==t;)t=t.parentNode;return t})(t)),a=o?"next":"prev";let s;for(;s=i[a]();)if(!We(e,s)&&!qt(s.textContent)&&0!==(null===(r=s.textContent)||void 0===r?void 0:r.length))return p.some(s);return p.none()};if(o&&Le(r))if(qt(r.textContent))r=a(r,!1).getOr(r);else for(null!==r.parentNode&&ao(e,r.parentNode)&&(r=r.parentNode);null!==r.previousSibling&&(ao(e,r.previousSibling)||Le(r.previousSibling));)r=r.previousSibling;if(!o&&Le(r))if(qt(r.textContent))r=a(r,!0).getOr(r);else for(null!==r.parentNode&&ao(e,r.parentNode)&&(r=r.parentNode);null!==r.nextSibling&&(ao(e,r.nextSibling)||Le(r.nextSibling));)r=r.nextSibling;for(;r.parentNode!==n;){const t=r.parentNode;if(Ve(e,r))return r;if(/^(TD|TH)$/.test(t.nodeName))return r;r=t}return r},lo=(e,t,o)=>{const n=e.selection.getRng();let r="LI";const i=mt(e,((e,t)=>{const o=e.selection.getStart(!0),n=so(e,t,!0,e.getBody());return Kt(R.fromDom(n),R.fromDom(t.commonAncestorContainer))?t.commonAncestorContainer:o})(e,n)),a=e.dom;if("false"===a.getContentEditable(e.selection.getNode()))return;"DL"===(t=t.toUpperCase())&&(r="DT");const s=to(n),l=C(((e,t,o)=>{const n=[],r=e.dom,i=so(e,t,!0,o),a=so(e,t,!1,o);let s;const l=[];for(let e=i;e&&(l.push(e),e!==a);e=e.nextSibling);return De.each(l,(t=>{var i;if(Ve(e,t))return n.push(t),void(s=null);if(r.isBlock(t)||Ue(t))return Ue(t)&&r.remove(t),void(s=null);const a=t.nextSibling;$t.isBookmarkNode(t)&&(Re(a)||Ve(e,a)||!a&&t.parentNode===o)?s=null:(s||(s=r.create("p"),null===(i=t.parentNode)||void 0===i||i.insertBefore(s,t),n.push(s)),s.appendChild(t))})),n})(e,n,i),e.dom.isEditable);De.each(l,(n=>{let i;const s=n.previousSibling,l=n.parentNode;Be(l)||(s&&Re(s)&&s.nodeName===t&&((e,t,o)=>{const n=e.getStyle(t,"list-style-type");let r=o?o["list-style-type"]:"";return r=null===r?"":r,n===r})(a,s,o)?(i=s,n=a.rename(n,r),s.appendChild(n)):(i=a.create(t),l.insertBefore(i,n),i.appendChild(n),n=a.rename(n,r)),((e,t,o)=>{De.each(o,(o=>e.setStyle(t,o,"")))})(a,n,["margin","margin-right","margin-bottom","margin-left","margin-top","padding","padding-right","padding-bottom","padding-left","padding-top"]),io(a,i,o),uo(e.dom,i))})),e.selection.setRng(oo(s))},co=(e,t,o)=>{return((e,t)=>Re(e)&&e.nodeName===(null==t?void 0:t.nodeName))(t,o)&&((e,t,o)=>e.getStyle(t,"list-style-type",!0)===e.getStyle(o,"list-style-type",!0))(e,t,o)&&(n=o,t.className===n.className);var n},uo=(e,t)=>{let o,n=t.nextSibling;if(co(e,t,n)){const r=n;for(;o=r.firstChild;)t.appendChild(o);e.remove(r)}if(n=t.previousSibling,co(e,t,n)){const r=n;for(;o=r.lastChild;)t.insertBefore(o,t.firstChild);e.remove(r)}},ho=(e,t,o,n)=>{if(t.nodeName!==o){const r=e.dom.rename(t,o);io(e.dom,r,n),Ct(e,no(o),r)}else io(e.dom,t,n),Ct(e,no(o),t)},mo=(e,t,o,n)=>{if(t.classList.forEach(((e,o,n)=>{e.startsWith("tox-")&&(n.remove(e),0===n.length&&t.removeAttribute("class"))})),t.nodeName!==o){const r=e.dom.rename(t,o);io(e.dom,r,n),Ct(e,no(o),r)}else io(e.dom,t,n),Ct(e,no(o),t)},go=e=>"list-style-type"in e,po=(e,t,o)=>{const n=ct(e);if(yt(e,n))return;const i=dt(e),a=r(o)?o:{};i.length>0?((e,t,o,n,r)=>{const i=Re(t);if(!i||t.nodeName!==n||go(r)||vt(t)){lo(e,n,r);const a=to(e.selection.getRng()),s=i?[t,...o]:o,l=i&&vt(t)?mo:ho;De.each(s,(t=>{l(e,t,n,r)})),e.selection.setRng(oo(a))}else Qt(e)})(e,n,i,t,a):((e,t,o,n)=>{if(t!==e.getBody())if(t)if(t.nodeName!==o||go(n)||vt(t)){const r=to(e.selection.getRng());vt(t)&&t.classList.forEach(((e,o,n)=>{e.startsWith("tox-")&&(n.remove(e),0===n.length&&t.removeAttribute("class"))})),io(e.dom,t,n);const i=e.dom.rename(t,o);uo(e.dom,i),e.selection.setRng(oo(r)),lo(e,o,n),Ct(e,no(o),i)}else Qt(e);else lo(e,o,n),Ct(e,no(o),t)})(e,n,t,a)},fo=Ee.DOM,vo=(e,t)=>{const o=De.grep(e.select("ol,ul",t));De.each(o,(t=>{((e,t)=>{const o=t.parentElement;if(o&&"LI"===o.nodeName&&o.firstChild===t){const n=o.previousSibling;n&&"LI"===n.nodeName?(n.appendChild(t),Ye(e,o)&&fo.remove(o)):fo.setStyle(o,"listStyleType","none")}if(Re(o)){const e=o.previousSibling;e&&"LI"===e.nodeName&&e.appendChild(t)}})(e,t)}))},bo=(e,t,o,n)=>{let r=t.startContainer;const i=t.startOffset;if(Le(r)&&(o?i0))return r;const a=e.schema.getNonEmptyElements();Pe(r)&&(r=xe.getNode(r,i));const s=new ye(r,n);o&&((e,t)=>!!Ue(t)&&e.isBlock(t.nextSibling)&&!Ue(t.previousSibling))(e.dom,r)&&s.next();const l=o?s.next.bind(s):s.prev2.bind(s);for(;r=l();){if("LI"===r.nodeName&&!r.hasChildNodes())return r;if(a[r.nodeName])return r;if(Le(r)&&r.data.length>0)return r}return null},xo=(e,t)=>{const o=t.childNodes;return 1===o.length&&!Re(o[0])&&e.isBlock(o[0])},yo=e=>p.from(e).map(R.fromDom).filter(X).exists((e=>((e,t=!1)=>ae(e)?e.dom.isContentEditable:ue(e).fold(u(t),(e=>"true"===he(e))))(e)&&!x(["details"],W(e)))),wo=(e,t,o)=>{let n;const r=xo(e,o)?o.firstChild:o;if(((e,t)=>{xo(e,t)&&yo(t.firstChild)&&e.remove(t.firstChild,!0)})(e,t),!Ye(e,t,!0))for(;n=t.firstChild;)r.appendChild(n)},_o=(e,t,o)=>{let n;const r=t.parentNode;if(!Ge(e,t)||!Ge(e,o))return;Re(o.lastChild)&&(n=o.lastChild),r===o.lastChild&&Ue(r.previousSibling)&&e.remove(r.previousSibling);const i=o.lastChild;i&&Ue(i)&&t.hasChildNodes()&&e.remove(i),Ye(e,o,!0)&&ve(R.fromDom(o)),wo(e,t,o),n&&o.appendChild(n);const a=((e,t)=>{const o=e.dom,n=t.dom;return o!==n&&o.contains(n)})(R.fromDom(o),R.fromDom(t))?e.getParents(t,Re,o):[];e.remove(t),_(a,(t=>{Ye(e,t)&&t!==e.getRoot()&&e.remove(t)}))},Co=(e,t,o,n)=>{const r=e.dom;if(r.isEmpty(n))((e,t,o)=>{ve(R.fromDom(o)),_o(e.dom,t,o),e.selection.setCursorLocation(o,0)})(e,o,n);else{const i=to(t);_o(r,o,n),e.selection.setRng(oo(i))}},So=(e,t)=>{const o=e.dom,n=e.selection,r=n.getStart(),i=ht(e,r),a=o.getParent(n.getStart(),"LI",i);if(a){const r=a.parentElement;if(r===e.getBody()&&Ye(o,r))return!0;const s=at(n.getRng()),l=o.getParent(bo(e,s,t,i),"LI",i),c=l&&(t?o.isChildOf(a,l):o.isChildOf(l,a));if(l&&l!==a&&!c)return e.undoManager.transact((()=>{var o,n;t?Co(e,s,l,a):(null===(n=(o=a).parentNode)||void 0===n?void 0:n.firstChild)===o?Jt(e):((e,t,o,n)=>{const r=to(t);_o(e.dom,o,n);const i=oo(r);e.selection.setRng(i)})(e,s,a,l)})),!0;if(c&&!t&&l!==a){const t=s.commonAncestorContainer.parentElement;return!(!t||o.isChildOf(l,t))&&(e.undoManager.transact((()=>{const n=to(s);wo(o,t,l),t.remove();const r=oo(n);e.selection.setRng(r)})),!0)}if(!l&&!t&&0===s.startOffset&&0===s.endOffset)return e.undoManager.transact((()=>{Qt(e)})),!0}return!1},ko=(e,t)=>{const o=e.dom,n=e.selection.getStart(),r=ht(e,n),i=o.getParent(n,o.isBlock,r);if(i&&o.isEmpty(i,void 0,{checkRootAsContent:!0})){const n=at(e.selection.getRng()),a=bo(e,n,t,r),s=o.getParent(a,"LI",r);if(a&&s){const l=e=>x(["td","th","caption"],W(e)),c=e=>e.dom===r;return!!((e,t,o=h)=>L(e,t,o).getOr(e.isNone()&&t.isNone()))(ce(R.fromDom(s),l,c),ce(R.fromDom(n.startContainer),l,c),z)&&(e.undoManager.transact((()=>{const n=s.parentNode;((e,t,o)=>{const n=e.getParent(t.parentNode,e.isBlock,o);e.remove(t),n&&e.isEmpty(n)&&e.remove(n)})(o,i,r),uo(o,n),e.selection.select(a,!0),e.selection.collapse(t)})),!0)}}return!1},Ao=e=>{const t=e.selection.getStart(),o=ht(e,t);return e.dom.getParent(t,"LI,DT,DD",o)||ut(e).length>0},Mo=(e,t)=>{const o=e.selection;return!yt(e,o.getNode())&&(o.isCollapsed()?((e,t)=>So(e,t)||ko(e,t))(e,t):(e=>!!Ao(e)&&(e.undoManager.transact((()=>{let t=!0;const o=()=>t=!1;e.on("input",o),e.execCommand("Delete"),e.off("input",o),t&&e.dispatch("input"),vo(e.dom,e.getBody())})),!0))(e))},To=e=>{const t=T(St(e).split("")),o=w(t,((e,t)=>{const o=e.toUpperCase().charCodeAt(0)-"A".charCodeAt(0)+1;return Math.pow(26,t)*o}));return S(o,((e,t)=>e+t),0)},Io=e=>{if(--e<0)return"";{const t=e%26,o=Math.floor(e/26);return Io(o)+String.fromCharCode("A".charCodeAt(0)+t)}},Eo=e=>{const t=parseInt(e.start,10);return N(e.listStyleType,"upper-alpha")?Io(t):N(e.listStyleType,"lower-alpha")?Io(t).toLowerCase():e.start},Do=e=>{const t=ct(e);ze(t)&&!yt(e,t)&&e.windowManager.open({title:"List Properties",body:{type:"panel",items:[{type:"input",name:"start",label:"Start list at number",inputMode:"numeric"}]},initialData:{start:Eo({start:e.dom.getAttrib(t,"start","1"),listStyleType:p.from(e.dom.getStyle(t,"list-style-type"))})},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],onSubmit:t=>{(e=>{switch((e=>/^[0-9]+$/.test(e)?2:/^[A-Z]+$/.test(e)?0:(e=>/^[a-z]+$/.test(e))(e)?1:e.length>0?4:3)(e)){case 2:return p.some({listStyleType:p.none(),start:e});case 0:return p.some({listStyleType:p.some("upper-alpha"),start:To(e).toString()});case 1:return p.some({listStyleType:p.some("lower-alpha"),start:To(e).toString()});case 3:return p.some({listStyleType:p.none(),start:""});case 4:return p.none()}})(t.getData().start).each((t=>{e.execCommand("mceListUpdate",!1,{attrs:{start:"1"===t.start?"":t.start},styles:{"list-style-type":t.listStyleType.getOr("")}})})),t.close()}})},Oo=(e,t)=>()=>{const o=ct(e);return s(o)&&o.nodeName===t},No=e=>{e.addCommand("mceListProps",(()=>{Do(e)}))},Lo=e=>{e.on("BeforeExecCommand",(t=>{const o=t.command.toLowerCase();"indent"===o?Xt(e):"outdent"===o&&Jt(e)})),e.addCommand("InsertUnorderedList",((t,o)=>{po(e,"UL",o)})),e.addCommand("InsertOrderedList",((t,o)=>{po(e,"OL",o)})),e.addCommand("InsertDefinitionList",((t,o)=>{po(e,"DL",o)})),e.addCommand("RemoveList",(()=>{Qt(e)})),No(e),e.addCommand("mceListUpdate",((t,o)=>{r(o)&&((e,t)=>{const o=ct(e);null===o||yt(e,o)||e.undoManager.transact((()=>{r(t.styles)&&e.dom.setStyles(o,t.styles),r(t.attrs)&&Se(t.attrs,((t,n)=>e.dom.setAttrib(o,n,t)))}))})(e,o)})),e.addQueryStateHandler("InsertUnorderedList",Oo(e,"UL")),e.addQueryStateHandler("InsertOrderedList",Oo(e,"OL")),e.addQueryStateHandler("InsertDefinitionList",Oo(e,"DL"))};var Po=tinymce.util.Tools.resolve("tinymce.html.Node");const Ro=e=>3===e.type,jo=e=>0===e.length,zo=e=>{const t=(t,o)=>{const n=Po.create("li");_(t,(e=>n.append(e))),o?e.insert(n,o,!0):e.append(n)},o=S(e.children(),((e,o)=>Ro(o)?[...e,o]:jo(e)||Ro(o)?e:(t(e,o),[])),[]);jo(o)||t(o)},Bo=e=>{Je(e)&&(e=>{e.on("keydown",(t=>{t.keyCode!==we.TAB||we.metaKeyPressed(t)||e.undoManager.transact((()=>{(t.shiftKey?Jt(e):Xt(e))&&t.preventDefault()}))}))})(e),(e=>{e.on("ExecCommand",(t=>{const o=t.command.toLowerCase();"delete"!==o&&"forwarddelete"!==o||!Ao(e)||vo(e.dom,e.getBody())})),e.on("keydown",(t=>{t.keyCode===we.BACKSPACE?Mo(e,!1)&&t.preventDefault():t.keyCode===we.DELETE&&Mo(e,!0)&&t.preventDefault()}))})(e)},Fo=(e,t)=>o=>(o.setEnabled(e.selection.isEditable()),wt(e,(n=>{o.setActive(bt(n.parents,t)),o.setEnabled(!yt(e,n.element)&&e.selection.isEditable())}))),Ho=(e,t)=>o=>wt(e,(n=>o.setEnabled(bt(n.parents,t)&&!yt(e,n.element))));e.add("lists",(e=>((e=>{(0,e.options.register)("lists_indent_on_tab",{processor:"boolean",default:!0})})(e),(e=>{e.on("PreInit",(()=>{const{parser:t}=e;t.addNodeFilter("ul,ol",(e=>_(e,zo)))}))})(e),e.hasPlugin("rtc",!0)?No(e):(Bo(e),Lo(e)),(e=>{const t=t=>()=>e.execCommand(t);e.hasPlugin("advlist")||(e.ui.registry.addToggleButton("numlist",{icon:"ordered-list",active:!1,tooltip:"Numbered list",onAction:t("InsertOrderedList"),onSetup:Fo(e,"OL")}),e.ui.registry.addToggleButton("bullist",{icon:"unordered-list",active:!1,tooltip:"Bullet list",onAction:t("InsertUnorderedList"),onSetup:Fo(e,"UL")}))})(e),(e=>{const t={text:"List properties...",icon:"ordered-list",onAction:()=>e.execCommand("mceListProps"),onSetup:Ho(e,"OL")};e.ui.registry.addMenuItem("listprops",t),e.ui.registry.addContextMenu("lists",{update:t=>{const o=ct(e,t);return ze(o)?["listprops"]:[]}})})(e),(e=>({backspaceDelete:t=>{Mo(e,t)}}))(e))))}()},7426(e,t,o){o(4855)},4855(){!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=r=e,n=(i=String).prototype,n.isPrototypeOf(o)||(null===(a=r.constructor)||void 0===a?void 0:a.name)===i.name)?"string":t;var o,n;var r,i,a})(t)===e,o=t("string"),n=t("object"),r=t("array"),i=e=>!(e=>null==e)(e);class a{constructor(e,t){this.tag=e,this.value=t}static some(e){return new a(!0,e)}static none(){return a.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?a.some(e(this.value)):a.none()}bind(e){return this.tag?e(this.value):a.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:a.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return i(e)?a.some(e):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const s=Array.prototype.push,l=(e,t)=>{for(let o=0,n=e.length;o{const t=[];for(let o=0,n=e.length;om(e,t)?a.from(e[t]):a.none(),m=(e,t)=>u.call(e,t),g=e=>t=>t.options.get(e),p=g("audio_template_callback"),f=g("video_template_callback"),v=g("iframe_template_callback"),b=g("media_live_embeds"),x=g("media_filter_html"),y=g("media_url_resolver"),w=g("media_alt_source"),_=g("media_poster"),C=g("media_dimensions");var S=tinymce.util.Tools.resolve("tinymce.util.Tools"),k=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),A=tinymce.util.Tools.resolve("tinymce.html.DomParser");const M=k.DOM,T=e=>e.replace(/px$/,""),I=e=>{const t=e.attr("style"),o=t?M.parseStyle(t):{};return{type:"ephox-embed-iri",source:e.attr("data-ephox-embed-iri"),altsource:"",poster:"",width:h(o,"max-width").map(T).getOr(""),height:h(o,"max-height").map(T).getOr("")}},E=(e,t)=>{let o={};for(let n=A({validate:!1,forced_root_block:!1},t).parse(e);n;n=n.walk())if(1===n.type){const e=n.name;if(n.attr("data-ephox-embed-iri")){o=I(n);break}o.source||"param"!==e||(o.source=n.attr("movie")),"iframe"!==e&&"object"!==e&&"embed"!==e&&"video"!==e&&"audio"!==e||(o.type||(o.type=e),o=S.extend(n.attributes.map,o)),"source"===e&&(o.source?o.altsource||(o.altsource=n.attr("src")):o.source=n.attr("src")),"img"!==e||o.poster||(o.poster=n.attr("src"))}return o.source=o.source||o.src||"",o.altsource=o.altsource||"",o.poster=o.poster||"",o},D=e=>{var t;const o=null!==(t=e.toLowerCase().split(".").pop())&&void 0!==t?t:"";return h({mp3:"audio/mpeg",m4a:"audio/x-m4a",wav:"audio/wav",mp4:"video/mp4",webm:"video/webm",ogg:"video/ogg",swf:"application/x-shockwave-flash"},o).getOr("")};var O=tinymce.util.Tools.resolve("tinymce.html.Node"),N=tinymce.util.Tools.resolve("tinymce.html.Serializer");const L=(e,t={})=>A({forced_root_block:!1,validate:!1,allow_conditional_comments:!0,...t},e),P=k.DOM,R=e=>/^[0-9.]+$/.test(e)?e+"px":e,j=(e,t)=>{const o=t.attr("style"),n=o?P.parseStyle(o):{};i(e.width)&&(n["max-width"]=R(e.width)),i(e.height)&&(n["max-height"]=R(e.height)),t.attr("style",P.serializeStyle(n))},z=["source","altsource"],B=(e,t,o,n)=>{let r=0,i=0;const a=L(n);a.addNodeFilter("source",(e=>r=e.length));const s=a.parse(e);for(let e=s;e;e=e.walk())if(1===e.type){const n=e.name;if(e.attr("data-ephox-embed-iri")){j(t,e);break}switch(n){case"video":case"object":case"embed":case"img":case"iframe":void 0!==t.height&&void 0!==t.width&&(e.attr("width",t.width),e.attr("height",t.height))}if(o)switch(n){case"video":e.attr("poster",t.poster),e.attr("src",null);for(let o=r;o<2;o++)if(t[z[o]]){const n=new O("source",1);n.attr("src",t[z[o]]),n.attr("type",t[z[o]+"mime"]||null),e.append(n)}break;case"iframe":e.attr("src",t.source);break;case"object":const o=e.getAll("img").length>0;if(t.poster&&!o){e.attr("src",t.poster);const o=new O("img",1);o.attr("src",t.poster),o.attr("width",t.width),o.attr("height",t.height),e.append(o)}break;case"source":if(i<2&&(e.attr("src",t[z[i]]),e.attr("type",t[z[i]+"mime"]||null),!t[z[i]])){e.remove();continue}i++;break;case"img":t.poster||e.remove()}}return N({},n).serialize(s)},F=[{regex:/youtu\.be\/([\w\-_\?&=.]+)/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$1",allowFullscreen:!0},{regex:/youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$2?$4",allowFullscreen:!0},{regex:/youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$1",allowFullscreen:!0},{regex:/vimeo\.com\/([0-9]+)\?h=(\w+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$1?h=$2&title=0&byline=0&portrait=0&color=8dc7dc",allowFullscreen:!0},{regex:/vimeo\.com\/(.*)\/([0-9]+)\?h=(\w+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$2?h=$3&title=0&byline=0",allowFullscreen:!0},{regex:/vimeo\.com\/([0-9]+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc",allowFullscreen:!0},{regex:/vimeo\.com\/(.*)\/([0-9]+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$2?title=0&byline=0",allowFullscreen:!0},{regex:/maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,type:"iframe",w:425,h:350,url:'maps.google.com/maps/ms?msid=$2&output=embed"',allowFullscreen:!1},{regex:/dailymotion\.com\/video\/([^_]+)/,type:"iframe",w:480,h:270,url:"www.dailymotion.com/embed/video/$1",allowFullscreen:!0},{regex:/dai\.ly\/([^_]+)/,type:"iframe",w:480,h:270,url:"www.dailymotion.com/embed/video/$1",allowFullscreen:!0}],H=(e,t)=>{const o=(e=>{const t=e.match(/^(https?:\/\/|www\.)(.+)$/i);return t&&t.length>1?"www."===t[1]?"https://":t[1]:"https://"})(t),n=e.regex.exec(t);let r=o+e.url;if(i(n))for(let e=0;en[e]?n[e]:""));return r.replace(/\?$/,"")},U=e=>{const t=F.filter((t=>t.regex.test(e)));return t.length>0?S.extend({},t[0],{url:H(t[0],e)}):null},V=(e,t)=>{var o;const n=S.extend({},t);if(!n.source&&(S.extend(n,E(null!==(o=n.embed)&&void 0!==o?o:"",e.schema)),!n.source))return"";n.altsource||(n.altsource=""),n.poster||(n.poster=""),n.source=e.convertURL(n.source,"source"),n.altsource=e.convertURL(n.altsource,"source"),n.sourcemime=D(n.source),n.altsourcemime=D(n.altsource),n.poster=e.convertURL(n.poster,"poster");const r=U(n.source);if(r&&(n.source=r.url,n.type=r.type,n.allowfullscreen=r.allowFullscreen,n.width=n.width||String(r.w),n.height=n.height||String(r.h)),n.embed)return B(n.embed,n,!0,e.schema);{const t=p(e),o=f(e),r=v(e);return n.width=n.width||"300",n.height=n.height||"150",S.each(n,((t,o)=>{n[o]=e.dom.encode(""+t)})),"iframe"===n.type?((e,t)=>{if(t)return t(e);{const t=e.allowfullscreen?' allowFullscreen="1"':"";return'"}})(n,r):"application/x-shockwave-flash"===n.sourcemime?(e=>{let t='';return e.poster&&(t+=''),t+="",t})(n):-1!==n.sourcemime.indexOf("audio")?((e,t)=>t?t(e):'")(n,t):((e,t)=>t?t(e):'")(n,o)}},Z=e=>e.hasAttribute("data-mce-object")||e.hasAttribute("data-ephox-embed-iri"),W={},Y=e=>t=>V(e,t),G=(e,t)=>{const o=y(e);return o?((e,t,o)=>new Promise(((n,r)=>{const i=o=>(o.html&&(W[e.source]=o),n({url:e.source,html:o.html?o.html:t(e)}));W[e.source]?i(W[e.source]):o({url:e.source}).then(i).catch(r)})))(t,Y(e),o):((e,t)=>Promise.resolve({html:t(e),url:e.source}))(t,Y(e))},X=(e,t)=>{const o={};return h(e,"dimensions").each((e=>{l(["width","height"],(n=>{h(t,n).orThunk((()=>h(e,n))).each((e=>o[n]=e))}))})),o},J=(e,t)=>{const o=t&&"dimensions"!==t?((e,t)=>h(t,e).bind((e=>h(e,"meta"))))(t,e).getOr({}):{},r=((e,t,o)=>r=>{const i=()=>h(e,r),s=()=>h(t,r),l=e=>h(e,"value").bind((e=>e.length>0?a.some(e):a.none()));return{[r]:(r===o?i().bind((e=>n(e)?l(e).orThunk(s):s().orThunk((()=>a.from(e))))):s().orThunk((()=>i().bind((e=>n(e)?l(e):a.from(e)))))).getOr("")}})(e,o,t);return{...r("source"),...r("altsource"),...r("poster"),...r("embed"),...X(e,o)}},Q=e=>{const t={...e,source:{value:h(e,"source").getOr("")},altsource:{value:h(e,"altsource").getOr("")},poster:{value:h(e,"poster").getOr("")}};return l(["width","height"],(o=>{h(e,o).each((e=>{const n=t.dimensions||{};n[o]=e,t.dimensions=n}))})),t},q=e=>t=>{const o=t&&t.msg?"Media embed handler error: "+t.msg:"Media embed handler threw unknown error.";e.notificationManager.open({type:"error",text:o})},K=(e,t)=>n=>{if(o(n.url)&&n.url.trim().length>0){const o=n.html,r={...E(o,t.schema),source:n.url,embed:o};e.setData(Q(r))}},$=(e,t)=>{const o=e.dom.select("*[data-mce-object]");e.insertContent(t),((e,t)=>{const o=e.dom.select("*[data-mce-object]");for(let e=0;e=0;n--)t[e]===o[n]&&o.splice(n,1);e.selection.select(o[0])})(e,o),e.nodeChanged()},ee=(e,t)=>i(t)&&"ephox-embed-iri"===t&&i(U(e)),te=(e,t)=>((e,t)=>e.width!==t.width||e.height!==t.height)(e,t)&&ee(t.source,e.type),oe=(e,t,o)=>{var n,r;t.embed=te(e,t)&&C(o)?V(o,{...t,embed:""}):B(null!==(n=t.embed)&&void 0!==n?n:"",t,!1,o.schema),t.embed&&(e.source===t.source||(r=t.source,m(W,r)))?$(o,t.embed):G(o,t).then((e=>{$(o,e.html)})).catch(q(o))},ne=e=>{const t=(e=>{const t=e.selection.getNode(),o=Z(t)?e.serializer.serialize(t,{selection:!0}):"",n=E(o,e.schema),r=(()=>{if(ee(n.source,n.type)){const o=e.dom.getRect(t);return{width:o.w.toString().replace(/px$/,""),height:o.h.toString().replace(/px$/,"")}}return{}})();return{embed:o,...n,...r}})(e),o=(e=>{let t=e;return{get:()=>t,set:e=>{t=e}}})(t),n=Q(t),r=C(e)?[{type:"sizeinput",name:"dimensions",label:"Constrain proportions",constrain:!0}]:[],i={title:"General",name:"general",items:c([[{name:"source",type:"urlinput",filetype:"media",label:"Source",picker_text:"Browse files"}],r])},a={title:"Embed",items:[{type:"textarea",name:"embed",label:"Paste your embed code below:"}]},s=[];w(e)&&s.push({name:"altsource",type:"urlinput",filetype:"media",label:"Alternative source URL"}),_(e)&&s.push({name:"poster",type:"urlinput",filetype:"image",label:"Media poster (Image URL)"});const l={title:"Advanced",name:"advanced",items:s},d=[i,a];s.length>0&&d.push(l);const u={type:"tabpanel",tabs:d},h=e.windowManager.open({title:"Insert/Edit Media",size:"normal",body:u,buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],onSubmit:t=>{const n=J(t.getData());oe(o.get(),n,e),t.close()},onChange:(t,n)=>{switch(n.name){case"source":((t,o)=>{const n=J(o.getData(),"source");t.source!==n.source&&(K(h,e)({url:n.source,html:""}),G(e,n).then(K(h,e)).catch(q(e)))})(o.get(),t);break;case"embed":(t=>{var o;const n=J(t.getData()),r=E(null!==(o=n.embed)&&void 0!==o?o:"",e.schema);t.setData(Q(r))})(t);break;case"dimensions":case"altsource":case"poster":((t,o,n)=>{const r=J(t.getData(),o),i=te(n,r)&&C(e)?{...r,embed:""}:r,a=V(e,i);t.setData(Q({...i,embed:a}))})(t,n.name,o.get())}o.set(J(t.getData()))},initialData:n})};var re=tinymce.util.Tools.resolve("tinymce.Env");const ie=e=>{const t=e.name;return"iframe"===t||"video"===t||"audio"===t},ae=(e,t,o,n=null)=>{const r=e.attr(o);return i(r)?r:m(t,o)?null:n},se=(e,t,o)=>{const n="img"===t.name||"video"===e.name,r=n?"300":null,i="audio"===e.name?"30":"150",a=n?i:null;t.attr({width:ae(e,o,"width",r),height:ae(e,o,"height",a)})},le=(e,t)=>{const o=t.name,n=new O("img",1);return de(e,t,n),se(t,n,{}),n.attr({style:t.attr("style"),src:re.transparentSrc,"data-mce-object":o,class:"mce-object mce-object-"+o}),n},ce=(e,t)=>{var o;const n=t.name,r=new O("span",1);r.attr({contentEditable:"false",style:t.attr("style"),"data-mce-object":n,class:"mce-preview-object mce-object-"+n}),de(e,t,r);const a=e.dom.parseStyle(null!==(o=t.attr("style"))&&void 0!==o?o:""),s=new O(n,1);if(se(t,s,a),s.attr({src:t.attr("src"),style:t.attr("style"),class:t.attr("class")}),"iframe"===n)s.attr({allowfullscreen:t.attr("allowfullscreen"),frameborder:"0",sandbox:t.attr("sandbox"),referrerpolicy:t.attr("referrerpolicy")});else{l(["controls","crossorigin","currentTime","loop","muted","poster","preload"],(e=>{s.attr(e,t.attr(e))}));const o=r.attr("data-mce-html");i(o)&&((e,t,o,n)=>{const r=L(e.schema).parse(n,{context:t});for(;r.firstChild;)o.append(r.firstChild)})(e,n,s,unescape(o))}const c=new O("span",1);return c.attr("class","mce-shim"),r.append(s),r.append(c),r},de=(e,t,o)=>{var n;const r=null!==(n=t.attributes)&&void 0!==n?n:[];let i=r.length;for(;i--;){const t=r[i].name;let n=r[i].value;"width"===t||"height"===t||"style"===t||((e,t,o)=>""===t||e.length>=t.length&&e.substr(o,o+t.length)===t)(t,"data-mce-",0)||("data"!==t&&"src"!==t||(n=e.convertURL(n,t)),o.attr("data-mce-p-"+t,n))}const a=N({inner:!0},e.schema),s=new O("div",1);l(t.children(),(e=>s.append(e)));const c=a.serialize(s);c&&(o.attr("data-mce-html",escape(c)),o.empty())},ue=e=>{const t=e.attr("class");return o(t)&&/\btiny-pageembed\b/.test(t)},he=e=>{let t=e;for(;t=t.parent;)if(t.attr("data-ephox-embed-iri")||ue(t))return!0;return!1},me=(e,t,o)=>{const n=(0,e.options.get)("xss_sanitization"),r=x(e);return L(e.schema,{sanitize:n,validate:r}).parse(o,{context:t})},ge=e=>{e.on("PreInit",(()=>{const{schema:t,serializer:o,parser:n}=e,r=t.getBoolAttrs();l("webkitallowfullscreen mozallowfullscreen".split(" "),(e=>{r[e]={}})),((e,t)=>{const o=d(e);for(let n=0,r=o.length;n{const n=t.getElementRule(o);n&&l(e,(e=>{n.attributes[e]={},n.attributesOrder.push(e)}))})),n.addNodeFilter("iframe,video,audio,object,embed",(e=>t=>{let o,n=t.length;for(;n--;)o=t[n],o.parent&&(o.parent.attr("data-mce-object")||(ie(o)&&b(e)?he(o)||o.replace(ce(e,o)):he(o)||o.replace(le(e,o))))})(e)),o.addAttributeFilter("data-mce-object",((t,o)=>{var n;let r=t.length;for(;r--;){const i=t[r];if(!i.parent)continue;const a=i.attr(o),s=new O(a,1);if("audio"!==a){const e=i.attr("class");e&&-1!==e.indexOf("mce-preview-object")&&i.firstChild?s.attr({width:i.firstChild.attr("width"),height:i.firstChild.attr("height")}):s.attr({width:i.attr("width"),height:i.attr("height")})}s.attr({style:i.attr("style")});const c=null!==(n=i.attributes)&&void 0!==n?n:[];let d=c.length;for(;d--;){const e=c[d].name;0===e.indexOf("data-mce-p-")&&s.attr(e.substr(11),c[d].value)}const u=i.attr("data-mce-html");if(u){const t=me(e,a,unescape(u));l(t.children(),(e=>s.append(e)))}i.replace(s)}}))})),e.on("SetContent",(()=>{const t=e.dom;l(t.select("span.mce-preview-object"),(e=>{0===t.select("span.mce-shim",e).length&&t.add(e,"span",{class:"mce-shim"})}))}))},pe=e=>t=>{const o=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",o),o(),()=>{e.off("NodeChange",o)}};e.add("media",(e=>((e=>{const t=e.options.register;t("audio_template_callback",{processor:"function"}),t("video_template_callback",{processor:"function"}),t("iframe_template_callback",{processor:"function"}),t("media_live_embeds",{processor:"boolean",default:!0}),t("media_filter_html",{processor:"boolean",default:!0}),t("media_url_resolver",{processor:"function"}),t("media_alt_source",{processor:"boolean",default:!0}),t("media_poster",{processor:"boolean",default:!0}),t("media_dimensions",{processor:"boolean",default:!0})})(e),(e=>{e.addCommand("mceMedia",(()=>{ne(e)}))})(e),(e=>{const t=()=>e.execCommand("mceMedia");e.ui.registry.addToggleButton("media",{tooltip:"Insert/edit media",icon:"embed",onAction:t,onSetup:t=>{const o=e.selection;t.setActive(Z(o.getNode()));const n=o.selectorChangedWithUnbind("img[data-mce-object],span[data-mce-object],div[data-ephox-embed-iri]",t.setActive).unbind,r=pe(e)(t);return()=>{n(),r()}}}),e.ui.registry.addMenuItem("media",{icon:"embed",text:"Media...",onAction:t,onSetup:pe(e)})})(e),(e=>{e.on("ResolveName",(e=>{let t;1===e.target.nodeType&&(t=e.target.getAttribute("data-mce-object"))&&(e.name=t)}))})(e),ge(e),(e=>{e.on("mousedown",(t=>{const o=e.dom.getParent(t.target,".mce-preview-object");o&&"2"===e.dom.getAttrib(o,"data-mce-selected")&&t.stopImmediatePropagation()})),e.on("click keyup touchend",(()=>{const t=e.selection.getNode();t&&e.dom.hasClass(t,"mce-preview-object")&&e.dom.getAttrib(t,"data-mce-selected")&&t.setAttribute("data-mce-selected","2")})),e.on("ObjectResized",(t=>{const o=t.target;if(o.getAttribute("data-mce-object")){let n=o.getAttribute("data-mce-html");n&&(n=unescape(n),o.setAttribute("data-mce-html",escape(B(n,{width:String(t.width),height:String(t.height)},!1,e.schema))))}}))})(e),(e=>({showDialog:()=>{ne(e)}}))(e))))}()},9638(e,t,o){o(2171)},2171(){!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=(o=void 0,e=>o===e);var o;class n{constructor(e,t){this.tag=e,this.value=t}static some(e){return new n(!0,e)}static none(){return n.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?n.some(e(this.value)):n.none()}bind(e){return this.tag?e(this.value):n.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:n.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return(e=>null==e)(e)?n.none():n.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}n.singletonNone=new n(!1);const r=e=>()=>e,i=r(!1),a=(e,t)=>((e,t,o)=>{for(let r=0,i=e.length;rl(0,0),l=(e,t)=>({major:e,minor:t}),c={nu:l,detect:(e,t)=>{const o=String(t).toLowerCase();return 0===e.length?s():((e,t)=>{const o=((e,t)=>{for(let o=0;oNumber(t.replace(o,"$"+e));return l(n(1),n(2))})(e,o)},unknown:s},d=(e,t)=>((e,t)=>{for(let o=0;o{const o=t.brand.toLowerCase();return a(e,(e=>{var t;return o===(null===(t=e.brand)||void 0===t?void 0:t.toLowerCase())})).map((e=>({current:e.name,version:c.nu(parseInt(t.version,10),0)})))})),u=(e,t)=>{const o=String(t).toLowerCase();return a(e,(e=>e.search(o)))},h=(e,o,n=0,r)=>{const i=e.indexOf(o,n);return-1!==i&&(!!t(r)||i+o.length<=r)},m=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,g=e=>t=>h(t,e),p=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:e=>h(e,"edge/")&&h(e,"chrome")&&h(e,"safari")&&h(e,"applewebkit")},{name:"Chromium",brand:"Chromium",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,m],search:e=>h(e,"chrome")&&!h(e,"chromeframe")},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:e=>h(e,"msie")||h(e,"trident")},{name:"Opera",versionRegexes:[m,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:g("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:g("firefox")},{name:"Safari",versionRegexes:[m,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:e=>(h(e,"safari")||h(e,"mobile/"))&&h(e,"applewebkit")}],f=[{name:"Windows",search:g("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:e=>h(e,"iphone")||h(e,"ipad"),versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:g("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"macOS",search:g("mac os x"),versionRegexes:[/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:g("linux"),versionRegexes:[]},{name:"Solaris",search:g("sunos"),versionRegexes:[]},{name:"FreeBSD",search:g("freebsd"),versionRegexes:[]},{name:"ChromeOS",search:g("cros"),versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/]}],v={browsers:r(p),oses:r(f)},b="Edge",x="Chromium",y="Opera",w="Firefox",_="Safari",C=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isEdge:n(b),isChromium:n(x),isIE:n("IE"),isOpera:n(y),isFirefox:n(w),isSafari:n(_)}},S={unknown:()=>C({current:void 0,version:c.unknown()}),nu:C,edge:r(b),chromium:r(x),ie:r("IE"),opera:r(y),firefox:r(w),safari:r(_)},k="Windows",A="Android",M="Linux",T="macOS",I="Solaris",E="FreeBSD",D="ChromeOS",O=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isWindows:n(k),isiOS:n("iOS"),isAndroid:n(A),isMacOS:n(T),isLinux:n(M),isSolaris:n(I),isFreeBSD:n(E),isChromeOS:n(D)}},N={unknown:()=>O({current:void 0,version:c.unknown()}),nu:O,windows:r(k),ios:r("iOS"),android:r(A),linux:r(M),macos:r(T),solaris:r(I),freebsd:r(E),chromeos:r(D)},L=(e,t,o)=>{const n=v.browsers(),i=v.oses(),a=t.bind((e=>d(n,e))).orThunk((()=>((e,t)=>u(e,t).map((e=>{const o=c.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(n,e))).fold(S.unknown,S.nu),s=((e,t)=>u(e,t).map((e=>{const o=c.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(i,e).fold(N.unknown,N.nu),l=((e,t,o,n)=>{const i=e.isiOS()&&!0===/ipad/i.test(o),a=e.isiOS()&&!i,s=e.isiOS()||e.isAndroid(),l=s||n("(pointer:coarse)"),c=i||!a&&s&&n("(min-device-width:768px)"),d=a||s&&!c,u=t.isSafari()&&e.isiOS()&&!1===/safari/i.test(o),h=!d&&!c&&!u;return{isiPad:r(i),isiPhone:r(a),isTablet:r(c),isPhone:r(d),isTouch:r(l),isAndroid:e.isAndroid,isiOS:e.isiOS,isWebView:r(u),isDesktop:r(h)}})(s,a,e,o);return{browser:a,os:s,deviceType:l}},P=e=>window.matchMedia(e).matches;let R=(e=>{let t,o=!1;return(...n)=>(o||(o=!0,t=e.apply(null,n)),t)})((()=>L(window.navigator.userAgent,n.from(window.navigator.userAgentData),P)));const j=()=>R(),z=()=>{const e=j().os.isMacOS()||j().os.isiOS();return` @@ -146,7 +270,8 @@ function select_page(source_id, page_name) { {{-- ページの指定場所移動用フォーム(POSTのためのフォーム。一つ用意して一覧からJavascriptで呼び出し) --}}
{{ csrf_field() }} - + +
{{-- 表示切り替え用フォーム(POSTのためのフォーム。一つ用意して一覧からJavascriptで呼び出し) --}} @@ -154,44 +279,72 @@ function select_page(source_id, page_name) { {{ csrf_field() }} + @php + $page_children = $pages->groupBy('parent_id'); + @endphp + {{-- 階層変更用モーダル表示 --}}