From f1ea6e7d7e2682740dd92ef46b29525d65fd807c Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Mon, 23 Mar 2026 09:22:24 +1030 Subject: [PATCH 01/29] Replace ts-node with tsx for running the demo due to an compatibility issue with node module system --- package.json | 10 +- yarn.lock | 418 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 272 insertions(+), 156 deletions(-) diff --git a/package.json b/package.json index d8091a9..92c5aba 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "test": "bedrock-auto -b chrome-headless -d src/test/ts", "build": "tsc -p ./tsconfig.json && rollup -c rollup.config.js", "lint": "yarn eslint src/**/*.ts", - "serve": "yarn ts-node -r esm src/demo/ts/Server.ts" + "serve": "yarn tsx src/demo/ts/Server.ts" }, "keywords": [ "TinyMCE", @@ -33,8 +33,6 @@ "@ephox/swag": "^4.6.0", "@tinymce/beehive-flow": "^0.19.0", "@tinymce/eslint-plugin": "^3.0.0", - "@types/esm": "^3.2.0", - "@types/express": "^5.0.0", "@types/node": "^24.5.2", "@typescript-eslint/eslint-plugin": "^8.44.0", "@typescript-eslint/parser": "^8.44.0", @@ -42,12 +40,10 @@ "eslint-config-eslint": "^13.0.0", "eslint-plugin-import": "^2.27.5", "eslint-plugin-prefer-arrow": "^1.2.3", - "esm": "^3.2.25", - "express": "^5.1.0", + "express": "^5.2.1", "rollup": "^4.24.0", "tinymce": "^8.0.0", - "ts-loader": "^9.4.2", - "ts-node": "^10.9.1", + "tsx": "^4.21.0", "typescript": "~5.9.2", "webpack": "^5.75.0" }, diff --git a/yarn.lock b/yarn.lock index adb9fc7..1e316e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -582,13 +582,6 @@ "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.27.1" -"@cspotcode/source-map-support@^0.8.0": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== - dependencies: - "@jridgewell/trace-mapping" "0.3.9" - "@deno/shim-deno-test@^0.4.0": version "0.4.0" resolved "https://registry.yarnpkg.com/@deno/shim-deno-test/-/shim-deno-test-0.4.0.tgz#2ff56821854c51323c0cd08a4a56d668f84367ba" @@ -791,6 +784,136 @@ esquery "^1.6.0" jsdoc-type-pratt-parser "~4.0.0" +"@esbuild/aix-ppc64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz#4c585002f7ad694d38fe0e8cbf5cfd939ccff327" + integrity sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q== + +"@esbuild/android-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz#7625d0952c3b402d3ede203a16c9f2b78f8a4827" + integrity sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw== + +"@esbuild/android-arm@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.27.4.tgz#9a0cf1d12997ec46dddfb32ce67e9bca842381ac" + integrity sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ== + +"@esbuild/android-x64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.27.4.tgz#06e1fdc6283fccd6bc6aadd6754afce6cf96f42e" + integrity sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw== + +"@esbuild/darwin-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz#6c550ee6c0273bcb0fac244478ff727c26755d80" + integrity sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ== + +"@esbuild/darwin-x64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz#ed7a125e9f25ce0091b9aff783ee943f6ba6cb86" + integrity sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw== + +"@esbuild/freebsd-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz#597dc8e7161dba71db4c1656131c1f1e9d7660c6" + integrity sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw== + +"@esbuild/freebsd-x64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz#ea171f9f4f00efaa8e9d3fe8baa1b75d757d1b36" + integrity sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ== + +"@esbuild/linux-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz#e52d57f202369386e6dbcb3370a17a0491ab1464" + integrity sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA== + +"@esbuild/linux-arm@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz#5e0c0b634908adbce0a02cebeba8b3acac263fb6" + integrity sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg== + +"@esbuild/linux-ia32@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz#5f90f01f131652473ec06b038a14c49683e14ec7" + integrity sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA== + +"@esbuild/linux-loong64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz#63bacffdb99574c9318f9afbd0dd4fff76a837e3" + integrity sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA== + +"@esbuild/linux-mips64el@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz#c4b6952eca6a8efff67fee3671a3536c8e67b7eb" + integrity sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw== + +"@esbuild/linux-ppc64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz#6dea67d3d98c6986f1b7769e4f1848e5ae47ad58" + integrity sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA== + +"@esbuild/linux-riscv64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz#9ad2b4c3c0502c6bada9c81997bb56c597853489" + integrity sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw== + +"@esbuild/linux-s390x@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz#c43d3cfd073042ca6f5c52bb9bc313ed2066ce28" + integrity sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA== + +"@esbuild/linux-x64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz#45fa173e0591ac74d80d3cf76704713e14e2a4a6" + integrity sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA== + +"@esbuild/netbsd-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz#366b0ef40cdb986fc751cbdad16e8c25fe1ba879" + integrity sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q== + +"@esbuild/netbsd-x64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz#e985d49a3668fd2044343071d52e1ae815112b3e" + integrity sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg== + +"@esbuild/openbsd-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz#6fb4ab7b73f7e5572ce5ec9cf91c13ff6dd44842" + integrity sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow== + +"@esbuild/openbsd-x64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz#641f052040a0d79843d68898f5791638a026d983" + integrity sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ== + +"@esbuild/openharmony-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz#fc1d33eac9d81ae0a433b3ed1dd6171a20d4e317" + integrity sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg== + +"@esbuild/sunos-x64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz#af2cd5ca842d6d057121f66a192d4f797de28f53" + integrity sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g== + +"@esbuild/win32-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz#78ec7e59bb06404583d4c9511e621db31c760de3" + integrity sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg== + +"@esbuild/win32-ia32@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz#0e616aa488b7ee5d2592ab070ff9ec06a9fddf11" + integrity sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw== + +"@esbuild/win32-x64@0.27.4": + version "0.27.4" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz#1f7ba71a3d6155d44a6faa8dbe249c62ab3e408c" + integrity sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg== + "@eslint-community/eslint-plugin-eslint-comments@^4.3.0": version "4.5.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-4.5.0.tgz#4ffa576583bd99dfbaf74c893635e2c76acba048" @@ -974,7 +1097,7 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": +"@jridgewell/resolve-uri@^3.1.0": version "3.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== @@ -987,19 +1110,11 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0", "@jridgewell/sourcemap-codec@^1.5.5": +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0", "@jridgewell/sourcemap-codec@^1.5.5": version "1.5.5" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25", "@jridgewell/trace-mapping@^0.3.28": version "0.3.31" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" @@ -1743,26 +1858,6 @@ resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c" integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA== -"@tsconfig/node10@^1.0.7": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" - integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== - -"@tsconfig/node12@^1.0.7": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" - integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== - -"@tsconfig/node14@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" - integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== - -"@tsconfig/node16@^1.0.2": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" - integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== - "@tybys/wasm-util@^0.10.0": version "0.10.1" resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz#ecddd3205cf1e2d5274649ff0eedd2991ed7f414" @@ -1816,13 +1911,6 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/esm@^3.2.0": - version "3.2.2" - resolved "https://registry.yarnpkg.com/@types/esm/-/esm-3.2.2.tgz#dd2de62e3e1d8b6ba3e835435d089928a090faa0" - integrity sha512-l3IQQD2sChjNiQVNf28qq+sY9Sjvz7HrcOO3g4ZeSaiQRXQccBaR6cpqXPpzJ3QYCt6UF7+4ugabMRsQTPV+Eg== - dependencies: - "@types/node" "*" - "@types/estree@*", "@types/estree@1.0.8", "@types/estree@^1.0.6", "@types/estree@^1.0.8": version "1.0.8" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" @@ -1848,7 +1936,7 @@ "@types/range-parser" "*" "@types/send" "*" -"@types/express@*", "@types/express@^5.0.0": +"@types/express@*": version "5.0.3" resolved "https://registry.yarnpkg.com/@types/express/-/express-5.0.3.tgz#6c4bc6acddc2e2a587142e1d8be0bce20757e956" integrity sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw== @@ -2513,14 +2601,7 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn-walk@^8.1.1: - version "8.3.4" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" - integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== - dependencies: - acorn "^8.11.0" - -acorn@^8.0.0, acorn@^8.11.0, acorn@^8.4.1: +acorn@^8.0.0: version "8.13.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.13.0.tgz#2a30d670818ad16ddd6a35d3842dacec9e5d7ca3" integrity sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w== @@ -2669,11 +2750,6 @@ are-docs-informative@^0.0.2: resolved "https://registry.yarnpkg.com/are-docs-informative/-/are-docs-informative-0.0.2.tgz#387f0e93f5d45280373d387a59d34c96db321963" integrity sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig== -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -2940,20 +3016,20 @@ body-parser@1.20.3: type-is "~1.6.18" unpipe "1.0.0" -body-parser@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-2.2.0.tgz#f7a9656de305249a715b549b7b8fd1ab9dfddcfa" - integrity sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg== +body-parser@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-2.2.2.tgz#1a32cdb966beaf68de50a9dfbe5b58f83cb8890c" + integrity sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA== dependencies: bytes "^3.1.2" content-type "^1.0.5" - debug "^4.4.0" + debug "^4.4.3" http-errors "^2.0.0" - iconv-lite "^0.6.3" + iconv-lite "^0.7.0" on-finished "^2.4.1" - qs "^6.14.0" - raw-body "^3.0.0" - type-is "^2.0.0" + qs "^6.14.1" + raw-body "^3.0.1" + type-is "^2.0.1" bonjour-service@^1.2.1: version "1.3.0" @@ -3054,7 +3130,7 @@ bundle-name@^4.1.0: dependencies: run-applescript "^7.0.0" -bytes@3.1.2, bytes@^3.1.2: +bytes@3.1.2, bytes@^3.1.2, bytes@~3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== @@ -3434,11 +3510,6 @@ crc32-stream@^6.0.0: crc-32 "^1.2.0" readable-stream "^4.0.0" -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - cross-fetch@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-4.0.0.tgz#f037aef1580bb3a1a35164ea2a848ba81b445983" @@ -3530,7 +3601,7 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6, debug@^4.4.0, debug@^4.4.1: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6, debug@^4.4.0, debug@^4.4.1, debug@^4.4.3: version "4.4.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== @@ -3645,7 +3716,7 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -depd@2.0.0, depd@^2.0.0: +depd@2.0.0, depd@^2.0.0, depd@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== @@ -3685,11 +3756,6 @@ diff-sequences@^29.6.3: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - diff@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" @@ -3916,6 +3982,38 @@ es-to-primitive@^1.3.0: is-date-object "^1.0.5" is-symbol "^1.0.4" +esbuild@~0.27.0: + version "0.27.4" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.27.4.tgz#b9591dd7e0ab803a11c9c3b602850403bef22f00" + integrity sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ== + optionalDependencies: + "@esbuild/aix-ppc64" "0.27.4" + "@esbuild/android-arm" "0.27.4" + "@esbuild/android-arm64" "0.27.4" + "@esbuild/android-x64" "0.27.4" + "@esbuild/darwin-arm64" "0.27.4" + "@esbuild/darwin-x64" "0.27.4" + "@esbuild/freebsd-arm64" "0.27.4" + "@esbuild/freebsd-x64" "0.27.4" + "@esbuild/linux-arm" "0.27.4" + "@esbuild/linux-arm64" "0.27.4" + "@esbuild/linux-ia32" "0.27.4" + "@esbuild/linux-loong64" "0.27.4" + "@esbuild/linux-mips64el" "0.27.4" + "@esbuild/linux-ppc64" "0.27.4" + "@esbuild/linux-riscv64" "0.27.4" + "@esbuild/linux-s390x" "0.27.4" + "@esbuild/linux-x64" "0.27.4" + "@esbuild/netbsd-arm64" "0.27.4" + "@esbuild/netbsd-x64" "0.27.4" + "@esbuild/openbsd-arm64" "0.27.4" + "@esbuild/openbsd-x64" "0.27.4" + "@esbuild/openharmony-arm64" "0.27.4" + "@esbuild/sunos-x64" "0.27.4" + "@esbuild/win32-arm64" "0.27.4" + "@esbuild/win32-ia32" "0.27.4" + "@esbuild/win32-x64" "0.27.4" + escalade@^3.1.1, escalade@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" @@ -4212,11 +4310,6 @@ eslint@^9.22.0, eslint@^9.36.0: natural-compare "^1.4.0" optionator "^0.9.3" -esm@^3.2.25: - version "3.2.25" - resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" - integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== - espree@^10.0.1, espree@^10.1.0, espree@^10.3.0, espree@^10.4.0: version "10.4.0" resolved "https://registry.yarnpkg.com/espree/-/espree-10.4.0.tgz#d54f4949d4629005a1fa168d937c3ff1f7e2a837" @@ -4373,18 +4466,19 @@ express@^4.21.2: utils-merge "1.0.1" vary "~1.1.2" -express@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/express/-/express-5.1.0.tgz#d31beaf715a0016f0d53f47d3b4d7acf28c75cc9" - integrity sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA== +express@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/express/-/express-5.2.1.tgz#8f21d15b6d327f92b4794ecf8cb08a72f956ac04" + integrity sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw== dependencies: accepts "^2.0.0" - body-parser "^2.2.0" + body-parser "^2.2.1" content-disposition "^1.0.0" content-type "^1.0.5" cookie "^0.7.1" cookie-signature "^1.2.1" debug "^4.4.0" + depd "^2.0.0" encodeurl "^2.0.0" escape-html "^1.0.3" etag "^1.8.1" @@ -4754,7 +4848,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@~2.3.2: +fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -4877,6 +4971,13 @@ get-tsconfig@^4.10.1, get-tsconfig@^4.8.1: dependencies: resolve-pkg-maps "^1.0.0" +get-tsconfig@^4.7.5: + version "4.13.7" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.13.7.tgz#b9d8b199b06033ceeea1a93df7ea5765415089bc" + integrity sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q== + dependencies: + resolve-pkg-maps "^1.0.0" + get-uri@^6.0.1: version "6.0.5" resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-6.0.5.tgz#714892aa4a871db671abc5395e5e9447bc306a16" @@ -5220,6 +5321,17 @@ http-errors@~1.6.2: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" +http-errors@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.1.tgz#36d2f65bc909c8790018dd36fb4d93da6caae06b" + integrity sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ== + dependencies: + depd "~2.0.0" + inherits "~2.0.4" + setprototypeof "~1.2.0" + statuses "~2.0.2" + toidentifier "~1.0.1" + http-parser-js@>=0.5.1: version "0.5.10" resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.10.tgz#b3277bd6d7ed5588e20ea73bf724fcbe44609075" @@ -5289,13 +5401,6 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.7.0.tgz#c50cd80e6746ca8115eb98743afa81aa0e147a3e" - integrity sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - iconv-lite@^0.6.3, iconv-lite@~0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -5303,6 +5408,13 @@ iconv-lite@^0.6.3, iconv-lite@~0.6.3: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" +iconv-lite@^0.7.0, iconv-lite@~0.7.0: + version "0.7.2" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.7.2.tgz#d0bdeac3f12b4835b7359c2ad89c422a4d1cc72e" + integrity sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -5354,7 +5466,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.3, inherits@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -6116,11 +6228,6 @@ make-dir@^3.0.2: dependencies: semver "^6.0.0" -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - make-iterator@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/make-iterator/-/make-iterator-1.0.1.tgz#29b33f312aa8f547c4a5e490f56afcec99133ad6" @@ -6972,6 +7079,13 @@ qs@^6.14.0: dependencies: side-channel "^1.1.0" +qs@^6.14.1: + version "6.15.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.15.0.tgz#db8fd5d1b1d2d6b5b33adaf87429805f1909e7b3" + integrity sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ== + dependencies: + side-channel "^1.1.0" + query-selector-shadow-dom@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/query-selector-shadow-dom/-/query-selector-shadow-dom-1.0.1.tgz#1c7b0058eff4881ac44f45d8f84ede32e9a2f349" @@ -7019,15 +7133,15 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" -raw-body@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-3.0.1.tgz#ced5cd79a77bbb0496d707f2a0f9e1ae3aecdcb1" - integrity sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA== +raw-body@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-3.0.2.tgz#3e3ada5ae5568f9095d84376fd3a49b8fb000a51" + integrity sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA== dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.7.0" - unpipe "1.0.0" + bytes "~3.1.2" + http-errors "~2.0.1" + iconv-lite "~0.7.0" + unpipe "~1.0.0" react-is@^18.0.0: version "18.3.1" @@ -7594,7 +7708,7 @@ setprototypeof@1.1.0: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== -setprototypeof@1.2.0: +setprototypeof@1.2.0, setprototypeof@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== @@ -7876,7 +7990,7 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== -statuses@^2.0.1: +statuses@^2.0.1, statuses@~2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.2.tgz#8f75eecef765b5e1cfcdc080da59409ed424e382" integrity sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw== @@ -7899,7 +8013,16 @@ streamx@^2.15.0, streamx@^2.21.0: optionalDependencies: bare-events "^2.2.0" -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -7963,7 +8086,14 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -8161,7 +8291,7 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -toidentifier@1.0.1: +toidentifier@1.0.1, toidentifier@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== @@ -8193,7 +8323,7 @@ ts-declaration-location@^1.0.6: dependencies: picomatch "^4.0.2" -ts-loader@^9.0.0, ts-loader@^9.4.2: +ts-loader@^9.0.0: version "9.5.4" resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.5.4.tgz#44b571165c10fb5a90744aa5b7e119233c4f4585" integrity sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ== @@ -8204,25 +8334,6 @@ ts-loader@^9.0.0, ts-loader@^9.4.2: semver "^7.3.4" source-map "^0.7.4" -ts-node@^10.9.1: - version "10.9.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" - integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - tsconfig-paths-webpack-plugin@^3.2.0: version "3.5.2" resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.5.2.tgz#01aafff59130c04a8c4ebc96a3045c43c376449a" @@ -8257,6 +8368,16 @@ tslib@^2.0.1, tslib@^2.4.0, tslib@^2.6.2: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== +tsx@^4.21.0: + version "4.21.0" + resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.21.0.tgz#32aa6cf17481e336f756195e6fe04dae3e6308b1" + integrity sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw== + dependencies: + esbuild "~0.27.0" + get-tsconfig "^4.7.5" + optionalDependencies: + fsevents "~2.3.3" + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -8289,7 +8410,7 @@ type-fest@^2.12.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== -type-is@^2.0.0, type-is@^2.0.1: +type-is@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/type-is/-/type-is-2.0.1.tgz#64f6cf03f92fce4015c2b224793f6bdd4b068c97" integrity sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw== @@ -8520,11 +8641,6 @@ uuid@^9.0.1: resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== -v8-compile-cache-lib@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - v8flags@~3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.2.0.tgz#b243e3b4dfd731fa774e7492128109a0fe66d656" @@ -8826,7 +8942,16 @@ wordwrapjs@^4.0.0: reduce-flatten "^2.0.0" typical "^5.2.0" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -8940,11 +9065,6 @@ yesno@^0.4.0: resolved "https://registry.yarnpkg.com/yesno/-/yesno-0.4.0.tgz#5d674f14d339f0bd4b0edc47f899612c74fcd895" integrity sha512-tdBxmHvbXPBKYIg81bMCB7bVeDmHkRzk5rVJyYYXurwKkHq/MCd8rz4HSJUP7hW0H2NlXiq8IFiWvYKEHhlotA== -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" From fe823e32ab3337aa69502b971135941b9a9345f1 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Wed, 25 Mar 2026 16:39:25 +1030 Subject: [PATCH 02/29] INT-3358: Remove tinymce/miniature as dependency --- package.json | 4 +--- src/main/ts/component/Editor.ts | 10 ++++------ yarn.lock | 25 ++----------------------- 3 files changed, 7 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index 92c5aba..1f1d310 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,5 @@ "typescript": "~5.9.2", "webpack": "^5.75.0" }, - "dependencies": { - "@tinymce/miniature": "^6.0.0" - } + "dependencies": {} } diff --git a/src/main/ts/component/Editor.ts b/src/main/ts/component/Editor.ts index 4922e17..6b9026d 100644 --- a/src/main/ts/component/Editor.ts +++ b/src/main/ts/component/Editor.ts @@ -1,7 +1,7 @@ import { Resolve, Obj, Fun, Global } from '@ephox/katamari'; import { TinyMCE, Editor } from 'tinymce'; import { ScriptLoader } from '../utils/ScriptLoader'; -import { TinyVer } from '@tinymce/miniature'; + type EditorOptions = Parameters[0]; type EventHandler = Parameters[1]; @@ -80,7 +80,8 @@ const configAttributes: Record unknown> = { const configRenames: Record = {}; // Function that checks if the disabled option is supported with the version used -const isDisabledOptionSupported = (tinymce: TinyMCE): boolean => !TinyVer.isLessThan(tinymce, '7.6.0'); +const isDisabledOptionSupported = (editor: Editor | undefined): boolean => + !!editor && typeof editor.options?.set === 'function' && editor.options.isRegistered('disabled'); class TinyMceEditor extends HTMLElement { private _status: Status; @@ -386,10 +387,7 @@ class TinyMceEditor extends HTMLElement { } set disabled(value: boolean) { - const tinymce = this._getTinymce?.(); - const isVersionNewer = tinymce ? isDisabledOptionSupported(tinymce) : true; - - if (this._editor && this._status === Status.Ready && isVersionNewer) { + if (this._editor && this._status === Status.Ready && isDisabledOptionSupported(this._editor)) { this._editor.options.set('disabled', value); } diff --git a/yarn.lock b/yarn.lock index 1e316e8..b9ef6bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -617,7 +617,7 @@ dependencies: tslib "^2.4.0" -"@ephox/agar@^8.0.0", "@ephox/agar@^8.0.1": +"@ephox/agar@^8.0.1": version "8.0.1" resolved "https://registry.yarnpkg.com/@ephox/agar/-/agar-8.0.1.tgz#6772ed7abd90adee5b08bc6f8baf0cb4f22b8d1c" integrity sha512-2LR/u0oos9GadRoLFDVE6NRDV8Tl9+DYQyouVYn0+7afAYdouyw+nXaoTVG5nnvMG+ofsmldKOC82nJWu0a4kQ== @@ -736,17 +736,6 @@ dependencies: "@ephox/dispute" "^1.0.3" -"@ephox/mcagar@^9.0.0": - version "9.0.1" - resolved "https://registry.yarnpkg.com/@ephox/mcagar/-/mcagar-9.0.1.tgz#d740d02628063e8df86ca8cdd8aa307654b1c69b" - integrity sha512-iNMP8mkz8AtgiRceU4TAnstQje3RG8yxM/QoWKkriCeh6n5fe1sSfexFRVW3fwZ0bUrjTlyawSqoH0yhESqJjQ== - dependencies: - "@ephox/agar" "^8.0.1" - "@ephox/katamari" "^9.1.6" - "@ephox/sand" "^6.0.10" - "@ephox/sugar" "^9.3.1" - fast-check "^2.0.0" - "@ephox/sand@^6.0.10": version "6.0.10" resolved "https://registry.yarnpkg.com/@ephox/sand/-/sand-6.0.10.tgz#1bd3e03ce339ab282fa3ac03591badc13f7d69b1" @@ -754,7 +743,7 @@ dependencies: "@ephox/katamari" "^9.1.6" -"@ephox/sugar@^9.2.1", "@ephox/sugar@^9.3.0", "@ephox/sugar@^9.3.1": +"@ephox/sugar@^9.2.1", "@ephox/sugar@^9.3.1": version "9.3.1" resolved "https://registry.yarnpkg.com/@ephox/sugar/-/sugar-9.3.1.tgz#082dbe885d41e657eff7ef6275d648f3dff88334" integrity sha512-NQMqDN0zC+IZGuhBuz/7RxncfJsmTBhCHgaqkHOJ5d1E0CIL9afIizBYQ0JSHS3osAb9woGGtwPobjCx3/Srpw== @@ -1843,16 +1832,6 @@ typescript "^5.7.2" typescript-eslint "^8.26.1" -"@tinymce/miniature@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@tinymce/miniature/-/miniature-6.0.0.tgz#d11ca91292fa614926faf399166898874baedd92" - integrity sha512-bLpaTTgbyMHP3V8bucSxvCTVTUjRRk05zDgnlD5Hj2eo6hEyHT1FCqpuhdVLHx9mbCydrlAIhhsY8Ex6Hp8Qqg== - dependencies: - "@ephox/agar" "^8.0.0" - "@ephox/katamari" "^9.1.5" - "@ephox/mcagar" "^9.0.0" - "@ephox/sugar" "^9.3.0" - "@tootallnate/quickjs-emscripten@^0.23.0": version "0.23.0" resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c" From 5020b0a56152b99f23daebb3b7514a61169d4382 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Thu, 26 Mar 2026 14:33:57 +1030 Subject: [PATCH 03/29] INT-3358: Remove @tinymce/miniature dependency --- package.json | 7 +- src/demo/html/disabled.html | 5 +- src/demo/js/configs/full-config.js | 1516 +++++++++++++++++++++++++++ src/demo/ts/Server.ts | 22 +- src/test/ts/alien/Utils.ts | 21 + src/test/ts/browser/DisabledTest.ts | 120 +++ yarn.lock | 38 +- 7 files changed, 1697 insertions(+), 32 deletions(-) create mode 100644 src/demo/js/configs/full-config.js create mode 100644 src/test/ts/alien/Utils.ts create mode 100644 src/test/ts/browser/DisabledTest.ts diff --git a/package.json b/package.json index 1f1d310..2ff2789 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@ephox/swag": "^4.6.0", "@tinymce/beehive-flow": "^0.19.0", "@tinymce/eslint-plugin": "^3.0.0", + "@tinymce/miniature": "^6.0.0", "@types/node": "^24.5.2", "@typescript-eslint/eslint-plugin": "^8.44.0", "@typescript-eslint/parser": "^8.44.0", @@ -42,10 +43,12 @@ "eslint-plugin-prefer-arrow": "^1.2.3", "express": "^5.2.1", "rollup": "^4.24.0", - "tinymce": "^8.0.0", + "tinymce": "^8", "tsx": "^4.21.0", "typescript": "~5.9.2", "webpack": "^5.75.0" }, - "dependencies": {} + "dependencies": { + "tinymce-8": "npm:tinymce@^8" + } } diff --git a/src/demo/html/disabled.html b/src/demo/html/disabled.html index d1e0e30..5c87bbd 100644 --- a/src/demo/html/disabled.html +++ b/src/demo/html/disabled.html @@ -34,12 +34,11 @@

TinyMCE WebComponent Demo: Disabled and Readonly

Readonly mode

- +

Disabled state

- +
- diff --git a/src/demo/js/configs/full-config.js b/src/demo/js/configs/full-config.js new file mode 100644 index 0000000..106f971 --- /dev/null +++ b/src/demo/js/configs/full-config.js @@ -0,0 +1,1516 @@ +var fullConfig = (function (exports) { + 'use strict'; + + const JWT_SERVER_URL = 'https://tinymce-ai-jwt.onrender.com'; + + var TinymceaiConfig = { + config: { + // tinymceai_api_url: 'https://tinymceai.api.staging.tiny.cloud/', + + // REQUIRED: tinymceai_service_url — Base URL of the AI backend service + // tinymceai_service_url: 'https://tinymceai.api.staging.tiny.cloud/', + // tinymceai_service_url: 'https://tinymceai.api.dev.tiny.cloud/', + tinymceai_token_provider: () => { + return fetch(`${JWT_SERVER_URL}/jwt`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }).then(r => r.json()); + }, + + + // content_id — Groups conversations by document + content_id: 'render_doc_1', + + // tinymceai_sidebar_type — 'static' | 'floating' (default: 'static') + tinymceai_sidebar_type: 'static', + + // Model configuration + // Available Models: auto (agent-1), gpt-5.2, gpt-5.1, gpt-5, gpt-5-mini, + // claude-4-5-haiku, claude-4-5-sonnet, gemini-3-pro, gemini-3-flash, + // gemini-2-5-flash, gpt-4.1, gpt-4.1-mini + + // tinymceai_default_model — Model ID to select by default + tinymceai_default_model: 'auto', + + // tinymceai_allow_model_selection — Show model selection dropdown (default: true) + tinymceai_allow_model_selection: true, + + // tinymceai_quickactions_menu — Items in the Quick Actions menu + // Correct control IDs: ai-quickactions-chat-prompts, ai-quickactions-improve-writing, + // ai-quickactions-continue-writing, ai-quickactions-check-grammar, + // ai-quickactions-change-length, ai-quickactions-change-tone, + // ai-quickactions-translate, ai-quickactions-custom + tinymceai_quickactions_menu: [ + 'ai-quickactions-chat-prompts', + 'ai-quickactions-improve-writing', + 'ai-quickactions-continue-writing', + 'ai-quickactions-check-grammar', + 'ai-quickactions-change-length', + 'ai-quickactions-change-tone', + 'ai-quickactions-translate', + 'ai-quickactions-custom' + ], + + // tinymceai_quickactions_chat_prompts — Items in the "Chat commands" sub-menu + // Correct control IDs: ai-chat-explain, ai-chat-summarize, ai-chat-highlight-key-points + tinymceai_quickactions_chat_prompts: [ + 'ai-chat-explain', + 'ai-chat-summarize', + 'ai-chat-highlight-key-points' + ], + + // tinymceai_quickactions_change_tone_menu — Items in the "Change tone" sub-menu + // Correct control IDs: ai-quickactions-tone-casual, ai-quickactions-tone-direct, + // ai-quickactions-tone-friendly, ai-quickactions-tone-confident, ai-quickactions-tone-professional + tinymceai_quickactions_change_tone_menu: [ + 'ai-quickactions-tone-casual', + 'ai-quickactions-tone-direct', + 'ai-quickactions-tone-friendly', + 'ai-quickactions-tone-confident', + 'ai-quickactions-tone-professional' + ], + + // tinymceai_languages — Languages in the "Translate" sub-menu + // Each item: { title: string, language: string } + tinymceai_languages: [ + { title: 'English', language: 'english' }, + { title: 'Chinese (Simplified)', language: 'chinese' }, + { title: 'Spanish', language: 'spanish' }, + { title: 'German', language: 'german' }, + { title: 'Japanese', language: 'japanese' }, + { title: 'Portuguese', language: 'portuguese' }, + { title: 'Korean', language: 'korean' }, + { title: 'Italian', language: 'italian' }, + { title: 'Russian', language: 'russian' }, + { title: 'French', language: 'french' } + ], + + // tinymceai_quickactions_custom — Custom commands in the "Other" sub-menu + // Chat type: { type: 'chat', title: string, prompt: string } + // Action type: { type: 'action', title: string, prompt: string, model: string } + tinymceai_quickactions_custom: [ + { + type: 'chat', + title: 'Generate Outline', + prompt: 'Create a detailed outline for the selected content' + }, + { + type: 'action', + title: 'Convert to Table', + prompt: 'Convert this data into an HTML table', + model: 'gpt-4.1' + }, + { + type: 'chat', + title: 'Explain Like I\'m 5', + prompt: 'Explain the selected content as if I am a 5 year old child' + } + ], + + // tinymceai_chat_welcome_message — Custom HTML welcome message in chat sidebar + tinymceai_chat_welcome_message: '

Welcome to AI Chat!

I can help you write, edit, review, and brainstorm. Ask me anything or use the quick actions above.

', + + // tinymceai_chat_fetch_sources — Provides a list of external sources users can attach + // Returns Promise + tinymceai_chat_fetch_sources: () => { + console.log('[tinymceai] tinymceai_chat_fetch_sources called'); + return Promise.resolve([ + { + label: 'Sample Documents', + icon: 'document-properties', + sources: [ + { label: 'Company Guidelines', id: 'doc-guidelines', type: 'web-resource' }, + { label: 'Product Roadmap', id: 'doc-roadmap', type: 'file' }, + { label: 'FAQ Document', id: 'doc-faq', type: 'web-resource' } + ] + } + ]); + }, + + // tinymceai_chat_fetch_source — Fetches a specific external source by ID + // Returns Promise — { type: 'file', file: File } or { type: 'web-resource', url: string } + tinymceai_chat_fetch_source: (id) => { + console.log('[tinymceai] tinymceai_chat_fetch_source called with id:', id); + if (id === 'doc-guidelines') { + return Promise.resolve({ type: 'web-resource', url: 'https://www.tiny.cloud' }); + } else if (id === 'doc-roadmap') { + const blob = new Blob(['Sample roadmap content for testing'], { type: 'text/plain' }); + const file = new File([blob], 'roadmap.txt', { type: 'text/plain' }); + return Promise.resolve({ type: 'file', file: file }); + } else { + return Promise.resolve({ type: 'web-resource', url: 'https://www.tiny.cloud/docs' }); + } + }, + }, + toolbar: 'tinymceai-chat tinymceai-review tinymceai-quickactions', + name: 'tinymceai', + }; + + const advtemplate_templates = [ + { + id: '1', + title: 'Quick replies', + items: [ + { + id: '2', + title: 'Message received', + content: '

Hey {{Customer.FirstName}}!

\n

Just a quick note to say we’ve received your message, and will get back to you within 48 hours.

\n

For reference, your ticket number is: {{Ticket.Number}}

\n

Should you have any questions in the meantime, just reply to this email and it will be attached to this ticket.

\n

 

\n

Regards,

\n

{{Agent.FirstName}}

' + }, + { + id: '3', + title: 'Thanks for the feedback', + content: '

Hi {{Customer.FirstName}},

\n

We appreciate you taking the time to provide feedback on {{Product.Name}}.

\n

It sounds like it wasn’t able to fully meet your expectations, for which we apologize. Rest assured our team looks at each piece of feedback and uses it to decide what to focus on next with {{Product.Name}}.

\n

 

\n

All the best, and let us know if there’s anything else we can do to help.

\n

-{{Agent.FirstName}}

' + }, + { + id: '6', + title: 'Still working on case', + content: '

\n

 

\n

Hi {{Customer.FirstName}},

\n

Just a quick note to let you know we’re still working on your case. It’s taking a bit longer than we hoped, but we’re aiming to get you an answer in the next 48 hours.

\n

Stay tuned,

\n

{{Agent.FirstName}}

' + } + ] + }, + { + id: '4', + title: 'Closing tickets', + items: [ + { + id: '7', + title: 'Closing ticket', + content: '

Hi {{Customer.FirstName}},

\n

We haven’t heard back from you in over a week, so we have gone ahead and closed your ticket number {{Ticket.Number}}.

\n

If you’re still running into issues, not to worry, just reply to this email and we will re-open your ticket.

\n

 

\n

All the best,

\n

{{Agent.FirstName}}

' + }, + { + id: '8', + title: 'Post-call survey', + content: '

Hey {{Customer.FirstName}}!

\n

 

\n

How did we do?

\n

If you have a few moments, we’d love you to fill out our post-support survey: {{Survey.Link}}

\n

 

\n

Thanks in advance!
{{Company.Name}} Customer Support

' + } + ] + }, + { + id: '5', + title: 'Product support', + items: [ + { + id: '9', + title: 'How to find model number', + content: '

Hi {{Customer.FirstName}},

\n

 

\n

My name is {{Agent.FirstName}} and I will be glad to assist you today.

\n

To troubleshoot your issue, we first need your model number, which can be found on the underside of your product beneath the safety warning label. 

\n

It should look something like the following: XX.XXXXX.X

\n

Once you send it over, I will advise on next steps.

\n

 

\n

Thanks!

\n

{{Agent.FirstName}}

' + }, + { + id: '10', + title: 'Support escalation', + content: '

\n

 

\n

Hi {{Customer.FirstName}},

\n

We have escalated your ticket {{Ticket.Number}} to second-level support.

\n

You should hear back from the new agent on your case, {{NewAgent.FirstName}}, shortly.

\n

 

\n

Thanks,

\n

{{Company.Name}} Customer Support

' + } + ] + }, + { + id: '6', + title: 'Email Signatures', + items: [ + { + id: '11', + title: 'Tiny Signature', + content: '

Regards


Tiny Technologies Inc

Shiridi Gandham
QA Template Manager

Email: shiridi.gandham@tiny.cloud
Phone: (+617) 3161 3557

Tiny Technologies
www.tiny.cloud

Linkedin Facebook Twitter GitHub Stack Overflow

' + } + ] + } + ]; + + var AdvtemplateConfig = { + toolbar: 'addtemplate inserttemplate', + name: 'advtemplate', + config: { + advtemplate_templates + } + }; + + var AccordionConfig = { + name: 'accordion', + toolbar: 'accordion', + config: {} + }; + + const mergetags_list = [ + { + value: 'Current.Date', + title: 'Current date in DD/MM/YYYY format' + }, + { + value: 'Campaign.Toc', + title: 'Linked table of contents in your campaign' + }, + { + title: 'Phone', + menu: [ + { + value: 'Phone.Home' + }, + { + value: 'Phone.work' + } + ] + }, + { + title: 'Person', + menu: [ + { + value: 'Person.Name' + }, + { + value: 'Person.Name.First' + }, + { + value: 'Person.Name.Last' + }, + { + value: 'Person.Name.Full' + }, + { + title: 'Email', + menu: [ + { + value: 'Person.Email.Work' + }, + { + value: 'Person.Email.Home' + } + ] + } + ] + } + ]; + + var MergetagsConfig = { + toolbar: 'mergetags', + name: 'mergetags', + config: { + mergetags_prefix: '${', + mergetags_suffix: '}', + mergetags_list, + } + }; + + const API_URL$1 = 'https://demouserdirectory.tiny.cloud/v1/users'; + + const mentions_fetch = async (query, success) => { + const searchPhrase = query.term.toLowerCase(); + await fetch(`${API_URL$1}?q=${encodeURIComponent(searchPhrase)}`) + .then((response) => response.json()) + .then((users) => success(users.data.map((userInfo) => ({ + id: userInfo.id, + name: userInfo.name, + image: userInfo.avatar, + description: userInfo.custom.role + })))) + .catch((error) => console.log(error)); + }; + + const mentions_menu_complete = (editor, userInfo) => { + const span = editor.getDoc().createElement('span'); + span.className = 'mymention'; + span.setAttribute('data-mention-id', userInfo.id); + span.appendChild(editor.getDoc().createTextNode('@' + userInfo.name)); + return span; + }; + + const createCard = (userInfo) => { + const div = document.createElement('div'); + div.innerHTML = ( + '
' + + '' + + '

' + userInfo.name + '

' + + '

' + userInfo.description + '

' + + '
' + ); + return div; + }; + + const mentions_menu_hover = async (userInfo, success) => { + const card = createCard(userInfo); + success(card); + }; + + const mentions_select = async (mention, success) => { + const id = mention.getAttribute('data-mention-id'); + await fetch(`${API_URL$1}/${id}`) + .then((response) => response.json()) + .then((userInfo) => { + const card = createCard({ + id: userInfo.id, + name: userInfo.name, + image: userInfo.avatar, + description: userInfo.custom.role + }); + success(card); + }) + .catch((error) => console.error(error)); + }; + + var MentionsConfig = { + toolbar: 'mentions', + name: 'mentions', + config: { + mentions_fetch, + mentions_menu_complete, + mentions_menu_hover, + mentions_select, + mentions_selector: '.mymention', + mentions_item_type: 'profile', + mentions_min_chars: 0, + } + }; + + const user_id$1 = 'james-wilson'; + + const tinycomments_create = (req, done, fail) => { + if (req.content === 'fail') { + fail(new Error('Something has gone wrong...')); + } else { + const uid = 'annotation-' + randomString(); + conversationDb[uid] = { + uid, + comments: [{ + uid, + author: user_id$1, + authorName: 'James Wilson', + authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg', + content: req.content, + createdAt: req.createdAt, + modifiedAt: req.createdAt + }] + }; + setTimeout(() => done({ conversationUid: uid }), fakeDelay); + } + }; + + const fakeDelay = 200; + + const randomString = () => { + return crypto.getRandomValues(new Uint32Array(1))[0].toString(36).substring(2, 14); + }; + + + const conversationDb = {}; + + const tinycomments_reply = (req, done) => { + const replyUid = 'annotation-' + randomString(); + conversationDb[req.conversationUid].comments.push({ + uid: replyUid, + author: user_id$1, + authorName: 'James Wilson', + authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg', + content: req.content, + createdAt: req.createdAt, + modifiedAt: req.createdAt + }); + setTimeout(() => done({ commentUid: replyUid }), fakeDelay); + }; + + const tinycomments_delete = (req, done) => { + { + setTimeout(() => done({ canDelete: false, reason: 'Must be admin user' }), fakeDelay); + } + }; + + const tinycomments_resolve = (req, done) => { + const conversation = conversationDb[req.conversationUid]; + if (user_id$1 === conversation.comments[0].author) { // Replace wth your own logic, e.g. check if user has admin priveleges + delete conversationDb[req.conversationUid]; + setTimeout(() => done({ canResolve: true }), fakeDelay); + } else { + setTimeout(() => done({ canResolve: false, reason: 'Must be conversation author' }), fakeDelay); + } + }; + + const tinycomments_delete_comment = (req, done) => { + const oldcomments = conversationDb[req.conversationUid].comments; + let reason = 'Comment not found'; + + const newcomments = oldcomments.filter((comment) => { + if (comment.uid === req.commentUid) { // Found the comment to delete + if (user_id$1 === comment.author) { // Replace with your own logic, e.g. check if user has admin privileges + return false; // Remove the comment + } else { + reason = 'Not authorised to delete this comment'; // Update reason + } + } + return true; // Keep the comment + }); + + if (newcomments.length === oldcomments.length) { + setTimeout(() => done({ canDelete: false, reason }), fakeDelay); + } else { + conversationDb[req.conversationUid].comments = newcomments; + setTimeout(() => done({ canDelete: true }), fakeDelay); + } + }; + + const tinycomments_edit_comment = (req, done) => { + const oldcomments = conversationDb[req.conversationUid].comments; + let reason = 'Comment not found'; + let canEdit = false; + + const newcomments = oldcomments.map((comment) => { + if (comment.uid === req.commentUid) { // Found the comment to delete + if (user_id$1 === comment.author) { // Replace with your own logic, e.g. check if user has admin privileges + canEdit = true; // User can edit the comment + return { ...comment, content: req.content, modifiedAt: new Date().toISOString() }; // Update the comment + } else { + reason = 'Not authorised to edit this comment'; // Update reason + } + } + return comment; // Keep the comment + }); + + if (canEdit) { + conversationDb[req.conversationUid].comments = newcomments; + setTimeout(() => done({ canEdit }), fakeDelay); + } else { + setTimeout(() => done({ canEdit, reason }), fakeDelay); + } + }; + + const tinycomments_delete_all = (req, done) => { + const conversation = conversationDb[req.conversationUid]; + if (user_id$1 === conversation.comments[0].author) { // Replace wth your own logic, e.g. check if user has admin priveleges + delete conversationDb[req.conversationUid]; + setTimeout(() => done({ canDelete: true }), fakeDelay); + } else { + setTimeout(() => done({ canDelete: false, reason: 'Must be conversation author' }), fakeDelay); + } + }; + + const tinycomments_lookup = (req, done) => { + setTimeout(() => { + done({ + conversation: { + uid: conversationDb[req.conversationUid].uid, + comments: [...conversationDb[req.conversationUid].comments] + } + }); + }, fakeDelay); + }; + + const tinycomments_fetch = (conversationUids, done) => { + const fetchedConversations = {}; + conversationUids.forEach((uid) => { + const conversation = conversationDb[uid]; + if (conversation) { + fetchedConversations[uid] = {...conversation}; + } + }); + setTimeout(() => done({ conversations: fetchedConversations }), fakeDelay); + }; + + var TinyCommentsConfig = { + toolbar: 'comments', + name: 'tinycomments', + config: { + tinycomments_mode: 'callback', + tinycomments_mentions_enabled: true, + tinycomments_create, + tinycomments_reply, + tinycomments_delete, + tinycomments_resolve, + tinycomments_delete_all, + tinycomments_lookup, + tinycomments_delete_comment, + tinycomments_edit_comment, + tinycomments_fetch, + // Fallback TinyMCE < 7.8 + tinycomments_author: user_id$1, + tinycomments_author_name: 'James Wilson', + tinycomments_avatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg', + // Fallback for tinymce >= 7.8 + tinycomments_fetch_author_info: (done) => { + setTimeout(() => done({ + author: user_id$1, + authorName: 'James Wilson', + authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg', + }), fakeDelay); + }, + } + }; + + var AdvlistConfig = { + toolbar: 'numlist bullist', + name: 'advlist', + config: { + advlist_number_styles: "default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman", + advlist_bullet_styles: "default,circle,disc,square", + }, + // Code samples for each configuration option: + // + // advlist_number_styles + // Specifies the number styles available in the list style dropdown + // - default: Standard numbering (1, 2, 3...) + // - lower-alpha: Lowercase letters (a, b, c...) + // - lower-greek: Lowercase Greek letters (α, β, γ...) + // - lower-roman: Lowercase Roman numerals (i, ii, iii...) + // - upper-alpha: Uppercase letters (A, B, C...) + // - upper-roman: Uppercase Roman numerals (I, II, III...) + // Usage: advlist_number_styles: "default,lower-alpha,lower-roman" + // + // advlist_bullet_styles + // Specifies the bullet styles available in the list style dropdown + // - default: Standard bullet point (•) + // - circle: Open circle (○) + // - disc: Filled circle/disc (●) + // - square: Square bullet (■) + // Usage: advlist_bullet_styles: "default,circle,square" + }; + + const suggestededitsModel = { + 'history': { + '2': [ + { + 'id': 1, + 'uid': 'james-wilson', + 'timestamp': 1752576936000, + 'feedback': 'Nice improvement!' + } + ] + }, + 'version': 1, + 'contents': [ + { + 'type': 'p', + 'children': [ + { + 'type': 'img', + 'attrs': { + 'style': 'display: block; margin-left: auto; margin-right: auto;', + 'title': 'Tiny Logo', + 'src': 'https://www.tiny.cloud/docs/images/logos/android-chrome-256x256.png', + 'alt': 'TinyMCE Logo', + 'width': '128', + 'height': '128' + } + } + ] + }, + { + 'type': 'h2', + 'attrs': { + 'style': 'text-align: center;' + }, + 'children': [ + { + 'text': 'Welcome to the TinyMCE Suggested Edits ' + }, + { + 'text': 'interactive ', + 'opData': { + 'id': 1, + 'type': 'insert', + 'uid': 'alex-thompson', + 'timestamp': 1752015064000 + } + }, + { + 'text': 'demo!' + } + ] + }, + { + 'type': 'p', + 'attrs': { + 'style': 'text-align: center;' + }, + 'children': [ + { + 'text': 'Try out the Suggested Edits feature' + }, + { + 'text': ': type in the editor, apply formatting or delete some content. T', + 'opData': { + 'id': 2, + 'type': 'insert', + 'uid': 'alex-thompson', + 'timestamp': 1752415064000 + } + }, + { + 'text': ' by typing in the editor and t', + 'opData': { + 'id': 2, + 'type': 'remove', + 'uid': 'alex-thompson', + 'timestamp': 1752415064000 + } + }, + { + 'text': 'hen' + }, + { + 'text': ',', + 'opData': { + 'id': 3, + 'type': 'insert', + 'uid': 'alex-thompson', + 'timestamp': 1752515064000 + } + }, + { + 'text': ' click' + }, + { + 'text': 'ing', + 'opData': { + 'id': 4, + 'type': 'remove', + 'uid': 'alex-thompson', + 'timestamp': 1752515064000 + } + }, + { + 'text': ' the Review Changes button in the toolbar' + }, + { + 'text': ' to see your changes', + 'opData': { + 'id': 5, + 'type': 'insert', + 'uid': 'kai-nakamura', + 'timestamp': 1752615064000 + } + }, + { + 'text': '.' + } + ] + }, + { + 'type': 'p', + 'attrs': { + 'style': 'text-align: center;' + }, + 'children': [ + { + 'text': 'And visit the ' + }, + { + 'text': 'pricing page', + 'opData': { + 'id': 6, + 'type': 'modify', + 'uid': 'kai-nakamura', + 'timestamp': 1752615064000 + }, + 'format': [ + { + 'type': 'a', + 'attrs': { + 'href': 'https://www.tiny.cloud/pricing' + } + } + ], + 'oldFormat': [ + { + 'type': 'a', + 'attrs': { + 'href': 'https://www.tiny.cloud/pricing' + } + }, + 'em' + ] + }, + { + 'text': ' to learn more about our Premium plugins.' + } + ] + }, + { + 'type': 'h2', + 'children': [ + { + 'text': 'A simple table to play with' + } + ] + }, + { + 'type': 'table', + 'attrs': { + 'style': 'border-collapse: collapse; width: 100%;', + 'border': '1' + }, + 'children': [ + { + 'type': 'thead', + 'children': [ + { + 'type': 'tr', + 'attrs': { + 'style': 'text-align: left;' + }, + 'children': [ + { + 'type': 'th', + 'children': [ + { + 'text': 'Product' + } + ] + }, + { + 'type': 'th', + 'children': [ + { + 'text': 'Cost' + } + ] + }, + { + 'type': 'th', + 'children': [ + { + 'text': 'Really?' + } + ] + } + ] + } + ] + }, + { + 'type': 'tbody', + 'children': [ + { + 'type': 'tr', + 'children': [ + { + 'type': 'td', + 'children': [ + { + 'text': 'TinyMCE Cloud' + } + ] + }, + { + 'type': 'td', + 'children': [ + { + 'text': 'Get started for free' + } + ] + }, + { + 'type': 'td', + 'children': [ + { + 'text': 'Yes!', + 'format': [ + 'strong' + ] + } + ] + } + ] + }, + { + 'type': 'tr', + 'children': [ + { + 'type': 'td', + 'children': [ + { + 'text': 'Plupload' + } + ] + }, + { + 'type': 'td', + 'children': [ + { + 'text': 'Free' + } + ] + }, + { + 'type': 'td', + 'children': [ + { + 'text': 'Yes!', + 'format': [ + 'strong' + ] + } + ] + } + ] + } + ] + } + ] + }, + { + 'type': 'h2', + 'opData': { + 'id': 7, + 'type': 'insert', + 'uid': 'mia-andersson', + 'timestamp': 1752576331000 + }, + 'children': [ + { + 'text': 'Found a bug?' + } + ] + }, + { + 'type': 'p', + 'children': [ + { + 'text': ' ', + 'opData': { + 'id': 7, + 'type': 'remove', + 'uid': 'mia-andersson', + 'timestamp': 1752576331000 + } + }, + { + 'text': 'If you believe you have found a bug please create an issue on the ', + 'opData': { + 'id': 7, + 'type': 'insert', + 'uid': 'mia-andersson', + 'timestamp': 1752576331000 + } + }, + { + 'text': 'GitHub repo', + 'opData': { + 'id': 7, + 'type': 'insert', + 'uid': 'mia-andersson', + 'timestamp': 1752576331000 + }, + 'format': [ + { + 'type': 'a', + 'attrs': { + 'href': 'https://github.com/tinymce/tinymce/issues' + } + } + ] + }, + { + 'text': ' to report it to the developers.', + 'opData': { + 'id': 7, + 'type': 'insert', + 'uid': 'mia-andersson', + 'timestamp': 1752576331000 + } + } + ] + }, + { + 'type': 'h2', + 'children': [ + { + 'text': 'Finally…' + } + ] + }, + { + 'type': 'p', + 'children': [ + { + 'text': 'Don’t forget to check out ' + }, + { + 'text': 'Plupload', + 'format': [ + { + 'type': 'a', + 'attrs': { + 'href': 'http://www.plupload.com', + 'target': '_blank', + 'rel': 'noopener' + } + } + ] + }, + { + 'text': ', the upload solution featuring HTML5 upload support.' + } + ] + }, + { + 'type': 'p', + 'children': [ + { + 'text': 'Thanks for supporting TinyMCE. We hope it helps you and your users create great content.' + } + ] + }, + { + 'type': 'p', + 'children': [ + { + 'text': 'All the best from the TinyMCE team.' + } + ] + } + ] + }; + + var SuggestedEditConfig = { + toolbar: 'suggestededits', + name: 'suggestededits', + config: { + suggestededits_model: suggestededitsModel, + suggestededits_access: 'full', + suggestededits_content: 'html', + }, + }; + + var CodeSampleConfig = { + name: 'codesample', + toolbar: 'codesample', + config: { + codesample_languages: [ + { text: 'HTML/XML', value: 'markup' }, + { text: 'JavaScript', value: 'javascript' }, + { text: 'CSS', value: 'css' }, + { text: 'PHP', value: 'php' }, + { text: 'Ruby', value: 'ruby' }, + { text: 'Python', value: 'python' }, + { text: 'Java', value: 'java' }, + { text: 'C', value: 'c' }, + { text: 'C#####', value: 'csharpppppp' }, + { text: 'C++', value: 'cpp' } + ], + } + }; + + var ExportWordConfig = { + toolbar: 'exportword', + name: 'exportword', + config: { + exportword_service_url: "https://exportdocx.converter.tiny.cloud", + exportword_converter_options: { + // 'Letter', 'Legal', 'Tabloid', 'Statement', 'Executive', 'A3', 'A4', 'A5', 'A6', 'B4', 'B5' + format: 'A4', + + margin_top: '1in', + margin_bottom: '1in', + margin_right: '1in', + margin_left: '1in', + header: [ + { + html: '

First page header.

', + css: 'h1 { font-size: 30px; }', + + //'default', 'even', 'odd', 'first' + type: 'first' + } + ], + + footer: [ + { + html: '

Page footer

', + css: 'p { font-size: 12px; }', + // 'default', 'even', 'odd', 'first' + type: 'default' + } + ], + + // 'portrait' or 'landscape' + orientation: 'portrait', + auto_pagination: true, + + base_url: 'https://example.com', + timezone: 'UTC' + }, + exportword_converter_style: 'p { color: cyan !important }', + }, + }; + + var InsertDatetimeConfig = { + name: 'insertdatetime', + toolbar: 'insertdatetime', + config: { + // override the default formatting rule for date formats inserted by the mceInsertDate command + insertdatetime_dateformat: "%Y/%m/%d", + + // override the default formatting rule for times inserted by the mceInsertTime command + insertdatetime_timeformat: "%H%M%S", + + // specify a list of date/time formats to be used in the date menu or date select box + insertdatetime_formats: ["%H:%M:%S", "%Y-%m-%d", "%I:%M:%S %p", "%D", "%H%M%S", "%Y/%m/%d"], + } + }; + + var AnchorConfig = { + name: 'anchor', + toolbar: 'anchor', + config: {} + }; + + var AutolinkConfig = { + name: 'autolink', + config: {} + }; + + var AutosaveConfig = { + name: 'autosave', + config: {} + }; + + var CharmapConfig = { + name: 'charmap', + toolbar: 'charmap', + config: {} + }; + + var CodeConfig = { + name: 'code', + toolbar: 'code', + config: {} + }; + + var EditimageConfig = { + name: 'editimage', + config: {} + }; + + var DirectionalityConfig = { + name: 'directionality', + toolbar: 'ltr rtl', + config: {} + }; + + var EmoticonsConfig = { + name: 'emoticons', + toolbar: 'emoticons', + config: {} + }; + + var FullscreenConfig = { + name: 'fullscreen', + toolbar: 'fullscreen', + config: {} + }; + + var HelpConfig = { + name: 'help', + toolbar: 'help', + config: {} + }; + + var ImageConfig = { + name: 'image', + toolbar: 'image', + config: { + image_advtab: true, + image_description: true, + image_dimensions: true, + image_title: true, + image_caption: true, + } + }; + + var ImportcssConfig = { + name: 'importcss', + config: {} + }; + + var LinkConfig = { + name: 'link', + toolbar: 'link unlink', + config: {} + }; + + var ListsConfig = { + name: 'lists', + toolbar: 'numlist bullist', + config: {} + }; + + var MediaConfig = { + name: 'media', + toolbar: 'media', + config: {} + }; + + var NonbreakingConfig = { + name: 'nonbreaking', + toolbar: 'nonbreaking', + config: {} + }; + + var PagebreakConfig = { + name: 'pagebreak', + toolbar: 'pagebreak', + config: {} + }; + + var PreviewConfig = { + name: 'preview', + toolbar: 'preview', + config: {} + }; + + var QuickbarsConfig = { + name: 'quickbars', + config: { + quickbars_image_toolbar: 'alignleft aligncenter alignright', + quickbars_selection_toolbar: 'undo redo | copy cut paste | quicklink align', + quickbars_insert_toolbar: 'quickimage quicktable | hr pagebreak' + } + }; + + var SaveConfig = { + name: 'save', + toolbar: 'save cancel', + config: {} + }; + + var SearchreplaceConfig = { + name: 'searchreplace', + toolbar: 'searchreplace', + config: { + save_onsavecallback: function () { alert("Saved"); }, + save_oncancelcallback: function () { alert("Save Cancelled"); }, + } + }; + + var TableConfig = { + name: 'table', + toolbar: 'table', + config: {} + }; + + var VisualblocksConfig = { + name: 'visualblocks', + toolbar: 'visualblocks', + config: {} + }; + + var VisualcharsConfig = { + name: 'visualchars', + toolbar: 'visualchars', + config: {} + }; + + var WordcountConfig = { + name: 'wordcount', + config: {} + }; + + var A11ycheckerConfig = { + name: 'a11ychecker', + config: {}, + toolbar: 'a11ycheck' + }; + + var AdvcodeConfig = { + name: 'advcode', + config: { + advcode_inline: true + } + }; + + var AdvtableConfig = { + name: 'advtable', + config: {} + }; + + var AutocorrectConfig = { + name: 'autocorrect', + config: { + autocorrect_autocorrect: true, + autocorrect_capitalize: true, + } + }; + + var CasechangeConfig = { + name: 'casechange', + toolbar: 'casechange', + config: {} + }; + + var ChecklistConfig = { + name: 'checklist', + toolbar: 'checklist', + config: {} + }; + + var EditimageConfig2 = { + name: 'editimage', + toolbar: 'rotateleft rotateright flipv fliph editimage imageoptions', + config: { + editimage_toolbar: "rotateleft rotateright flipv fliph editimage imageoptions", + editimage_proxy_service_url: 'https://imageproxy.tiny.cloud', + } + }; + + var ExportpdfConfig = { + name: 'exportpdf', + toolbar: 'exportpdf', + config: { + exportpdf_service_url: "https://exportpdf.converter.tiny.cloud", + exportpdf_converter_options: { + header_html: '
Document Title
Date:
Page of
', + footer_html: '
Confidential
', + header_and_footer_css: 'div { color: blue; font-family: Arial, sans-serif; font-size: 10pt; }', + margin_top: '2cm', + margin_bottom: '2cm', + margin_left: '20mm', + margin_right: '20mm', + format: 'A4', + page_orientation: 'portrait', + }, + exportpdf_converter_style: 'body { color: black !important; font-family: Helvetica, Arial, sans-serif; } p { color: cyan !important; }', + } + }; + + var FootnotesConfig = { + name: 'footnotes', + toolbar: 'footnotes footnotesupdate', + config: {} + }; + + var FormatpainterConfig = { + name: 'formatpainter', + toolbar: 'formatpainter', + config: {} + }; + + var ImportwordConfig = { + name: 'importword', + toolbar: 'importword', + config: { + importword_service_url: "https://importdocx.converter.tiny.cloud", + importword_converter_options: { + formatting: { + styles: 'inline', + resets: 'inline', + defaults: 'inline', + } + } + } + }; + + var InlinecssConfig = { + name: 'inlinecss', + config: {} + }; + + var LinkcheckerConfig = { + name: 'linkchecker', + config: {} + }; + + var MarkdownConfig = { + name: 'markdown', + config: {} + }; + + var MathConfig = { + name: 'math', + toolbar: 'math', + config: {} + }; + + var MediaembedConfig = { + name: 'mediaembed', + config: {} + }; + + var PageembedConfig = { + name: 'pageembed', + toolbar: 'pageembed', + config: {} + }; + + var PermanentpenConfig = { + name: 'permanentpen', + toolbar: 'permanentpen', + config: { + permanentpen_properties: { + fontname: 'impact,sans-serif', + forecolor: '#E74C3C', + fontsize: '12px', + bold: true, + italic: false, + strikethrough: false, + underline: false + }, + } + }; + + var PowerpasteConfig = { + name: 'powerpaste', + config: {} + }; + + const revisions = [ + { + 'revisionId': '1', + 'createdAt': '2023-11-25T03:30:46.171Z', + 'content': '

Rev 1

' + }, + { + 'revisionId': '2', + 'createdAt': '2023-11-25T12:06:09.675Z', + 'content': '

Rev 2

' + }, + { + 'revisionId': '3', + 'createdAt': '2023-11-27T03:23:32.351Z', + 'content': '

Rev 3

' + }, + { + 'revisionId': '4', + 'createdAt': '2023-11-29T12:35:16.203Z', + 'content': '

Rev 4

' + }, + { + 'revisionId': '5', + 'createdAt': '2023-11-28T08:01:56.100Z', + 'content': '

Rev 5

' + } + ]; + + var RevisionhistoryConfig = { + toolbar: 'revisionhistory', + name: 'revisionhistory', + config: { + revisionhistory_fetch: () => Promise.resolve(revisions), + } + }; + + var TableofcontentsConfig = { + name: 'tableofcontents', + toolbar: 'tableofcontents', + config: {} + }; + + var TinymcespellcheckerConfig = { + name: 'tinymcespellchecker', + config: {} + }; + + var TypographyConfig = { + name: 'typography', + toolbar: 'typography', + config: {} + }; + + var UploadcareConfig = { + name: 'uploadcare', + toolbar: 'uploadcare', + config: { + uploadcare_public_key: '6ff5776be9bb64e10023', + } + }; + + const API_URL = 'https://demouserdirectory.tiny.cloud/v1/users'; + + const user_id = 'james-wilson'; + const basicConfig = { + height: 600, + mobile: { + theme: "silver", + contextmenu: "link image table preview", + }, + pad_empty_with_br: true, + help_accessibility: true, + // TODO: Target for tinymce 8 + user_id, + fetch_users: (userIds) => + Promise.all(userIds.map((userId) => fetch(`${API_URL}/${userId}`) + .then((response) => response.json()) + .catch(() => ({ id: userId })))), + + }; + + const pluginsConfig = [ + AccordionConfig, + CodeSampleConfig, + AdvlistConfig, + AnchorConfig, + AutolinkConfig, + AutosaveConfig, + CharmapConfig, + CodeConfig, + EditimageConfig, + DirectionalityConfig, + EmoticonsConfig, + FullscreenConfig, + HelpConfig, + ImageConfig, + ImportcssConfig, + InsertDatetimeConfig, + LinkConfig, + ListsConfig, + MediaConfig, + NonbreakingConfig, + PagebreakConfig, + PreviewConfig, + QuickbarsConfig, + SaveConfig, + SearchreplaceConfig, + TableConfig, + VisualblocksConfig, + VisualcharsConfig, + WordcountConfig, + A11ycheckerConfig, + AdvcodeConfig, + AdvtableConfig, + AdvtemplateConfig, + AutocorrectConfig, + CasechangeConfig, + ChecklistConfig, + EditimageConfig2, + ExportpdfConfig, + ExportWordConfig, + FootnotesConfig, + FormatpainterConfig, + ImportwordConfig, + InlinecssConfig, + LinkcheckerConfig, + MarkdownConfig, + MathConfig, + MediaembedConfig, + MentionsConfig, + MergetagsConfig, + PageembedConfig, + PermanentpenConfig, + PowerpasteConfig, + RevisionhistoryConfig, + SuggestedEditConfig, + TableofcontentsConfig, + TinyCommentsConfig, + TinymcespellcheckerConfig, + TypographyConfig, + UploadcareConfig, + TinymceaiConfig, + ]; + + const toolbarConfig = pluginsConfig.map((plugin) => plugin?.toolbar).filter(Boolean).join(' | '); + const generateConfig = ({ excludePlugins = [], overrideConfig = {} }) => { + const plugins = pluginsConfig.map((p) => p.name).filter((name) => !excludePlugins.includes(name)); + const extractedPluginsConfig = pluginsConfig.reduce((acc, cur) => { + return { ...acc, ...cur.config }; + }, {}); + const finalConfig = { + ...basicConfig, + ...extractedPluginsConfig, + ...overrideConfig + }; + + return { + ...finalConfig, + plugins: plugins, + toolbar: toolbarConfig, + height: 500 + }; + }; + + exports.generateConfig = generateConfig; + + return exports; + +})({}); diff --git a/src/demo/ts/Server.ts b/src/demo/ts/Server.ts index f249413..d883f5b 100644 --- a/src/demo/ts/Server.ts +++ b/src/demo/ts/Server.ts @@ -45,27 +45,7 @@ const page = (editor1Value: string, editor2Value: string, editor3Value: string,

TinyMCE WebComponent in Form

Editor 1 (outside form with form attribute)

- ${encodeHtmlEntities(editor1Value)} -

Editor 2 (nested in shadow dom, outside form with form attribute)

- -
-

Editor 3 (inside form)

- ${encodeHtmlEntities(editor3Value)} -

Editor 4 (nested in shadow dom, inside form)

- - -
- -

Posted Content

-

Editor 1 value

-
${editor1Value}
-

Editor 2 value

-
${editor2Value}
-

Editor 3 value

-
${editor3Value}
-

Editor 4 value

-
${editor4Value}
- + ${encodeHtmlEntities(editor1Value)} diff --git a/src/test/ts/alien/Utils.ts b/src/test/ts/alien/Utils.ts new file mode 100644 index 0000000..4f13bc4 --- /dev/null +++ b/src/test/ts/alien/Utils.ts @@ -0,0 +1,21 @@ +import { Attribute, Remove, SelectorFilter, SugarElement } from '@ephox/sugar'; +import { ScriptLoader } from 'src/main/ts/utils/ScriptLoader'; +import { Arr, Global, Strings } from '@ephox/katamari'; + + +export const deleteTinymce = () => { + ScriptLoader.reinitialize(); + + delete Global.tinymce; + delete Global.tinyMCE; + + const hasTinyUri = (attrName: string) => (elm: SugarElement) => + Attribute.getOpt(elm, attrName).exists((src) => Strings.contains(src, 'tinymce')); + + const elements = Arr.flatten([ + Arr.filter(SelectorFilter.all('script'), hasTinyUri('src')), + Arr.filter(SelectorFilter.all('link'), hasTinyUri('href')), + ]); + + Arr.each(elements, Remove.remove); +} \ No newline at end of file diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts new file mode 100644 index 0000000..81362ab --- /dev/null +++ b/src/test/ts/browser/DisabledTest.ts @@ -0,0 +1,120 @@ +import { Assertions } from '@ephox/agar'; +import { before, after, describe, it, context } from '@ephox/bedrock-client'; +import { Global } from '@ephox/katamari'; +import Editor from '../../../main/ts/component/Editor'; +import { VersionLoader } from "@tinymce/miniature"; +import { deleteTinymce } from '../alien/Utils'; + +type EditorElement = HTMLElement & { disabled: boolean }; + +describe('DisableTest', () => { + context('disabled option is not supported ( { + + }); + + context('disbaled option is supported', () => { + before(async () => { + await VersionLoader.pLoadVersion('8'); + Global.tinymce.baseURL = '/node_modules/tinymce'; + Global.tinymceTestConfig = { license_key: 'gpl' }; + if (!window.customElements.get('tinymce-editor')) { + Editor(); + } + }); + + after(() => { + document.querySelectorAll('tinymce-editor').forEach((el) => el.remove()); + deleteTinymce(); + }); + + let uid = 0; + const nextId = () => `_disabled_test_fn_${uid++}`; + + const pCreateEditor = ( + attrs: Record = {}, + onSetup?: (editor: any) => void + ): Promise<{ el: EditorElement; editor: any }> => + new Promise((resolve) => { + const setupFnName = nextId(); + const initFnName = nextId(); + let editorInstance: any; + + Global[setupFnName] = (editor: any) => { + editorInstance = editor; + onSetup?.(editor); + delete Global[setupFnName]; + }; + + Global[initFnName] = () => { + delete Global[initFnName]; + resolve({ el: el as EditorElement, editor: editorInstance }); + }; + + const el = document.createElement('tinymce-editor'); + el.setAttribute('config', 'tinymceTestConfig'); + el.setAttribute('setup', setupFnName); + el.setAttribute('on-init', initFnName); + for (const [ key, value ] of Object.entries(attrs)) { + el.setAttribute(key, value); + } + document.body.appendChild(el); + }); + + const removeEditors = () => { + document.querySelectorAll('tinymce-editor').forEach((el) => el.remove()); + }; + + const pWaitForDisabledChange = (editor: any): Promise => + new Promise((resolve) => editor.once('DisabledStateChange', resolve)); + + it('Editor initializes with disabled attribute — disabled option is true', async () => { + const { el, editor } = await pCreateEditor({ disabled: '' }); + Assertions.assertEq('Editor option should be disabled on init', true, editor.options.get('disabled')); + Assertions.assertEq('Element should have disabled attribute', true, el.hasAttribute('disabled')); + removeEditors(); + }); + + it('Editor initializes without disabled attribute — disabled option is false', async () => { + const { el, editor } = await pCreateEditor(); + Assertions.assertEq('Editor option should not be disabled on init', false, editor.options.get('disabled')); + Assertions.assertEq('Element should not have disabled attribute', false, el.hasAttribute('disabled')); + removeEditors(); + }); + + it('Setting disabled attribute after init disables the editor', async () => { + const { el, editor } = await pCreateEditor(); + Assertions.assertEq('Editor should not be disabled initially', false, editor.options.get('disabled')); + el.setAttribute('disabled', ''); + await pWaitForDisabledChange(editor); + Assertions.assertEq('Editor option should be disabled after setAttribute', true, editor.options.get('disabled')); + Assertions.assertEq('Element should have disabled attribute', true, el.hasAttribute('disabled')); + removeEditors(); + }); + + it('Removing disabled attribute after init enables the editor', async () => { + const { el, editor } = await pCreateEditor({ disabled: '' }); + Assertions.assertEq('Editor should be disabled initially', true, editor.options.get('disabled')); + el.removeAttribute('disabled'); + await pWaitForDisabledChange(editor); + Assertions.assertEq('Editor option should not be disabled after removeAttribute', false, editor.options.get('disabled')); + Assertions.assertEq('Element should not have disabled attribute', false, el.hasAttribute('disabled')); + removeEditors(); + }); + + it('Setting disabled property directly syncs editor option and attribute', async () => { + const { el, editor } = await pCreateEditor(); + Assertions.assertEq('disabled property should be false initially', false, el.disabled); + el.disabled = true; + await pWaitForDisabledChange(editor); + Assertions.assertEq('disabled property should be true', true, el.disabled); + Assertions.assertEq('disabled attribute should be present', true, el.hasAttribute('disabled')); + Assertions.assertEq('editor option should be true', true, editor.options.get('disabled')); + el.disabled = false; + await pWaitForDisabledChange(editor); + Assertions.assertEq('disabled property should be false', false, el.disabled); + Assertions.assertEq('disabled attribute should be absent', false, el.hasAttribute('disabled')); + Assertions.assertEq('editor option should be false', false, editor.options.get('disabled')); + removeEditors(); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index b9ef6bd..66ec3e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -617,7 +617,7 @@ dependencies: tslib "^2.4.0" -"@ephox/agar@^8.0.1": +"@ephox/agar@^8.0.0", "@ephox/agar@^8.0.1": version "8.0.1" resolved "https://registry.yarnpkg.com/@ephox/agar/-/agar-8.0.1.tgz#6772ed7abd90adee5b08bc6f8baf0cb4f22b8d1c" integrity sha512-2LR/u0oos9GadRoLFDVE6NRDV8Tl9+DYQyouVYn0+7afAYdouyw+nXaoTVG5nnvMG+ofsmldKOC82nJWu0a4kQ== @@ -736,6 +736,17 @@ dependencies: "@ephox/dispute" "^1.0.3" +"@ephox/mcagar@^9.0.0": + version "9.0.1" + resolved "https://registry.yarnpkg.com/@ephox/mcagar/-/mcagar-9.0.1.tgz#d740d02628063e8df86ca8cdd8aa307654b1c69b" + integrity sha512-iNMP8mkz8AtgiRceU4TAnstQje3RG8yxM/QoWKkriCeh6n5fe1sSfexFRVW3fwZ0bUrjTlyawSqoH0yhESqJjQ== + dependencies: + "@ephox/agar" "^8.0.1" + "@ephox/katamari" "^9.1.6" + "@ephox/sand" "^6.0.10" + "@ephox/sugar" "^9.3.1" + fast-check "^2.0.0" + "@ephox/sand@^6.0.10": version "6.0.10" resolved "https://registry.yarnpkg.com/@ephox/sand/-/sand-6.0.10.tgz#1bd3e03ce339ab282fa3ac03591badc13f7d69b1" @@ -743,7 +754,7 @@ dependencies: "@ephox/katamari" "^9.1.6" -"@ephox/sugar@^9.2.1", "@ephox/sugar@^9.3.1": +"@ephox/sugar@^9.2.1", "@ephox/sugar@^9.3.0", "@ephox/sugar@^9.3.1": version "9.3.1" resolved "https://registry.yarnpkg.com/@ephox/sugar/-/sugar-9.3.1.tgz#082dbe885d41e657eff7ef6275d648f3dff88334" integrity sha512-NQMqDN0zC+IZGuhBuz/7RxncfJsmTBhCHgaqkHOJ5d1E0CIL9afIizBYQ0JSHS3osAb9woGGtwPobjCx3/Srpw== @@ -1832,6 +1843,16 @@ typescript "^5.7.2" typescript-eslint "^8.26.1" +"@tinymce/miniature@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@tinymce/miniature/-/miniature-6.0.0.tgz#d11ca91292fa614926faf399166898874baedd92" + integrity sha512-bLpaTTgbyMHP3V8bucSxvCTVTUjRRk05zDgnlD5Hj2eo6hEyHT1FCqpuhdVLHx9mbCydrlAIhhsY8Ex6Hp8Qqg== + dependencies: + "@ephox/agar" "^8.0.0" + "@ephox/katamari" "^9.1.5" + "@ephox/mcagar" "^9.0.0" + "@ephox/sugar" "^9.3.0" + "@tootallnate/quickjs-emscripten@^0.23.0": version "0.23.0" resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c" @@ -8248,10 +8269,15 @@ thunky@^1.0.2: resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== -tinymce@^8.0.0: - version "8.1.2" - resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-8.1.2.tgz#0598f3703a2977533196161f5bce5256d6872da0" - integrity sha512-KITxHEEHRlxC5xOnxA123eAJ67NgsWxNphtItWt9TRu07DiTZrWIqJeIKRX9euE51/l3kJO4WQiqoBXKTJJGsA== +"tinymce-8@npm:tinymce@^8": + version "8.3.2" + resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-8.3.2.tgz#bfdba186b00d61598eafbc29cab778de7f8e1e33" + integrity sha512-iZ8aIUtrgGOw2AkukNf8spUM0LOzNLoCHRepwXQwWmHxP2TI5LzHjjG0SmXGxbya4EmoD5/pAox0ZXJfLO5DUw== + +tinymce@^8: + version "8.3.2" + resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-8.3.2.tgz#bfdba186b00d61598eafbc29cab778de7f8e1e33" + integrity sha512-iZ8aIUtrgGOw2AkukNf8spUM0LOzNLoCHRepwXQwWmHxP2TI5LzHjjG0SmXGxbya4EmoD5/pAox0ZXJfLO5DUw== tinyrainbow@^1.2.0: version "1.2.0" From ccda14fb5ac950b95d210ddf767313db08679bbc Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Thu, 26 Mar 2026 15:08:35 +1030 Subject: [PATCH 04/29] Update test --- src/test/ts/browser/DisabledTest.ts | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index 81362ab..ef3e74d 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -1,5 +1,5 @@ import { Assertions } from '@ephox/agar'; -import { before, after, describe, it, context } from '@ephox/bedrock-client'; +import { before, after, describe, it, context, afterEach } from '@ephox/bedrock-client'; import { Global } from '@ephox/katamari'; import Editor from '../../../main/ts/component/Editor'; import { VersionLoader } from "@tinymce/miniature"; @@ -27,6 +27,10 @@ describe('DisableTest', () => { deleteTinymce(); }); + afterEach(() => { + document.querySelectorAll('tinymce-editor').forEach((el) => el.remove()); + }); + let uid = 0; const nextId = () => `_disabled_test_fn_${uid++}`; @@ -40,9 +44,9 @@ describe('DisableTest', () => { let editorInstance: any; Global[setupFnName] = (editor: any) => { + delete Global[setupFnName]; editorInstance = editor; onSetup?.(editor); - delete Global[setupFnName]; }; Global[initFnName] = () => { @@ -60,10 +64,6 @@ describe('DisableTest', () => { document.body.appendChild(el); }); - const removeEditors = () => { - document.querySelectorAll('tinymce-editor').forEach((el) => el.remove()); - }; - const pWaitForDisabledChange = (editor: any): Promise => new Promise((resolve) => editor.once('DisabledStateChange', resolve)); @@ -71,14 +71,12 @@ describe('DisableTest', () => { const { el, editor } = await pCreateEditor({ disabled: '' }); Assertions.assertEq('Editor option should be disabled on init', true, editor.options.get('disabled')); Assertions.assertEq('Element should have disabled attribute', true, el.hasAttribute('disabled')); - removeEditors(); }); it('Editor initializes without disabled attribute — disabled option is false', async () => { const { el, editor } = await pCreateEditor(); Assertions.assertEq('Editor option should not be disabled on init', false, editor.options.get('disabled')); Assertions.assertEq('Element should not have disabled attribute', false, el.hasAttribute('disabled')); - removeEditors(); }); it('Setting disabled attribute after init disables the editor', async () => { @@ -88,7 +86,6 @@ describe('DisableTest', () => { await pWaitForDisabledChange(editor); Assertions.assertEq('Editor option should be disabled after setAttribute', true, editor.options.get('disabled')); Assertions.assertEq('Element should have disabled attribute', true, el.hasAttribute('disabled')); - removeEditors(); }); it('Removing disabled attribute after init enables the editor', async () => { @@ -98,7 +95,6 @@ describe('DisableTest', () => { await pWaitForDisabledChange(editor); Assertions.assertEq('Editor option should not be disabled after removeAttribute', false, editor.options.get('disabled')); Assertions.assertEq('Element should not have disabled attribute', false, el.hasAttribute('disabled')); - removeEditors(); }); it('Setting disabled property directly syncs editor option and attribute', async () => { @@ -114,7 +110,6 @@ describe('DisableTest', () => { Assertions.assertEq('disabled property should be false', false, el.disabled); Assertions.assertEq('disabled attribute should be absent', false, el.hasAttribute('disabled')); Assertions.assertEq('editor option should be false', false, editor.options.get('disabled')); - removeEditors(); }); }); }); From 623bc3773e36c0ae951a6b8e8258a97f32a37722 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Wed, 1 Apr 2026 13:34:14 +1030 Subject: [PATCH 05/29] Add more tests --- package.json | 1 + src/test/ts/browser/DisabledTest.ts | 144 +++++++++++++++------------- yarn.lock | 5 + 3 files changed, 82 insertions(+), 68 deletions(-) diff --git a/package.json b/package.json index 2ff2789..1a3e343 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "webpack": "^5.75.0" }, "dependencies": { + "tinymce-7.5.0": "npm:tinymce@7.5.0", "tinymce-8": "npm:tinymce@^8" } } diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index ef3e74d..a984980 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -1,115 +1,123 @@ import { Assertions } from '@ephox/agar'; -import { before, after, describe, it, context, afterEach } from '@ephox/bedrock-client'; +import { before, describe, it, context, after, beforeEach, afterEach } from '@ephox/bedrock-client'; import { Global } from '@ephox/katamari'; import Editor from '../../../main/ts/component/Editor'; import { VersionLoader } from "@tinymce/miniature"; import { deleteTinymce } from '../alien/Utils'; +import type { Editor as TinyMCEEditor } from 'tinymce'; type EditorElement = HTMLElement & { disabled: boolean }; describe('DisableTest', () => { - context('disabled option is not supported ( { - - }); + let uid = 0; + const nextId = () => `_disabled_test_fn_${uid++}`; - context('disbaled option is supported', () => { + const setupVersionContext = (version: string) => { before(async () => { - await VersionLoader.pLoadVersion('8'); - Global.tinymce.baseURL = '/node_modules/tinymce'; + await VersionLoader.pLoadVersion(version); Global.tinymceTestConfig = { license_key: 'gpl' }; - if (!window.customElements.get('tinymce-editor')) { - Editor(); - } }); after(() => { - document.querySelectorAll('tinymce-editor').forEach((el) => el.remove()); + delete Global.tinymceTestConfig; deleteTinymce(); }); + + beforeEach(() => { + if (!window.customElements.get('tinymce-editor')) { + Editor(); + } + }); afterEach(() => { document.querySelectorAll('tinymce-editor').forEach((el) => el.remove()); }); + } + + const pCreateEditor = + (attrs: Record = {}, onSetup?: (editor: any) => void): Promise<{ el: EditorElement; editor: TinyMCEEditor }> => new Promise((resolve) => { + const setupFnName = nextId(); + const initFnName = nextId(); + let editorInstance: any; + + Global[setupFnName] = (editor: any) => { + delete Global[setupFnName]; + editorInstance = editor; + onSetup?.(editor); + }; + + Global[initFnName] = () => { + delete Global[initFnName]; + resolve({ el: el as EditorElement, editor: editorInstance }); + }; + + const el = document.createElement('tinymce-editor'); + el.setAttribute('config', 'tinymceTestConfig'); + el.setAttribute('setup', setupFnName); + el.setAttribute('on-init', initFnName); + for (const [ key, value ] of Object.entries(attrs)) { + el.setAttribute(key, value); + } + + document.body.appendChild(el); + }); + + context('When using with Tinymce < 7.6', () => { + setupVersionContext('7.5.0'); + + it('Editor should be not be disabled when disabled attribute is present', async () => { + const { editor } = await pCreateEditor({ disabled: '' }); + Assertions.assertEq('Editor should be in design mode', true, editor.mode.get() === 'design'); + }); + }); - let uid = 0; - const nextId = () => `_disabled_test_fn_${uid++}`; - - const pCreateEditor = ( - attrs: Record = {}, - onSetup?: (editor: any) => void - ): Promise<{ el: EditorElement; editor: any }> => - new Promise((resolve) => { - const setupFnName = nextId(); - const initFnName = nextId(); - let editorInstance: any; - - Global[setupFnName] = (editor: any) => { - delete Global[setupFnName]; - editorInstance = editor; - onSetup?.(editor); - }; - - Global[initFnName] = () => { - delete Global[initFnName]; - resolve({ el: el as EditorElement, editor: editorInstance }); - }; - - const el = document.createElement('tinymce-editor'); - el.setAttribute('config', 'tinymceTestConfig'); - el.setAttribute('setup', setupFnName); - el.setAttribute('on-init', initFnName); - for (const [ key, value ] of Object.entries(attrs)) { - el.setAttribute(key, value); - } - document.body.appendChild(el); - }); - - const pWaitForDisabledChange = (editor: any): Promise => + context('When using with Tinymce >= 7.6', () => { + setupVersionContext('8'); + + const pWaitForDisabledStateChange = (editor: any): Promise => new Promise((resolve) => editor.once('DisabledStateChange', resolve)); - it('Editor initializes with disabled attribute — disabled option is true', async () => { + const assertDisabledState = (el: EditorElement, editor: TinyMCEEditor, expected: boolean) => { + const hasDisabledAtt = el.hasAttribute('disabled'); + Assertions.assertEq('Editor should be disabled', expected, editor.options.get('disabled')); + Assertions.assertEq(`disabled attribute should be ${expected ? 'present' : 'absent'}`, expected, hasDisabledAtt); + } + + it('Editor should be disabled when disabled attribute is present', async () => { const { el, editor } = await pCreateEditor({ disabled: '' }); - Assertions.assertEq('Editor option should be disabled on init', true, editor.options.get('disabled')); - Assertions.assertEq('Element should have disabled attribute', true, el.hasAttribute('disabled')); + assertDisabledState(el, editor, true); }); - it('Editor initializes without disabled attribute — disabled option is false', async () => { + it('Editor is not disabled when disabled attribute is absent', async () => { const { el, editor } = await pCreateEditor(); - Assertions.assertEq('Editor option should not be disabled on init', false, editor.options.get('disabled')); - Assertions.assertEq('Element should not have disabled attribute', false, el.hasAttribute('disabled')); + assertDisabledState(el, editor, false); }); it('Setting disabled attribute after init disables the editor', async () => { const { el, editor } = await pCreateEditor(); - Assertions.assertEq('Editor should not be disabled initially', false, editor.options.get('disabled')); + assertDisabledState(el, editor, false); el.setAttribute('disabled', ''); - await pWaitForDisabledChange(editor); - Assertions.assertEq('Editor option should be disabled after setAttribute', true, editor.options.get('disabled')); - Assertions.assertEq('Element should have disabled attribute', true, el.hasAttribute('disabled')); + await pWaitForDisabledStateChange(editor); + assertDisabledState(el, editor, true); }); it('Removing disabled attribute after init enables the editor', async () => { const { el, editor } = await pCreateEditor({ disabled: '' }); - Assertions.assertEq('Editor should be disabled initially', true, editor.options.get('disabled')); + assertDisabledState(el, editor, true); el.removeAttribute('disabled'); - await pWaitForDisabledChange(editor); - Assertions.assertEq('Editor option should not be disabled after removeAttribute', false, editor.options.get('disabled')); - Assertions.assertEq('Element should not have disabled attribute', false, el.hasAttribute('disabled')); + await pWaitForDisabledStateChange(editor); + assertDisabledState(el, editor, false); }); - it('Setting disabled property directly syncs editor option and attribute', async () => { + it('Updating disabled property directly syncs editor option and attribute', async () => { const { el, editor } = await pCreateEditor(); Assertions.assertEq('disabled property should be false initially', false, el.disabled); el.disabled = true; - await pWaitForDisabledChange(editor); - Assertions.assertEq('disabled property should be true', true, el.disabled); - Assertions.assertEq('disabled attribute should be present', true, el.hasAttribute('disabled')); - Assertions.assertEq('editor option should be true', true, editor.options.get('disabled')); + await pWaitForDisabledStateChange(editor); + assertDisabledState(el, editor, true); el.disabled = false; - await pWaitForDisabledChange(editor); - Assertions.assertEq('disabled property should be false', false, el.disabled); - Assertions.assertEq('disabled attribute should be absent', false, el.hasAttribute('disabled')); - Assertions.assertEq('editor option should be false', false, editor.options.get('disabled')); + await pWaitForDisabledStateChange(editor); + assertDisabledState(el, editor, false); }); }); }); diff --git a/yarn.lock b/yarn.lock index 66ec3e7..f380e74 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8269,6 +8269,11 @@ thunky@^1.0.2: resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== +"tinymce-7.5.0@npm:tinymce@7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-7.5.0.tgz#56388d314399c288a100df4aaf468153f29477f1" + integrity sha512-A7iuQPIfeze5rO6bvnnPwP7TiWnPA9AGr8U/9ssLwrEG+FMYPzvLPt3RT8ktVn/wPSJkVBBSLCAZX2dAHb8YEA== + "tinymce-8@npm:tinymce@^8": version "8.3.2" resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-8.3.2.tgz#bfdba186b00d61598eafbc29cab778de7f8e1e33" From 313577f60c92d803a65700f58824c40d6576c8cb Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Wed, 1 Apr 2026 13:46:24 +1030 Subject: [PATCH 06/29] Update changelog --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c70ce7..3e8b6e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## Changed + +- Moved `@tinymce/miniature` to devDependency. #INT-3358 + ## 2.3.2 - 2025-12-18 ### Fixed @@ -25,7 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 2.2.0 - 2025-05-29 ### Added -- New `readonly` attribute that can be used to toggle the editor's `readonly` mode. #TINY-11911 +- New `disabled` attribute that can be used to toggle the editor's `disabled` option. #INT-11911 ## 2.1.0 - 2024-01-08 From 47f9413e9edf19753aecb0bf740fe669f21ac3ce Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Wed, 1 Apr 2026 13:51:43 +1030 Subject: [PATCH 07/29] Correct ticket number in the changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e8b6e3..7c8db79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 2.2.0 - 2025-05-29 ### Added -- New `disabled` attribute that can be used to toggle the editor's `disabled` option. #INT-11911 +- New `disabled` attribute that can be used to toggle the editor's `disabled` option. #TINY-11911 ## 2.1.0 - 2024-01-08 From 02ce3c55068a35edb3d2be09813c0debb600e6be Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Wed, 1 Apr 2026 13:54:22 +1030 Subject: [PATCH 08/29] Fix lining errors --- src/demo/ts/Server.ts | 22 +++++++++++++++++++++- src/test/ts/alien/Utils.ts | 3 +-- src/test/ts/browser/DisabledTest.ts | 14 +++++++------- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/demo/ts/Server.ts b/src/demo/ts/Server.ts index d883f5b..f249413 100644 --- a/src/demo/ts/Server.ts +++ b/src/demo/ts/Server.ts @@ -45,7 +45,27 @@ const page = (editor1Value: string, editor2Value: string, editor3Value: string,

TinyMCE WebComponent in Form

Editor 1 (outside form with form attribute)

- ${encodeHtmlEntities(editor1Value)} + ${encodeHtmlEntities(editor1Value)} +

Editor 2 (nested in shadow dom, outside form with form attribute)

+ +
+

Editor 3 (inside form)

+ ${encodeHtmlEntities(editor3Value)} +

Editor 4 (nested in shadow dom, inside form)

+ + +
+ +

Posted Content

+

Editor 1 value

+
${editor1Value}
+

Editor 2 value

+
${editor2Value}
+

Editor 3 value

+
${editor3Value}
+

Editor 4 value

+
${editor4Value}
+ diff --git a/src/test/ts/alien/Utils.ts b/src/test/ts/alien/Utils.ts index 4f13bc4..02c67f1 100644 --- a/src/test/ts/alien/Utils.ts +++ b/src/test/ts/alien/Utils.ts @@ -2,7 +2,6 @@ import { Attribute, Remove, SelectorFilter, SugarElement } from '@ephox/sugar'; import { ScriptLoader } from 'src/main/ts/utils/ScriptLoader'; import { Arr, Global, Strings } from '@ephox/katamari'; - export const deleteTinymce = () => { ScriptLoader.reinitialize(); @@ -18,4 +17,4 @@ export const deleteTinymce = () => { ]); Arr.each(elements, Remove.remove); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index a984980..b046b30 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -2,7 +2,7 @@ import { Assertions } from '@ephox/agar'; import { before, describe, it, context, after, beforeEach, afterEach } from '@ephox/bedrock-client'; import { Global } from '@ephox/katamari'; import Editor from '../../../main/ts/component/Editor'; -import { VersionLoader } from "@tinymce/miniature"; +import { VersionLoader } from '@tinymce/miniature'; import { deleteTinymce } from '../alien/Utils'; import type { Editor as TinyMCEEditor } from 'tinymce'; @@ -22,7 +22,7 @@ describe('DisableTest', () => { delete Global.tinymceTestConfig; deleteTinymce(); }); - + beforeEach(() => { if (!window.customElements.get('tinymce-editor')) { Editor(); @@ -32,9 +32,9 @@ describe('DisableTest', () => { afterEach(() => { document.querySelectorAll('tinymce-editor').forEach((el) => el.remove()); }); - } + }; - const pCreateEditor = + const pCreateEditor = (attrs: Record = {}, onSetup?: (editor: any) => void): Promise<{ el: EditorElement; editor: TinyMCEEditor }> => new Promise((resolve) => { const setupFnName = nextId(); const initFnName = nextId(); @@ -60,8 +60,8 @@ describe('DisableTest', () => { } document.body.appendChild(el); - }); - + }); + context('When using with Tinymce < 7.6', () => { setupVersionContext('7.5.0'); @@ -81,7 +81,7 @@ describe('DisableTest', () => { const hasDisabledAtt = el.hasAttribute('disabled'); Assertions.assertEq('Editor should be disabled', expected, editor.options.get('disabled')); Assertions.assertEq(`disabled attribute should be ${expected ? 'present' : 'absent'}`, expected, hasDisabledAtt); - } + }; it('Editor should be disabled when disabled attribute is present', async () => { const { el, editor } = await pCreateEditor({ disabled: '' }); From 06ce570ebd2dfaf0614ac4c5a55ad6d408d93785 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Tue, 7 Apr 2026 08:50:31 +0930 Subject: [PATCH 09/29] Remove the accidentally added file --- src/demo/js/configs/full-config.js | 1516 --------------------------- src/test/ts/browser/DisabledTest.ts | 190 ++-- 2 files changed, 116 insertions(+), 1590 deletions(-) delete mode 100644 src/demo/js/configs/full-config.js diff --git a/src/demo/js/configs/full-config.js b/src/demo/js/configs/full-config.js deleted file mode 100644 index 106f971..0000000 --- a/src/demo/js/configs/full-config.js +++ /dev/null @@ -1,1516 +0,0 @@ -var fullConfig = (function (exports) { - 'use strict'; - - const JWT_SERVER_URL = 'https://tinymce-ai-jwt.onrender.com'; - - var TinymceaiConfig = { - config: { - // tinymceai_api_url: 'https://tinymceai.api.staging.tiny.cloud/', - - // REQUIRED: tinymceai_service_url — Base URL of the AI backend service - // tinymceai_service_url: 'https://tinymceai.api.staging.tiny.cloud/', - // tinymceai_service_url: 'https://tinymceai.api.dev.tiny.cloud/', - tinymceai_token_provider: () => { - return fetch(`${JWT_SERVER_URL}/jwt`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }).then(r => r.json()); - }, - - - // content_id — Groups conversations by document - content_id: 'render_doc_1', - - // tinymceai_sidebar_type — 'static' | 'floating' (default: 'static') - tinymceai_sidebar_type: 'static', - - // Model configuration - // Available Models: auto (agent-1), gpt-5.2, gpt-5.1, gpt-5, gpt-5-mini, - // claude-4-5-haiku, claude-4-5-sonnet, gemini-3-pro, gemini-3-flash, - // gemini-2-5-flash, gpt-4.1, gpt-4.1-mini - - // tinymceai_default_model — Model ID to select by default - tinymceai_default_model: 'auto', - - // tinymceai_allow_model_selection — Show model selection dropdown (default: true) - tinymceai_allow_model_selection: true, - - // tinymceai_quickactions_menu — Items in the Quick Actions menu - // Correct control IDs: ai-quickactions-chat-prompts, ai-quickactions-improve-writing, - // ai-quickactions-continue-writing, ai-quickactions-check-grammar, - // ai-quickactions-change-length, ai-quickactions-change-tone, - // ai-quickactions-translate, ai-quickactions-custom - tinymceai_quickactions_menu: [ - 'ai-quickactions-chat-prompts', - 'ai-quickactions-improve-writing', - 'ai-quickactions-continue-writing', - 'ai-quickactions-check-grammar', - 'ai-quickactions-change-length', - 'ai-quickactions-change-tone', - 'ai-quickactions-translate', - 'ai-quickactions-custom' - ], - - // tinymceai_quickactions_chat_prompts — Items in the "Chat commands" sub-menu - // Correct control IDs: ai-chat-explain, ai-chat-summarize, ai-chat-highlight-key-points - tinymceai_quickactions_chat_prompts: [ - 'ai-chat-explain', - 'ai-chat-summarize', - 'ai-chat-highlight-key-points' - ], - - // tinymceai_quickactions_change_tone_menu — Items in the "Change tone" sub-menu - // Correct control IDs: ai-quickactions-tone-casual, ai-quickactions-tone-direct, - // ai-quickactions-tone-friendly, ai-quickactions-tone-confident, ai-quickactions-tone-professional - tinymceai_quickactions_change_tone_menu: [ - 'ai-quickactions-tone-casual', - 'ai-quickactions-tone-direct', - 'ai-quickactions-tone-friendly', - 'ai-quickactions-tone-confident', - 'ai-quickactions-tone-professional' - ], - - // tinymceai_languages — Languages in the "Translate" sub-menu - // Each item: { title: string, language: string } - tinymceai_languages: [ - { title: 'English', language: 'english' }, - { title: 'Chinese (Simplified)', language: 'chinese' }, - { title: 'Spanish', language: 'spanish' }, - { title: 'German', language: 'german' }, - { title: 'Japanese', language: 'japanese' }, - { title: 'Portuguese', language: 'portuguese' }, - { title: 'Korean', language: 'korean' }, - { title: 'Italian', language: 'italian' }, - { title: 'Russian', language: 'russian' }, - { title: 'French', language: 'french' } - ], - - // tinymceai_quickactions_custom — Custom commands in the "Other" sub-menu - // Chat type: { type: 'chat', title: string, prompt: string } - // Action type: { type: 'action', title: string, prompt: string, model: string } - tinymceai_quickactions_custom: [ - { - type: 'chat', - title: 'Generate Outline', - prompt: 'Create a detailed outline for the selected content' - }, - { - type: 'action', - title: 'Convert to Table', - prompt: 'Convert this data into an HTML table', - model: 'gpt-4.1' - }, - { - type: 'chat', - title: 'Explain Like I\'m 5', - prompt: 'Explain the selected content as if I am a 5 year old child' - } - ], - - // tinymceai_chat_welcome_message — Custom HTML welcome message in chat sidebar - tinymceai_chat_welcome_message: '

Welcome to AI Chat!

I can help you write, edit, review, and brainstorm. Ask me anything or use the quick actions above.

', - - // tinymceai_chat_fetch_sources — Provides a list of external sources users can attach - // Returns Promise - tinymceai_chat_fetch_sources: () => { - console.log('[tinymceai] tinymceai_chat_fetch_sources called'); - return Promise.resolve([ - { - label: 'Sample Documents', - icon: 'document-properties', - sources: [ - { label: 'Company Guidelines', id: 'doc-guidelines', type: 'web-resource' }, - { label: 'Product Roadmap', id: 'doc-roadmap', type: 'file' }, - { label: 'FAQ Document', id: 'doc-faq', type: 'web-resource' } - ] - } - ]); - }, - - // tinymceai_chat_fetch_source — Fetches a specific external source by ID - // Returns Promise — { type: 'file', file: File } or { type: 'web-resource', url: string } - tinymceai_chat_fetch_source: (id) => { - console.log('[tinymceai] tinymceai_chat_fetch_source called with id:', id); - if (id === 'doc-guidelines') { - return Promise.resolve({ type: 'web-resource', url: 'https://www.tiny.cloud' }); - } else if (id === 'doc-roadmap') { - const blob = new Blob(['Sample roadmap content for testing'], { type: 'text/plain' }); - const file = new File([blob], 'roadmap.txt', { type: 'text/plain' }); - return Promise.resolve({ type: 'file', file: file }); - } else { - return Promise.resolve({ type: 'web-resource', url: 'https://www.tiny.cloud/docs' }); - } - }, - }, - toolbar: 'tinymceai-chat tinymceai-review tinymceai-quickactions', - name: 'tinymceai', - }; - - const advtemplate_templates = [ - { - id: '1', - title: 'Quick replies', - items: [ - { - id: '2', - title: 'Message received', - content: '

Hey {{Customer.FirstName}}!

\n

Just a quick note to say we’ve received your message, and will get back to you within 48 hours.

\n

For reference, your ticket number is: {{Ticket.Number}}

\n

Should you have any questions in the meantime, just reply to this email and it will be attached to this ticket.

\n

 

\n

Regards,

\n

{{Agent.FirstName}}

' - }, - { - id: '3', - title: 'Thanks for the feedback', - content: '

Hi {{Customer.FirstName}},

\n

We appreciate you taking the time to provide feedback on {{Product.Name}}.

\n

It sounds like it wasn’t able to fully meet your expectations, for which we apologize. Rest assured our team looks at each piece of feedback and uses it to decide what to focus on next with {{Product.Name}}.

\n

 

\n

All the best, and let us know if there’s anything else we can do to help.

\n

-{{Agent.FirstName}}

' - }, - { - id: '6', - title: 'Still working on case', - content: '

\n

 

\n

Hi {{Customer.FirstName}},

\n

Just a quick note to let you know we’re still working on your case. It’s taking a bit longer than we hoped, but we’re aiming to get you an answer in the next 48 hours.

\n

Stay tuned,

\n

{{Agent.FirstName}}

' - } - ] - }, - { - id: '4', - title: 'Closing tickets', - items: [ - { - id: '7', - title: 'Closing ticket', - content: '

Hi {{Customer.FirstName}},

\n

We haven’t heard back from you in over a week, so we have gone ahead and closed your ticket number {{Ticket.Number}}.

\n

If you’re still running into issues, not to worry, just reply to this email and we will re-open your ticket.

\n

 

\n

All the best,

\n

{{Agent.FirstName}}

' - }, - { - id: '8', - title: 'Post-call survey', - content: '

Hey {{Customer.FirstName}}!

\n

 

\n

How did we do?

\n

If you have a few moments, we’d love you to fill out our post-support survey: {{Survey.Link}}

\n

 

\n

Thanks in advance!
{{Company.Name}} Customer Support

' - } - ] - }, - { - id: '5', - title: 'Product support', - items: [ - { - id: '9', - title: 'How to find model number', - content: '

Hi {{Customer.FirstName}},

\n

 

\n

My name is {{Agent.FirstName}} and I will be glad to assist you today.

\n

To troubleshoot your issue, we first need your model number, which can be found on the underside of your product beneath the safety warning label. 

\n

It should look something like the following: XX.XXXXX.X

\n

Once you send it over, I will advise on next steps.

\n

 

\n

Thanks!

\n

{{Agent.FirstName}}

' - }, - { - id: '10', - title: 'Support escalation', - content: '

\n

 

\n

Hi {{Customer.FirstName}},

\n

We have escalated your ticket {{Ticket.Number}} to second-level support.

\n

You should hear back from the new agent on your case, {{NewAgent.FirstName}}, shortly.

\n

 

\n

Thanks,

\n

{{Company.Name}} Customer Support

' - } - ] - }, - { - id: '6', - title: 'Email Signatures', - items: [ - { - id: '11', - title: 'Tiny Signature', - content: '

Regards


Tiny Technologies Inc

Shiridi Gandham
QA Template Manager

Email: shiridi.gandham@tiny.cloud
Phone: (+617) 3161 3557

Tiny Technologies
www.tiny.cloud

Linkedin Facebook Twitter GitHub Stack Overflow

' - } - ] - } - ]; - - var AdvtemplateConfig = { - toolbar: 'addtemplate inserttemplate', - name: 'advtemplate', - config: { - advtemplate_templates - } - }; - - var AccordionConfig = { - name: 'accordion', - toolbar: 'accordion', - config: {} - }; - - const mergetags_list = [ - { - value: 'Current.Date', - title: 'Current date in DD/MM/YYYY format' - }, - { - value: 'Campaign.Toc', - title: 'Linked table of contents in your campaign' - }, - { - title: 'Phone', - menu: [ - { - value: 'Phone.Home' - }, - { - value: 'Phone.work' - } - ] - }, - { - title: 'Person', - menu: [ - { - value: 'Person.Name' - }, - { - value: 'Person.Name.First' - }, - { - value: 'Person.Name.Last' - }, - { - value: 'Person.Name.Full' - }, - { - title: 'Email', - menu: [ - { - value: 'Person.Email.Work' - }, - { - value: 'Person.Email.Home' - } - ] - } - ] - } - ]; - - var MergetagsConfig = { - toolbar: 'mergetags', - name: 'mergetags', - config: { - mergetags_prefix: '${', - mergetags_suffix: '}', - mergetags_list, - } - }; - - const API_URL$1 = 'https://demouserdirectory.tiny.cloud/v1/users'; - - const mentions_fetch = async (query, success) => { - const searchPhrase = query.term.toLowerCase(); - await fetch(`${API_URL$1}?q=${encodeURIComponent(searchPhrase)}`) - .then((response) => response.json()) - .then((users) => success(users.data.map((userInfo) => ({ - id: userInfo.id, - name: userInfo.name, - image: userInfo.avatar, - description: userInfo.custom.role - })))) - .catch((error) => console.log(error)); - }; - - const mentions_menu_complete = (editor, userInfo) => { - const span = editor.getDoc().createElement('span'); - span.className = 'mymention'; - span.setAttribute('data-mention-id', userInfo.id); - span.appendChild(editor.getDoc().createTextNode('@' + userInfo.name)); - return span; - }; - - const createCard = (userInfo) => { - const div = document.createElement('div'); - div.innerHTML = ( - '
' + - '' + - '

' + userInfo.name + '

' + - '

' + userInfo.description + '

' + - '
' - ); - return div; - }; - - const mentions_menu_hover = async (userInfo, success) => { - const card = createCard(userInfo); - success(card); - }; - - const mentions_select = async (mention, success) => { - const id = mention.getAttribute('data-mention-id'); - await fetch(`${API_URL$1}/${id}`) - .then((response) => response.json()) - .then((userInfo) => { - const card = createCard({ - id: userInfo.id, - name: userInfo.name, - image: userInfo.avatar, - description: userInfo.custom.role - }); - success(card); - }) - .catch((error) => console.error(error)); - }; - - var MentionsConfig = { - toolbar: 'mentions', - name: 'mentions', - config: { - mentions_fetch, - mentions_menu_complete, - mentions_menu_hover, - mentions_select, - mentions_selector: '.mymention', - mentions_item_type: 'profile', - mentions_min_chars: 0, - } - }; - - const user_id$1 = 'james-wilson'; - - const tinycomments_create = (req, done, fail) => { - if (req.content === 'fail') { - fail(new Error('Something has gone wrong...')); - } else { - const uid = 'annotation-' + randomString(); - conversationDb[uid] = { - uid, - comments: [{ - uid, - author: user_id$1, - authorName: 'James Wilson', - authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg', - content: req.content, - createdAt: req.createdAt, - modifiedAt: req.createdAt - }] - }; - setTimeout(() => done({ conversationUid: uid }), fakeDelay); - } - }; - - const fakeDelay = 200; - - const randomString = () => { - return crypto.getRandomValues(new Uint32Array(1))[0].toString(36).substring(2, 14); - }; - - - const conversationDb = {}; - - const tinycomments_reply = (req, done) => { - const replyUid = 'annotation-' + randomString(); - conversationDb[req.conversationUid].comments.push({ - uid: replyUid, - author: user_id$1, - authorName: 'James Wilson', - authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg', - content: req.content, - createdAt: req.createdAt, - modifiedAt: req.createdAt - }); - setTimeout(() => done({ commentUid: replyUid }), fakeDelay); - }; - - const tinycomments_delete = (req, done) => { - { - setTimeout(() => done({ canDelete: false, reason: 'Must be admin user' }), fakeDelay); - } - }; - - const tinycomments_resolve = (req, done) => { - const conversation = conversationDb[req.conversationUid]; - if (user_id$1 === conversation.comments[0].author) { // Replace wth your own logic, e.g. check if user has admin priveleges - delete conversationDb[req.conversationUid]; - setTimeout(() => done({ canResolve: true }), fakeDelay); - } else { - setTimeout(() => done({ canResolve: false, reason: 'Must be conversation author' }), fakeDelay); - } - }; - - const tinycomments_delete_comment = (req, done) => { - const oldcomments = conversationDb[req.conversationUid].comments; - let reason = 'Comment not found'; - - const newcomments = oldcomments.filter((comment) => { - if (comment.uid === req.commentUid) { // Found the comment to delete - if (user_id$1 === comment.author) { // Replace with your own logic, e.g. check if user has admin privileges - return false; // Remove the comment - } else { - reason = 'Not authorised to delete this comment'; // Update reason - } - } - return true; // Keep the comment - }); - - if (newcomments.length === oldcomments.length) { - setTimeout(() => done({ canDelete: false, reason }), fakeDelay); - } else { - conversationDb[req.conversationUid].comments = newcomments; - setTimeout(() => done({ canDelete: true }), fakeDelay); - } - }; - - const tinycomments_edit_comment = (req, done) => { - const oldcomments = conversationDb[req.conversationUid].comments; - let reason = 'Comment not found'; - let canEdit = false; - - const newcomments = oldcomments.map((comment) => { - if (comment.uid === req.commentUid) { // Found the comment to delete - if (user_id$1 === comment.author) { // Replace with your own logic, e.g. check if user has admin privileges - canEdit = true; // User can edit the comment - return { ...comment, content: req.content, modifiedAt: new Date().toISOString() }; // Update the comment - } else { - reason = 'Not authorised to edit this comment'; // Update reason - } - } - return comment; // Keep the comment - }); - - if (canEdit) { - conversationDb[req.conversationUid].comments = newcomments; - setTimeout(() => done({ canEdit }), fakeDelay); - } else { - setTimeout(() => done({ canEdit, reason }), fakeDelay); - } - }; - - const tinycomments_delete_all = (req, done) => { - const conversation = conversationDb[req.conversationUid]; - if (user_id$1 === conversation.comments[0].author) { // Replace wth your own logic, e.g. check if user has admin priveleges - delete conversationDb[req.conversationUid]; - setTimeout(() => done({ canDelete: true }), fakeDelay); - } else { - setTimeout(() => done({ canDelete: false, reason: 'Must be conversation author' }), fakeDelay); - } - }; - - const tinycomments_lookup = (req, done) => { - setTimeout(() => { - done({ - conversation: { - uid: conversationDb[req.conversationUid].uid, - comments: [...conversationDb[req.conversationUid].comments] - } - }); - }, fakeDelay); - }; - - const tinycomments_fetch = (conversationUids, done) => { - const fetchedConversations = {}; - conversationUids.forEach((uid) => { - const conversation = conversationDb[uid]; - if (conversation) { - fetchedConversations[uid] = {...conversation}; - } - }); - setTimeout(() => done({ conversations: fetchedConversations }), fakeDelay); - }; - - var TinyCommentsConfig = { - toolbar: 'comments', - name: 'tinycomments', - config: { - tinycomments_mode: 'callback', - tinycomments_mentions_enabled: true, - tinycomments_create, - tinycomments_reply, - tinycomments_delete, - tinycomments_resolve, - tinycomments_delete_all, - tinycomments_lookup, - tinycomments_delete_comment, - tinycomments_edit_comment, - tinycomments_fetch, - // Fallback TinyMCE < 7.8 - tinycomments_author: user_id$1, - tinycomments_author_name: 'James Wilson', - tinycomments_avatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg', - // Fallback for tinymce >= 7.8 - tinycomments_fetch_author_info: (done) => { - setTimeout(() => done({ - author: user_id$1, - authorName: 'James Wilson', - authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg', - }), fakeDelay); - }, - } - }; - - var AdvlistConfig = { - toolbar: 'numlist bullist', - name: 'advlist', - config: { - advlist_number_styles: "default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman", - advlist_bullet_styles: "default,circle,disc,square", - }, - // Code samples for each configuration option: - // - // advlist_number_styles - // Specifies the number styles available in the list style dropdown - // - default: Standard numbering (1, 2, 3...) - // - lower-alpha: Lowercase letters (a, b, c...) - // - lower-greek: Lowercase Greek letters (α, β, γ...) - // - lower-roman: Lowercase Roman numerals (i, ii, iii...) - // - upper-alpha: Uppercase letters (A, B, C...) - // - upper-roman: Uppercase Roman numerals (I, II, III...) - // Usage: advlist_number_styles: "default,lower-alpha,lower-roman" - // - // advlist_bullet_styles - // Specifies the bullet styles available in the list style dropdown - // - default: Standard bullet point (•) - // - circle: Open circle (○) - // - disc: Filled circle/disc (●) - // - square: Square bullet (■) - // Usage: advlist_bullet_styles: "default,circle,square" - }; - - const suggestededitsModel = { - 'history': { - '2': [ - { - 'id': 1, - 'uid': 'james-wilson', - 'timestamp': 1752576936000, - 'feedback': 'Nice improvement!' - } - ] - }, - 'version': 1, - 'contents': [ - { - 'type': 'p', - 'children': [ - { - 'type': 'img', - 'attrs': { - 'style': 'display: block; margin-left: auto; margin-right: auto;', - 'title': 'Tiny Logo', - 'src': 'https://www.tiny.cloud/docs/images/logos/android-chrome-256x256.png', - 'alt': 'TinyMCE Logo', - 'width': '128', - 'height': '128' - } - } - ] - }, - { - 'type': 'h2', - 'attrs': { - 'style': 'text-align: center;' - }, - 'children': [ - { - 'text': 'Welcome to the TinyMCE Suggested Edits ' - }, - { - 'text': 'interactive ', - 'opData': { - 'id': 1, - 'type': 'insert', - 'uid': 'alex-thompson', - 'timestamp': 1752015064000 - } - }, - { - 'text': 'demo!' - } - ] - }, - { - 'type': 'p', - 'attrs': { - 'style': 'text-align: center;' - }, - 'children': [ - { - 'text': 'Try out the Suggested Edits feature' - }, - { - 'text': ': type in the editor, apply formatting or delete some content. T', - 'opData': { - 'id': 2, - 'type': 'insert', - 'uid': 'alex-thompson', - 'timestamp': 1752415064000 - } - }, - { - 'text': ' by typing in the editor and t', - 'opData': { - 'id': 2, - 'type': 'remove', - 'uid': 'alex-thompson', - 'timestamp': 1752415064000 - } - }, - { - 'text': 'hen' - }, - { - 'text': ',', - 'opData': { - 'id': 3, - 'type': 'insert', - 'uid': 'alex-thompson', - 'timestamp': 1752515064000 - } - }, - { - 'text': ' click' - }, - { - 'text': 'ing', - 'opData': { - 'id': 4, - 'type': 'remove', - 'uid': 'alex-thompson', - 'timestamp': 1752515064000 - } - }, - { - 'text': ' the Review Changes button in the toolbar' - }, - { - 'text': ' to see your changes', - 'opData': { - 'id': 5, - 'type': 'insert', - 'uid': 'kai-nakamura', - 'timestamp': 1752615064000 - } - }, - { - 'text': '.' - } - ] - }, - { - 'type': 'p', - 'attrs': { - 'style': 'text-align: center;' - }, - 'children': [ - { - 'text': 'And visit the ' - }, - { - 'text': 'pricing page', - 'opData': { - 'id': 6, - 'type': 'modify', - 'uid': 'kai-nakamura', - 'timestamp': 1752615064000 - }, - 'format': [ - { - 'type': 'a', - 'attrs': { - 'href': 'https://www.tiny.cloud/pricing' - } - } - ], - 'oldFormat': [ - { - 'type': 'a', - 'attrs': { - 'href': 'https://www.tiny.cloud/pricing' - } - }, - 'em' - ] - }, - { - 'text': ' to learn more about our Premium plugins.' - } - ] - }, - { - 'type': 'h2', - 'children': [ - { - 'text': 'A simple table to play with' - } - ] - }, - { - 'type': 'table', - 'attrs': { - 'style': 'border-collapse: collapse; width: 100%;', - 'border': '1' - }, - 'children': [ - { - 'type': 'thead', - 'children': [ - { - 'type': 'tr', - 'attrs': { - 'style': 'text-align: left;' - }, - 'children': [ - { - 'type': 'th', - 'children': [ - { - 'text': 'Product' - } - ] - }, - { - 'type': 'th', - 'children': [ - { - 'text': 'Cost' - } - ] - }, - { - 'type': 'th', - 'children': [ - { - 'text': 'Really?' - } - ] - } - ] - } - ] - }, - { - 'type': 'tbody', - 'children': [ - { - 'type': 'tr', - 'children': [ - { - 'type': 'td', - 'children': [ - { - 'text': 'TinyMCE Cloud' - } - ] - }, - { - 'type': 'td', - 'children': [ - { - 'text': 'Get started for free' - } - ] - }, - { - 'type': 'td', - 'children': [ - { - 'text': 'Yes!', - 'format': [ - 'strong' - ] - } - ] - } - ] - }, - { - 'type': 'tr', - 'children': [ - { - 'type': 'td', - 'children': [ - { - 'text': 'Plupload' - } - ] - }, - { - 'type': 'td', - 'children': [ - { - 'text': 'Free' - } - ] - }, - { - 'type': 'td', - 'children': [ - { - 'text': 'Yes!', - 'format': [ - 'strong' - ] - } - ] - } - ] - } - ] - } - ] - }, - { - 'type': 'h2', - 'opData': { - 'id': 7, - 'type': 'insert', - 'uid': 'mia-andersson', - 'timestamp': 1752576331000 - }, - 'children': [ - { - 'text': 'Found a bug?' - } - ] - }, - { - 'type': 'p', - 'children': [ - { - 'text': ' ', - 'opData': { - 'id': 7, - 'type': 'remove', - 'uid': 'mia-andersson', - 'timestamp': 1752576331000 - } - }, - { - 'text': 'If you believe you have found a bug please create an issue on the ', - 'opData': { - 'id': 7, - 'type': 'insert', - 'uid': 'mia-andersson', - 'timestamp': 1752576331000 - } - }, - { - 'text': 'GitHub repo', - 'opData': { - 'id': 7, - 'type': 'insert', - 'uid': 'mia-andersson', - 'timestamp': 1752576331000 - }, - 'format': [ - { - 'type': 'a', - 'attrs': { - 'href': 'https://github.com/tinymce/tinymce/issues' - } - } - ] - }, - { - 'text': ' to report it to the developers.', - 'opData': { - 'id': 7, - 'type': 'insert', - 'uid': 'mia-andersson', - 'timestamp': 1752576331000 - } - } - ] - }, - { - 'type': 'h2', - 'children': [ - { - 'text': 'Finally…' - } - ] - }, - { - 'type': 'p', - 'children': [ - { - 'text': 'Don’t forget to check out ' - }, - { - 'text': 'Plupload', - 'format': [ - { - 'type': 'a', - 'attrs': { - 'href': 'http://www.plupload.com', - 'target': '_blank', - 'rel': 'noopener' - } - } - ] - }, - { - 'text': ', the upload solution featuring HTML5 upload support.' - } - ] - }, - { - 'type': 'p', - 'children': [ - { - 'text': 'Thanks for supporting TinyMCE. We hope it helps you and your users create great content.' - } - ] - }, - { - 'type': 'p', - 'children': [ - { - 'text': 'All the best from the TinyMCE team.' - } - ] - } - ] - }; - - var SuggestedEditConfig = { - toolbar: 'suggestededits', - name: 'suggestededits', - config: { - suggestededits_model: suggestededitsModel, - suggestededits_access: 'full', - suggestededits_content: 'html', - }, - }; - - var CodeSampleConfig = { - name: 'codesample', - toolbar: 'codesample', - config: { - codesample_languages: [ - { text: 'HTML/XML', value: 'markup' }, - { text: 'JavaScript', value: 'javascript' }, - { text: 'CSS', value: 'css' }, - { text: 'PHP', value: 'php' }, - { text: 'Ruby', value: 'ruby' }, - { text: 'Python', value: 'python' }, - { text: 'Java', value: 'java' }, - { text: 'C', value: 'c' }, - { text: 'C#####', value: 'csharpppppp' }, - { text: 'C++', value: 'cpp' } - ], - } - }; - - var ExportWordConfig = { - toolbar: 'exportword', - name: 'exportword', - config: { - exportword_service_url: "https://exportdocx.converter.tiny.cloud", - exportword_converter_options: { - // 'Letter', 'Legal', 'Tabloid', 'Statement', 'Executive', 'A3', 'A4', 'A5', 'A6', 'B4', 'B5' - format: 'A4', - - margin_top: '1in', - margin_bottom: '1in', - margin_right: '1in', - margin_left: '1in', - header: [ - { - html: '

First page header.

', - css: 'h1 { font-size: 30px; }', - - //'default', 'even', 'odd', 'first' - type: 'first' - } - ], - - footer: [ - { - html: '

Page footer

', - css: 'p { font-size: 12px; }', - // 'default', 'even', 'odd', 'first' - type: 'default' - } - ], - - // 'portrait' or 'landscape' - orientation: 'portrait', - auto_pagination: true, - - base_url: 'https://example.com', - timezone: 'UTC' - }, - exportword_converter_style: 'p { color: cyan !important }', - }, - }; - - var InsertDatetimeConfig = { - name: 'insertdatetime', - toolbar: 'insertdatetime', - config: { - // override the default formatting rule for date formats inserted by the mceInsertDate command - insertdatetime_dateformat: "%Y/%m/%d", - - // override the default formatting rule for times inserted by the mceInsertTime command - insertdatetime_timeformat: "%H%M%S", - - // specify a list of date/time formats to be used in the date menu or date select box - insertdatetime_formats: ["%H:%M:%S", "%Y-%m-%d", "%I:%M:%S %p", "%D", "%H%M%S", "%Y/%m/%d"], - } - }; - - var AnchorConfig = { - name: 'anchor', - toolbar: 'anchor', - config: {} - }; - - var AutolinkConfig = { - name: 'autolink', - config: {} - }; - - var AutosaveConfig = { - name: 'autosave', - config: {} - }; - - var CharmapConfig = { - name: 'charmap', - toolbar: 'charmap', - config: {} - }; - - var CodeConfig = { - name: 'code', - toolbar: 'code', - config: {} - }; - - var EditimageConfig = { - name: 'editimage', - config: {} - }; - - var DirectionalityConfig = { - name: 'directionality', - toolbar: 'ltr rtl', - config: {} - }; - - var EmoticonsConfig = { - name: 'emoticons', - toolbar: 'emoticons', - config: {} - }; - - var FullscreenConfig = { - name: 'fullscreen', - toolbar: 'fullscreen', - config: {} - }; - - var HelpConfig = { - name: 'help', - toolbar: 'help', - config: {} - }; - - var ImageConfig = { - name: 'image', - toolbar: 'image', - config: { - image_advtab: true, - image_description: true, - image_dimensions: true, - image_title: true, - image_caption: true, - } - }; - - var ImportcssConfig = { - name: 'importcss', - config: {} - }; - - var LinkConfig = { - name: 'link', - toolbar: 'link unlink', - config: {} - }; - - var ListsConfig = { - name: 'lists', - toolbar: 'numlist bullist', - config: {} - }; - - var MediaConfig = { - name: 'media', - toolbar: 'media', - config: {} - }; - - var NonbreakingConfig = { - name: 'nonbreaking', - toolbar: 'nonbreaking', - config: {} - }; - - var PagebreakConfig = { - name: 'pagebreak', - toolbar: 'pagebreak', - config: {} - }; - - var PreviewConfig = { - name: 'preview', - toolbar: 'preview', - config: {} - }; - - var QuickbarsConfig = { - name: 'quickbars', - config: { - quickbars_image_toolbar: 'alignleft aligncenter alignright', - quickbars_selection_toolbar: 'undo redo | copy cut paste | quicklink align', - quickbars_insert_toolbar: 'quickimage quicktable | hr pagebreak' - } - }; - - var SaveConfig = { - name: 'save', - toolbar: 'save cancel', - config: {} - }; - - var SearchreplaceConfig = { - name: 'searchreplace', - toolbar: 'searchreplace', - config: { - save_onsavecallback: function () { alert("Saved"); }, - save_oncancelcallback: function () { alert("Save Cancelled"); }, - } - }; - - var TableConfig = { - name: 'table', - toolbar: 'table', - config: {} - }; - - var VisualblocksConfig = { - name: 'visualblocks', - toolbar: 'visualblocks', - config: {} - }; - - var VisualcharsConfig = { - name: 'visualchars', - toolbar: 'visualchars', - config: {} - }; - - var WordcountConfig = { - name: 'wordcount', - config: {} - }; - - var A11ycheckerConfig = { - name: 'a11ychecker', - config: {}, - toolbar: 'a11ycheck' - }; - - var AdvcodeConfig = { - name: 'advcode', - config: { - advcode_inline: true - } - }; - - var AdvtableConfig = { - name: 'advtable', - config: {} - }; - - var AutocorrectConfig = { - name: 'autocorrect', - config: { - autocorrect_autocorrect: true, - autocorrect_capitalize: true, - } - }; - - var CasechangeConfig = { - name: 'casechange', - toolbar: 'casechange', - config: {} - }; - - var ChecklistConfig = { - name: 'checklist', - toolbar: 'checklist', - config: {} - }; - - var EditimageConfig2 = { - name: 'editimage', - toolbar: 'rotateleft rotateright flipv fliph editimage imageoptions', - config: { - editimage_toolbar: "rotateleft rotateright flipv fliph editimage imageoptions", - editimage_proxy_service_url: 'https://imageproxy.tiny.cloud', - } - }; - - var ExportpdfConfig = { - name: 'exportpdf', - toolbar: 'exportpdf', - config: { - exportpdf_service_url: "https://exportpdf.converter.tiny.cloud", - exportpdf_converter_options: { - header_html: '
Document Title
Date:
Page of
', - footer_html: '
Confidential
', - header_and_footer_css: 'div { color: blue; font-family: Arial, sans-serif; font-size: 10pt; }', - margin_top: '2cm', - margin_bottom: '2cm', - margin_left: '20mm', - margin_right: '20mm', - format: 'A4', - page_orientation: 'portrait', - }, - exportpdf_converter_style: 'body { color: black !important; font-family: Helvetica, Arial, sans-serif; } p { color: cyan !important; }', - } - }; - - var FootnotesConfig = { - name: 'footnotes', - toolbar: 'footnotes footnotesupdate', - config: {} - }; - - var FormatpainterConfig = { - name: 'formatpainter', - toolbar: 'formatpainter', - config: {} - }; - - var ImportwordConfig = { - name: 'importword', - toolbar: 'importword', - config: { - importword_service_url: "https://importdocx.converter.tiny.cloud", - importword_converter_options: { - formatting: { - styles: 'inline', - resets: 'inline', - defaults: 'inline', - } - } - } - }; - - var InlinecssConfig = { - name: 'inlinecss', - config: {} - }; - - var LinkcheckerConfig = { - name: 'linkchecker', - config: {} - }; - - var MarkdownConfig = { - name: 'markdown', - config: {} - }; - - var MathConfig = { - name: 'math', - toolbar: 'math', - config: {} - }; - - var MediaembedConfig = { - name: 'mediaembed', - config: {} - }; - - var PageembedConfig = { - name: 'pageembed', - toolbar: 'pageembed', - config: {} - }; - - var PermanentpenConfig = { - name: 'permanentpen', - toolbar: 'permanentpen', - config: { - permanentpen_properties: { - fontname: 'impact,sans-serif', - forecolor: '#E74C3C', - fontsize: '12px', - bold: true, - italic: false, - strikethrough: false, - underline: false - }, - } - }; - - var PowerpasteConfig = { - name: 'powerpaste', - config: {} - }; - - const revisions = [ - { - 'revisionId': '1', - 'createdAt': '2023-11-25T03:30:46.171Z', - 'content': '

Rev 1

' - }, - { - 'revisionId': '2', - 'createdAt': '2023-11-25T12:06:09.675Z', - 'content': '

Rev 2

' - }, - { - 'revisionId': '3', - 'createdAt': '2023-11-27T03:23:32.351Z', - 'content': '

Rev 3

' - }, - { - 'revisionId': '4', - 'createdAt': '2023-11-29T12:35:16.203Z', - 'content': '

Rev 4

' - }, - { - 'revisionId': '5', - 'createdAt': '2023-11-28T08:01:56.100Z', - 'content': '

Rev 5

' - } - ]; - - var RevisionhistoryConfig = { - toolbar: 'revisionhistory', - name: 'revisionhistory', - config: { - revisionhistory_fetch: () => Promise.resolve(revisions), - } - }; - - var TableofcontentsConfig = { - name: 'tableofcontents', - toolbar: 'tableofcontents', - config: {} - }; - - var TinymcespellcheckerConfig = { - name: 'tinymcespellchecker', - config: {} - }; - - var TypographyConfig = { - name: 'typography', - toolbar: 'typography', - config: {} - }; - - var UploadcareConfig = { - name: 'uploadcare', - toolbar: 'uploadcare', - config: { - uploadcare_public_key: '6ff5776be9bb64e10023', - } - }; - - const API_URL = 'https://demouserdirectory.tiny.cloud/v1/users'; - - const user_id = 'james-wilson'; - const basicConfig = { - height: 600, - mobile: { - theme: "silver", - contextmenu: "link image table preview", - }, - pad_empty_with_br: true, - help_accessibility: true, - // TODO: Target for tinymce 8 - user_id, - fetch_users: (userIds) => - Promise.all(userIds.map((userId) => fetch(`${API_URL}/${userId}`) - .then((response) => response.json()) - .catch(() => ({ id: userId })))), - - }; - - const pluginsConfig = [ - AccordionConfig, - CodeSampleConfig, - AdvlistConfig, - AnchorConfig, - AutolinkConfig, - AutosaveConfig, - CharmapConfig, - CodeConfig, - EditimageConfig, - DirectionalityConfig, - EmoticonsConfig, - FullscreenConfig, - HelpConfig, - ImageConfig, - ImportcssConfig, - InsertDatetimeConfig, - LinkConfig, - ListsConfig, - MediaConfig, - NonbreakingConfig, - PagebreakConfig, - PreviewConfig, - QuickbarsConfig, - SaveConfig, - SearchreplaceConfig, - TableConfig, - VisualblocksConfig, - VisualcharsConfig, - WordcountConfig, - A11ycheckerConfig, - AdvcodeConfig, - AdvtableConfig, - AdvtemplateConfig, - AutocorrectConfig, - CasechangeConfig, - ChecklistConfig, - EditimageConfig2, - ExportpdfConfig, - ExportWordConfig, - FootnotesConfig, - FormatpainterConfig, - ImportwordConfig, - InlinecssConfig, - LinkcheckerConfig, - MarkdownConfig, - MathConfig, - MediaembedConfig, - MentionsConfig, - MergetagsConfig, - PageembedConfig, - PermanentpenConfig, - PowerpasteConfig, - RevisionhistoryConfig, - SuggestedEditConfig, - TableofcontentsConfig, - TinyCommentsConfig, - TinymcespellcheckerConfig, - TypographyConfig, - UploadcareConfig, - TinymceaiConfig, - ]; - - const toolbarConfig = pluginsConfig.map((plugin) => plugin?.toolbar).filter(Boolean).join(' | '); - const generateConfig = ({ excludePlugins = [], overrideConfig = {} }) => { - const plugins = pluginsConfig.map((p) => p.name).filter((name) => !excludePlugins.includes(name)); - const extractedPluginsConfig = pluginsConfig.reduce((acc, cur) => { - return { ...acc, ...cur.config }; - }, {}); - const finalConfig = { - ...basicConfig, - ...extractedPluginsConfig, - ...overrideConfig - }; - - return { - ...finalConfig, - plugins: plugins, - toolbar: toolbarConfig, - height: 500 - }; - }; - - exports.generateConfig = generateConfig; - - return exports; - -})({}); diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index b046b30..d96720f 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -1,10 +1,10 @@ import { Assertions } from '@ephox/agar'; import { before, describe, it, context, after, beforeEach, afterEach } from '@ephox/bedrock-client'; import { Global } from '@ephox/katamari'; -import Editor from '../../../main/ts/component/Editor'; -import { VersionLoader } from '@tinymce/miniature'; +import { VersionHooks } from '@tinymce/miniature'; import { deleteTinymce } from '../alien/Utils'; import type { Editor as TinyMCEEditor } from 'tinymce'; +import { Remove, SugarElement } from '@ephox/sugar'; type EditorElement = HTMLElement & { disabled: boolean }; @@ -12,30 +12,52 @@ describe('DisableTest', () => { let uid = 0; const nextId = () => `_disabled_test_fn_${uid++}`; - const setupVersionContext = (version: string) => { - before(async () => { - await VersionLoader.pLoadVersion(version); - Global.tinymceTestConfig = { license_key: 'gpl' }; - }); - - after(() => { - delete Global.tinymceTestConfig; - deleteTinymce(); - }); - - beforeEach(() => { - if (!window.customElements.get('tinymce-editor')) { - Editor(); - } - }); + before(() => { + Global.tinymceTestConfig = { license_key: 'gpl' }; + }); + + after(() => { + delete Global.tinymceTestConfig; + }); - afterEach(() => { - document.querySelectorAll('tinymce-editor').forEach((el) => el.remove()); - }); - }; + // const setupVersionContext = (version: string) => { + // before(async () => { + // // await VersionLoader.pLoadVersion(version); + // Global.tinymceTestConfig = { license_key: 'gpl' }; + // }); + + // after(() => { + // delete Global.tinymceTestConfig; + // console.log('Deleting tinymce from global'); + // deleteTinymce(); + // }); + + // beforeEach(() => { + // // if (!window.customElements.get('tinymce-editor')) { + // // Editor(); + // // } + // }); + + // afterEach(() => { + // document.querySelectorAll('tinymce-editor').forEach((el) => el.remove()); + // }); + // }; + + // const editorHook = VersionHooks.bddSetupVersionFromElement('latest', {}, () => { + // const el = document.createElement('tinymce-editor') as EditorElement; + // el.setAttribute('config', 'tinymceTestConfig'); + // document.body.appendChild(el); + // return { + // element: SugarElement.fromDom(el), + // teardown: () => { + // delete Global.tinymceTestConfig; + // deleteTinymce(); + // } + // }; + // }); const pCreateEditor = - (attrs: Record = {}, onSetup?: (editor: any) => void): Promise<{ el: EditorElement; editor: TinyMCEEditor }> => new Promise((resolve) => { + (attrs: Record = {}): Promise<{ el: EditorElement; editor: TinyMCEEditor }> => new Promise((resolve) => { const setupFnName = nextId(); const initFnName = nextId(); let editorInstance: any; @@ -43,7 +65,6 @@ describe('DisableTest', () => { Global[setupFnName] = (editor: any) => { delete Global[setupFnName]; editorInstance = editor; - onSetup?.(editor); }; Global[initFnName] = () => { @@ -62,62 +83,83 @@ describe('DisableTest', () => { document.body.appendChild(el); }); - context('When using with Tinymce < 7.6', () => { - setupVersionContext('7.5.0'); + const createHoook = (version: string, attrs: Record) => + VersionHooks.bddSetupVersionFromElement(version, {}, () => { + const el = document.createElement('tinymce-editor'); + el.setAttribute('config', 'tinymceTestConfig'); + for (const [ key, value ] of Object.entries(attrs)) { + el.setAttribute(key, value); + } + document.body.appendChild(el); + const sEl = SugarElement.fromDom(el); - it('Editor should be not be disabled when disabled attribute is present', async () => { - const { editor } = await pCreateEditor({ disabled: '' }); - Assertions.assertEq('Editor should be in design mode', true, editor.mode.get() === 'design'); - }); + return { + element: sEl, + teardown: () => { + Remove.remove(sEl); + } + } }); - context('When using with Tinymce >= 7.6', () => { - setupVersionContext('8'); - - const pWaitForDisabledStateChange = (editor: any): Promise => - new Promise((resolve) => editor.once('DisabledStateChange', resolve)); - - const assertDisabledState = (el: EditorElement, editor: TinyMCEEditor, expected: boolean) => { - const hasDisabledAtt = el.hasAttribute('disabled'); - Assertions.assertEq('Editor should be disabled', expected, editor.options.get('disabled')); - Assertions.assertEq(`disabled attribute should be ${expected ? 'present' : 'absent'}`, expected, hasDisabledAtt); - }; - - it('Editor should be disabled when disabled attribute is present', async () => { - const { el, editor } = await pCreateEditor({ disabled: '' }); - assertDisabledState(el, editor, true); - }); - - it('Editor is not disabled when disabled attribute is absent', async () => { - const { el, editor } = await pCreateEditor(); - assertDisabledState(el, editor, false); - }); - - it('Setting disabled attribute after init disables the editor', async () => { - const { el, editor } = await pCreateEditor(); - assertDisabledState(el, editor, false); - el.setAttribute('disabled', ''); - await pWaitForDisabledStateChange(editor); - assertDisabledState(el, editor, true); - }); + context('When using with Tinymce < 7.6', () => { + const hook = createHoook('7.5.0', { disabled: '' }); - it('Removing disabled attribute after init enables the editor', async () => { - const { el, editor } = await pCreateEditor({ disabled: '' }); - assertDisabledState(el, editor, true); - el.removeAttribute('disabled'); - await pWaitForDisabledStateChange(editor); - assertDisabledState(el, editor, false); + after(() => { + // Necessary to clean up the editor loading scripts otherwise bedrock will complain about extra elements were left in the DOM + deleteTinymce(); }); - it('Updating disabled property directly syncs editor option and attribute', async () => { - const { el, editor } = await pCreateEditor(); - Assertions.assertEq('disabled property should be false initially', false, el.disabled); - el.disabled = true; - await pWaitForDisabledStateChange(editor); - assertDisabledState(el, editor, true); - el.disabled = false; - await pWaitForDisabledStateChange(editor); - assertDisabledState(el, editor, false); + it.only('Editor should be not be disabled when disabled attribute is present', () => { + Assertions.assertEq('Editor should be in design mode', true, hook.editor().mode.get() === 'design'); }); }); + + // context('When using with Tinymce >= 7.6', () => { + + // const pWaitForDisabledStateChange = (editor: any): Promise => + // new Promise((resolve) => editor.once('DisabledStateChange', resolve)); + + // const assertDisabledState = (el: EditorElement, editor: TinyMCEEditor, expected: boolean) => { + // const hasDisabledAtt = el.hasAttribute('disabled'); + // Assertions.assertEq('Editor should be disabled', expected, editor.options.get('disabled')); + // Assertions.assertEq(`disabled attribute should be ${expected ? 'present' : 'absent'}`, expected, hasDisabledAtt); + // }; + + // it('Editor should be disabled when disabled attribute is present', async () => { + // const { el, editor } = await pCreateEditor({ disabled: '' }); + // assertDisabledState(el, editor, true); + // }); + + // it('Editor is not disabled when disabled attribute is absent', async () => { + // const { el, editor } = await pCreateEditor(); + // assertDisabledState(el, editor, false); + // }); + + // it('Setting disabled attribute after init disables the editor', async () => { + // const { el, editor } = await pCreateEditor(); + // assertDisabledState(el, editor, false); + // el.setAttribute('disabled', ''); + // await pWaitForDisabledStateChange(editor); + // assertDisabledState(el, editor, true); + // }); + + // it('Removing disabled attribute after init enables the editor', async () => { + // const { el, editor } = await pCreateEditor({ disabled: '' }); + // assertDisabledState(el, editor, true); + // el.removeAttribute('disabled'); + // await pWaitForDisabledStateChange(editor); + // assertDisabledState(el, editor, false); + // }); + + // it('Updating disabled property directly syncs editor option and attribute', async () => { + // const { el, editor } = await pCreateEditor(); + // Assertions.assertEq('disabled property should be false initially', false, el.disabled); + // el.disabled = true; + // await pWaitForDisabledStateChange(editor); + // assertDisabledState(el, editor, true); + // el.disabled = false; + // await pWaitForDisabledStateChange(editor); + // assertDisabledState(el, editor, false); + // }); + // }); }); From f87ea904e24fcc4328d08d88a2a9c452220784e1 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Tue, 7 Apr 2026 09:11:20 +0930 Subject: [PATCH 10/29] Bump minor and corrected the heading in changelog --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c8db79..561a2a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -## Changed +### Changed - Moved `@tinymce/miniature` to devDependency. #INT-3358 diff --git a/package.json b/package.json index 1a3e343..13b474d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "description": "Official TinyMCE Web Component", - "version": "2.3.3-rc", + "version": "2.4.0-rc", "name": "@tinymce/tinymce-webcomponent", "repository": { "url": "https://github.com/tinymce/tinymce-webcomponent" From cb188a98af21f81adb6a039b47ae36463b1af34b Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Tue, 7 Apr 2026 13:01:52 +0930 Subject: [PATCH 11/29] Fixed tests --- src/test/ts/alien/Utils.ts | 16 ++- src/test/ts/browser/DisabledTest.ts | 187 +++++++++++----------------- src/test/ts/browser/LoadTest.ts | 68 +++++----- 3 files changed, 124 insertions(+), 147 deletions(-) diff --git a/src/test/ts/alien/Utils.ts b/src/test/ts/alien/Utils.ts index 02c67f1..81f21cb 100644 --- a/src/test/ts/alien/Utils.ts +++ b/src/test/ts/alien/Utils.ts @@ -1,12 +1,12 @@ import { Attribute, Remove, SelectorFilter, SugarElement } from '@ephox/sugar'; import { ScriptLoader } from 'src/main/ts/utils/ScriptLoader'; -import { Arr, Global, Strings } from '@ephox/katamari'; +import { Arr, Strings, Optional, Fun } from '@ephox/katamari'; +import * as Globals from '@tinymce/miniature/lib/main/ts/loader/Globals'; +import Editor from 'src/main/ts/component/Editor'; export const deleteTinymce = () => { ScriptLoader.reinitialize(); - - delete Global.tinymce; - delete Global.tinyMCE; + Globals.deleteTinymceGlobals(); const hasTinyUri = (attrName: string) => (elm: SugarElement) => Attribute.getOpt(elm, attrName).exists((src) => Strings.contains(src, 'tinymce')); @@ -17,4 +17,12 @@ export const deleteTinymce = () => { ]); Arr.each(elements, Remove.remove); +}; + +export const removeTinymceElement = () => { + Arr.map(SelectorFilter.all('tinymce-editor'), Remove.remove); +}; + +export const registerCustomElementIfNot = () => { + Optional.from(customElements.get('tinymce-editor')).fold(Editor, Fun.noop); }; \ No newline at end of file diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index d96720f..8081a1d 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -1,18 +1,19 @@ import { Assertions } from '@ephox/agar'; -import { before, describe, it, context, after, beforeEach, afterEach } from '@ephox/bedrock-client'; +import { before, describe, it, context, after, afterEach } from '@ephox/bedrock-client'; import { Global } from '@ephox/katamari'; -import { VersionHooks } from '@tinymce/miniature'; -import { deleteTinymce } from '../alien/Utils'; -import type { Editor as TinyMCEEditor } from 'tinymce'; -import { Remove, SugarElement } from '@ephox/sugar'; +import type { TinyMCE, Editor as TinyMCEEditor } from 'tinymce'; +import { VersionLoader, TinyVer } from '@tinymce/miniature'; +import { deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; -type EditorElement = HTMLElement & { disabled: boolean }; +type EditorElement = HTMLElement & { disabled?: boolean }; +declare const tinymce: TinyMCE; describe('DisableTest', () => { let uid = 0; const nextId = () => `_disabled_test_fn_${uid++}`; before(() => { + registerCustomElementIfNot(); Global.tinymceTestConfig = { license_key: 'gpl' }; }); @@ -20,42 +21,6 @@ describe('DisableTest', () => { delete Global.tinymceTestConfig; }); - // const setupVersionContext = (version: string) => { - // before(async () => { - // // await VersionLoader.pLoadVersion(version); - // Global.tinymceTestConfig = { license_key: 'gpl' }; - // }); - - // after(() => { - // delete Global.tinymceTestConfig; - // console.log('Deleting tinymce from global'); - // deleteTinymce(); - // }); - - // beforeEach(() => { - // // if (!window.customElements.get('tinymce-editor')) { - // // Editor(); - // // } - // }); - - // afterEach(() => { - // document.querySelectorAll('tinymce-editor').forEach((el) => el.remove()); - // }); - // }; - - // const editorHook = VersionHooks.bddSetupVersionFromElement('latest', {}, () => { - // const el = document.createElement('tinymce-editor') as EditorElement; - // el.setAttribute('config', 'tinymceTestConfig'); - // document.body.appendChild(el); - // return { - // element: SugarElement.fromDom(el), - // teardown: () => { - // delete Global.tinymceTestConfig; - // deleteTinymce(); - // } - // }; - // }); - const pCreateEditor = (attrs: Record = {}): Promise<{ el: EditorElement; editor: TinyMCEEditor }> => new Promise((resolve) => { const setupFnName = nextId(); @@ -63,12 +28,10 @@ describe('DisableTest', () => { let editorInstance: any; Global[setupFnName] = (editor: any) => { - delete Global[setupFnName]; editorInstance = editor; }; Global[initFnName] = () => { - delete Global[initFnName]; resolve({ el: el as EditorElement, editor: editorInstance }); }; @@ -83,83 +46,81 @@ describe('DisableTest', () => { document.body.appendChild(el); }); - const createHoook = (version: string, attrs: Record) => - VersionHooks.bddSetupVersionFromElement(version, {}, () => { - const el = document.createElement('tinymce-editor'); - el.setAttribute('config', 'tinymceTestConfig'); - for (const [ key, value ] of Object.entries(attrs)) { - el.setAttribute(key, value); - } - document.body.appendChild(el); - const sEl = SugarElement.fromDom(el); + context('When using with Tinymce < 7.6', () => { + before(async () => { + await VersionLoader.pLoadVersion('7.5.0'); + Assertions.assertEq('Tinymce 7.5.0 should be loaded', '7.5.0', TinyVer.getVersion(tinymce).major + '.' + TinyVer.getVersion(tinymce).minor + '.' + TinyVer.getVersion(tinymce).patch); + }); - return { - element: sEl, - teardown: () => { - Remove.remove(sEl); - } - } + after(() => { + deleteTinymce(); + }); + + it('Editor should be not be disabled when disabled attribute is present', async () => { + const { editor } = await pCreateEditor(); + Assertions.assertEq('Editor should be in design mode', true, editor.mode.get() === 'design'); + removeTinymceElement(); + }); }); - context('When using with Tinymce < 7.6', () => { - const hook = createHoook('7.5.0', { disabled: '' }); + context('When using with Tinymce >= 7.6', () => { + before(async () => { + await VersionLoader.pLoadVersion('8'); + Assertions.assertEq('Tinymce 8 should be loaded', '8', TinyVer.getVersion(tinymce).major + ''); + }); + + afterEach(() => { + removeTinymceElement(); + }); after(() => { - // Necessary to clean up the editor loading scripts otherwise bedrock will complain about extra elements were left in the DOM deleteTinymce(); }); - it.only('Editor should be not be disabled when disabled attribute is present', () => { - Assertions.assertEq('Editor should be in design mode', true, hook.editor().mode.get() === 'design'); + const pWaitForDisabledStateChange = (editor: any): Promise => + new Promise((resolve) => editor.once('DisabledStateChange', resolve)); + + const assertDisabledState = (el: EditorElement, editor: TinyMCEEditor, expected: boolean) => { + const hasDisabledAtt = el.hasAttribute('disabled'); + Assertions.assertEq('Editor should be disabled', expected, editor.options.get('disabled')); + Assertions.assertEq(`disabled attribute should be ${expected ? 'present' : 'absent'}`, expected, hasDisabledAtt); + }; + + it('Editor should be disabled when disabled attribute is present', async () => { + const { el, editor } = await pCreateEditor({ disabled: '' }); + assertDisabledState(el, editor, true); + }); + + it('Editor is not disabled when disabled attribute is absent', async () => { + const { el, editor } = await pCreateEditor(); + assertDisabledState(el, editor, false); + }); + + it('Setting disabled attribute after init disables the editor', async () => { + const { el, editor } = await pCreateEditor(); + assertDisabledState(el, editor, false); + el.setAttribute('disabled', ''); + await pWaitForDisabledStateChange(editor); + assertDisabledState(el, editor, true); }); - }); - // context('When using with Tinymce >= 7.6', () => { - - // const pWaitForDisabledStateChange = (editor: any): Promise => - // new Promise((resolve) => editor.once('DisabledStateChange', resolve)); - - // const assertDisabledState = (el: EditorElement, editor: TinyMCEEditor, expected: boolean) => { - // const hasDisabledAtt = el.hasAttribute('disabled'); - // Assertions.assertEq('Editor should be disabled', expected, editor.options.get('disabled')); - // Assertions.assertEq(`disabled attribute should be ${expected ? 'present' : 'absent'}`, expected, hasDisabledAtt); - // }; - - // it('Editor should be disabled when disabled attribute is present', async () => { - // const { el, editor } = await pCreateEditor({ disabled: '' }); - // assertDisabledState(el, editor, true); - // }); - - // it('Editor is not disabled when disabled attribute is absent', async () => { - // const { el, editor } = await pCreateEditor(); - // assertDisabledState(el, editor, false); - // }); - - // it('Setting disabled attribute after init disables the editor', async () => { - // const { el, editor } = await pCreateEditor(); - // assertDisabledState(el, editor, false); - // el.setAttribute('disabled', ''); - // await pWaitForDisabledStateChange(editor); - // assertDisabledState(el, editor, true); - // }); - - // it('Removing disabled attribute after init enables the editor', async () => { - // const { el, editor } = await pCreateEditor({ disabled: '' }); - // assertDisabledState(el, editor, true); - // el.removeAttribute('disabled'); - // await pWaitForDisabledStateChange(editor); - // assertDisabledState(el, editor, false); - // }); - - // it('Updating disabled property directly syncs editor option and attribute', async () => { - // const { el, editor } = await pCreateEditor(); - // Assertions.assertEq('disabled property should be false initially', false, el.disabled); - // el.disabled = true; - // await pWaitForDisabledStateChange(editor); - // assertDisabledState(el, editor, true); - // el.disabled = false; - // await pWaitForDisabledStateChange(editor); - // assertDisabledState(el, editor, false); - // }); - // }); + it('Removing disabled attribute after init enables the editor', async () => { + const { el, editor } = await pCreateEditor({ disabled: '' }); + assertDisabledState(el, editor, true); + el.removeAttribute('disabled'); + await pWaitForDisabledStateChange(editor); + assertDisabledState(el, editor, false); + }); + + it('Updating disabled property directly syncs editor option and attribute', async () => { + const { el, editor } = await pCreateEditor(); + Assertions.assertEq('disabled property should be false initially', false, el.disabled); + el.disabled = true; + await pWaitForDisabledStateChange(editor); + assertDisabledState(el, editor, true); + el.disabled = false; + await pWaitForDisabledStateChange(editor); + assertDisabledState(el, editor, false); + }); + }); }); diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index 2c7d4ff..8c434c0 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -1,8 +1,9 @@ -import { Pipeline, Step, Waiter, Assertions } from '@ephox/agar'; -import { SugarElement, Attribute, SugarBody, Insert, Remove, SelectorFilter, TextContent } from '@ephox/sugar'; -import { UnitTest } from '@ephox/bedrock-client'; -import Editor from '../../../main/ts/component/Editor'; -import { Arr, Global } from '@ephox/katamari'; +import { Assertions } from '@ephox/agar'; +import { SugarElement, Attribute, SugarBody, Insert, TextContent } from '@ephox/sugar'; +import { before, describe, after, it } from '@ephox/bedrock-client'; +import { Global } from '@ephox/katamari'; +import { deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; +import { VersionLoader } from '@tinymce/miniature'; const makeTinymceElement = (attrs: Record, content: string) => { const ce = SugarElement.fromTag('tinymce-editor'); @@ -12,39 +13,46 @@ const makeTinymceElement = (attrs: Record, content: string) => { Insert.append(SugarBody.body(), ce); }; -const removeTinymceElement = () => { - Arr.map(SelectorFilter.all('tinymce-editor'), Remove.remove); -}; - -UnitTest.asynctest('LoadTest', (success, failure) => { - Editor(); +describe('LoadTest', () => { let seenSetup = false; let seenInit = false; let editorInstance: any; - Pipeline.async('', [ - Step.sync(() => { + + before(async () => { + await VersionLoader.pLoadVersion('8'); + registerCustomElementIfNot(); + Global.tinymceTestConfig = { license_key: 'gpl' }; + + await new Promise((resolve) => { Global.customElementTinymceSetup = (editor: any) => { seenSetup = true; editorInstance = editor; }; Global.customElementTinymceInit = (_evt: unknown) => { seenInit = true; + resolve({}); }; - }), - Step.sync(() => makeTinymceElement({ - 'setup': 'customElementTinymceSetup', - 'on-init': 'customElementTinymceInit', - 'id': 'example_id' - }, '

Hello world

')), - Waiter.sTryUntilPredicate('Waiting for editor setup', () => seenSetup), - Waiter.sTryUntilPredicate('Waiting for editor init', () => seenInit), - Step.sync(() => { - Assertions.assertHtmlStructure('', '

Hello world

', editorInstance.getContent() as string); - Assertions.assertEq('An editor instance is registered', true, Global.tinymce.get('example_id') !== null); - }), - Step.sync(() => removeTinymceElement()), - Step.sync(() => { - Assertions.assertEq('The editor instance is removed', true, Global.tinymce.get('example_id') === null); - }) - ], success, failure); + makeTinymceElement({ + 'setup': 'customElementTinymceSetup', + 'on-init': 'customElementTinymceInit', + 'config': 'tinymceTestConfig', + 'id': 'example_id' + }, '

Hello world

'); + }); + }); + + after(() => { + delete Global.tinymceTestConfig; + removeTinymceElement(); + Assertions.assertEq('The editor instance is removed', true, Global.tinymce.get('example_id') === null); + deleteTinymce(); + }); + + it('Should load the editor and execute setup and init callbacks', () => { + Assertions.assertEq('Editor setup callback should be called', true, seenSetup); + Assertions.assertEq('Editor init callback should be called', true, seenInit); + Assertions.assertEq('An editor instance is registered', true, Global.tinymce.get('example_id') !== null); + Assertions.assertHtmlStructure('', '

Hello world

', editorInstance.getContent() as string); + Assertions.assertEq('An editor instance is registered', true, Global.tinymce.get('example_id') !== null); + }); }); \ No newline at end of file From b5e2bae4fd4613683fa9af9d951ea624c978199d Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Tue, 7 Apr 2026 13:53:10 +0930 Subject: [PATCH 12/29] Remove eslint errors --- src/test/ts/alien/Utils.ts | 3 ++- src/test/ts/browser/DisabledTest.ts | 10 ++++++---- src/test/ts/browser/LoadTest.ts | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/test/ts/alien/Utils.ts b/src/test/ts/alien/Utils.ts index 81f21cb..fa9a46d 100644 --- a/src/test/ts/alien/Utils.ts +++ b/src/test/ts/alien/Utils.ts @@ -1,6 +1,7 @@ import { Attribute, Remove, SelectorFilter, SugarElement } from '@ephox/sugar'; import { ScriptLoader } from 'src/main/ts/utils/ScriptLoader'; import { Arr, Strings, Optional, Fun } from '@ephox/katamari'; +// eslint-disable-next-line @tinymce/no-direct-imports import * as Globals from '@tinymce/miniature/lib/main/ts/loader/Globals'; import Editor from 'src/main/ts/component/Editor'; @@ -24,5 +25,5 @@ export const removeTinymceElement = () => { }; export const registerCustomElementIfNot = () => { - Optional.from(customElements.get('tinymce-editor')).fold(Editor, Fun.noop); + Optional.from(window.customElements.get('tinymce-editor')).fold(Editor, Fun.noop); }; \ No newline at end of file diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index 8081a1d..2b76c4a 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -16,8 +16,8 @@ describe('DisableTest', () => { registerCustomElementIfNot(); Global.tinymceTestConfig = { license_key: 'gpl' }; }); - - after(() => { + + after(() => { delete Global.tinymceTestConfig; }); @@ -49,13 +49,15 @@ describe('DisableTest', () => { context('When using with Tinymce < 7.6', () => { before(async () => { await VersionLoader.pLoadVersion('7.5.0'); - Assertions.assertEq('Tinymce 7.5.0 should be loaded', '7.5.0', TinyVer.getVersion(tinymce).major + '.' + TinyVer.getVersion(tinymce).minor + '.' + TinyVer.getVersion(tinymce).patch); + Assertions.assertEq('Tinymce 7.5.0 should be loaded', + '7.5.0', + TinyVer.getVersion(tinymce).major + '.' + TinyVer.getVersion(tinymce).minor + '.' + TinyVer.getVersion(tinymce).patch); }); after(() => { deleteTinymce(); }); - + it('Editor should be not be disabled when disabled attribute is present', async () => { const { editor } = await pCreateEditor(); Assertions.assertEq('Editor should be in design mode', true, editor.mode.get() === 'design'); diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index 8c434c0..94d0d7c 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -1,7 +1,7 @@ import { Assertions } from '@ephox/agar'; import { SugarElement, Attribute, SugarBody, Insert, TextContent } from '@ephox/sugar'; import { before, describe, after, it } from '@ephox/bedrock-client'; -import { Global } from '@ephox/katamari'; +import { Global } from '@ephox/katamari'; import { deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; import { VersionLoader } from '@tinymce/miniature'; From a94d177cbd99a341ba5cd87bfe9ece3b912729d1 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Tue, 7 Apr 2026 14:17:24 +0930 Subject: [PATCH 13/29] Fix timeout and refactor --- src/test/ts/alien/Utils.ts | 10 +++++ src/test/ts/browser/DisabledTest.ts | 63 ++++++++++++++--------------- src/test/ts/browser/LoadTest.ts | 13 +----- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/test/ts/alien/Utils.ts b/src/test/ts/alien/Utils.ts index fa9a46d..c15341a 100644 --- a/src/test/ts/alien/Utils.ts +++ b/src/test/ts/alien/Utils.ts @@ -26,4 +26,14 @@ export const removeTinymceElement = () => { export const registerCustomElementIfNot = () => { Optional.from(window.customElements.get('tinymce-editor')).fold(Editor, Fun.noop); +}; + +export const createTinymceElement = (attrs: Record, content?: string) => { + const ce = SugarElement.fromTag('tinymce-editor'); + Attribute.setAll(ce, attrs); + if (content) { + ce.dom.innerHTML = content; + } + document.body.appendChild(ce.dom); + return ce; }; \ No newline at end of file diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index 2b76c4a..387942c 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -3,7 +3,8 @@ import { before, describe, it, context, after, afterEach } from '@ephox/bedrock- import { Global } from '@ephox/katamari'; import type { TinyMCE, Editor as TinyMCEEditor } from 'tinymce'; import { VersionLoader, TinyVer } from '@tinymce/miniature'; -import { deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; +import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; +import { Attribute, SugarElement } from '@ephox/sugar'; type EditorElement = HTMLElement & { disabled?: boolean }; declare const tinymce: TinyMCE; @@ -22,9 +23,10 @@ describe('DisableTest', () => { }); const pCreateEditor = - (attrs: Record = {}): Promise<{ el: EditorElement; editor: TinyMCEEditor }> => new Promise((resolve) => { + (attrs: Record = {}): Promise<{ element: SugarElement; editor: TinyMCEEditor }> => new Promise((resolve) => { const setupFnName = nextId(); const initFnName = nextId(); + let tinymceEl: SugarElement; let editorInstance: any; Global[setupFnName] = (editor: any) => { @@ -32,18 +34,15 @@ describe('DisableTest', () => { }; Global[initFnName] = () => { - resolve({ el: el as EditorElement, editor: editorInstance }); + resolve({ element: tinymceEl, editor: editorInstance }); }; - const el = document.createElement('tinymce-editor'); - el.setAttribute('config', 'tinymceTestConfig'); - el.setAttribute('setup', setupFnName); - el.setAttribute('on-init', initFnName); - for (const [ key, value ] of Object.entries(attrs)) { - el.setAttribute(key, value); - } - - document.body.appendChild(el); + tinymceEl = createTinymceElement({ + 'setup': setupFnName, + 'on-init': initFnName, + 'config': 'tinymceTestConfig', + ...attrs + }); }); context('When using with Tinymce < 7.6', () => { @@ -82,47 +81,47 @@ describe('DisableTest', () => { const pWaitForDisabledStateChange = (editor: any): Promise => new Promise((resolve) => editor.once('DisabledStateChange', resolve)); - const assertDisabledState = (el: EditorElement, editor: TinyMCEEditor, expected: boolean) => { - const hasDisabledAtt = el.hasAttribute('disabled'); + const assertDisabledState = (el: SugarElement, editor: TinyMCEEditor, expected: boolean) => { + const hasDisabledAtt = Attribute.has(el, 'disabled'); Assertions.assertEq('Editor should be disabled', expected, editor.options.get('disabled')); Assertions.assertEq(`disabled attribute should be ${expected ? 'present' : 'absent'}`, expected, hasDisabledAtt); }; it('Editor should be disabled when disabled attribute is present', async () => { - const { el, editor } = await pCreateEditor({ disabled: '' }); - assertDisabledState(el, editor, true); + const { element, editor } = await pCreateEditor({ disabled: '' }); + assertDisabledState(element, editor, true); }); it('Editor is not disabled when disabled attribute is absent', async () => { - const { el, editor } = await pCreateEditor(); - assertDisabledState(el, editor, false); + const { element, editor } = await pCreateEditor(); + assertDisabledState(element, editor, false); }); it('Setting disabled attribute after init disables the editor', async () => { - const { el, editor } = await pCreateEditor(); - assertDisabledState(el, editor, false); - el.setAttribute('disabled', ''); + const { element, editor } = await pCreateEditor(); + assertDisabledState(element, editor, false); + Attribute.set(element, 'disabled', ''); await pWaitForDisabledStateChange(editor); - assertDisabledState(el, editor, true); + assertDisabledState(element, editor, true); }); it('Removing disabled attribute after init enables the editor', async () => { - const { el, editor } = await pCreateEditor({ disabled: '' }); - assertDisabledState(el, editor, true); - el.removeAttribute('disabled'); + const { element, editor } = await pCreateEditor({ disabled: '' }); + assertDisabledState(element, editor, true); + Attribute.remove(element, 'disabled'); await pWaitForDisabledStateChange(editor); - assertDisabledState(el, editor, false); + assertDisabledState(element, editor, false); }); it('Updating disabled property directly syncs editor option and attribute', async () => { - const { el, editor } = await pCreateEditor(); - Assertions.assertEq('disabled property should be false initially', false, el.disabled); - el.disabled = true; + const { element, editor } = await pCreateEditor(); + Assertions.assertEq('disabled property should be false initially', false, element.dom.disabled); + element.dom.disabled = true; await pWaitForDisabledStateChange(editor); - assertDisabledState(el, editor, true); - el.disabled = false; + assertDisabledState(element, editor, true); + element.dom.disabled = false; await pWaitForDisabledStateChange(editor); - assertDisabledState(el, editor, false); + assertDisabledState(element, editor, false); }); }); }); diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index 94d0d7c..a9d4451 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -1,18 +1,9 @@ import { Assertions } from '@ephox/agar'; -import { SugarElement, Attribute, SugarBody, Insert, TextContent } from '@ephox/sugar'; import { before, describe, after, it } from '@ephox/bedrock-client'; import { Global } from '@ephox/katamari'; -import { deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; +import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; import { VersionLoader } from '@tinymce/miniature'; -const makeTinymceElement = (attrs: Record, content: string) => { - const ce = SugarElement.fromTag('tinymce-editor'); - Attribute.set(ce, 'channel', '8'); - Attribute.setAll(ce, attrs); - TextContent.set(ce, content); - Insert.append(SugarBody.body(), ce); -}; - describe('LoadTest', () => { let seenSetup = false; let seenInit = false; @@ -32,7 +23,7 @@ describe('LoadTest', () => { seenInit = true; resolve({}); }; - makeTinymceElement({ + createTinymceElement({ 'setup': 'customElementTinymceSetup', 'on-init': 'customElementTinymceInit', 'config': 'tinymceTestConfig', From 631d8023589fb24f102bf685dc14c25b37828cc7 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Tue, 7 Apr 2026 14:22:25 +0930 Subject: [PATCH 14/29] Ignore pre-const lint error --- src/test/ts/browser/DisabledTest.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index 387942c..35bf27a 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -26,6 +26,7 @@ describe('DisableTest', () => { (attrs: Record = {}): Promise<{ element: SugarElement; editor: TinyMCEEditor }> => new Promise((resolve) => { const setupFnName = nextId(); const initFnName = nextId(); + // eslint-disable-next-line prefer-const let tinymceEl: SugarElement; let editorInstance: any; From 6bb424a88fdcbb7cff4c67e27fb418518a089f9d Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Tue, 7 Apr 2026 14:38:37 +0930 Subject: [PATCH 15/29] Move tinymce to dev --- package.json | 9 ++++----- yarn.lock | 16 ++++++++-------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 13b474d..13e885c 100644 --- a/package.json +++ b/package.json @@ -43,13 +43,12 @@ "eslint-plugin-prefer-arrow": "^1.2.3", "express": "^5.2.1", "rollup": "^4.24.0", - "tinymce": "^8", + "tinymce": "^8.4.0", + "tinymce-7.5.0": "npm:tinymce@7.5.0", + "tinymce-8": "npm:tinymce@8", "tsx": "^4.21.0", "typescript": "~5.9.2", "webpack": "^5.75.0" }, - "dependencies": { - "tinymce-7.5.0": "npm:tinymce@7.5.0", - "tinymce-8": "npm:tinymce@^8" - } + "dependencies": {} } diff --git a/yarn.lock b/yarn.lock index f380e74..145b846 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8274,15 +8274,15 @@ thunky@^1.0.2: resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-7.5.0.tgz#56388d314399c288a100df4aaf468153f29477f1" integrity sha512-A7iuQPIfeze5rO6bvnnPwP7TiWnPA9AGr8U/9ssLwrEG+FMYPzvLPt3RT8ktVn/wPSJkVBBSLCAZX2dAHb8YEA== -"tinymce-8@npm:tinymce@^8": - version "8.3.2" - resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-8.3.2.tgz#bfdba186b00d61598eafbc29cab778de7f8e1e33" - integrity sha512-iZ8aIUtrgGOw2AkukNf8spUM0LOzNLoCHRepwXQwWmHxP2TI5LzHjjG0SmXGxbya4EmoD5/pAox0ZXJfLO5DUw== +"tinymce-8@npm:tinymce@8": + version "8.4.0" + resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-8.4.0.tgz#403ea8418b48d6120f373bce2f9e4166bb844006" + integrity sha512-Q/0/iLycB7hgSkOBoRqfceOz/7Obs9zIo0DwTRuvrReLxb6qdz/1vI7aVJMcW2BAuW80QqZiTyYdVM2amBkqIg== -tinymce@^8: - version "8.3.2" - resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-8.3.2.tgz#bfdba186b00d61598eafbc29cab778de7f8e1e33" - integrity sha512-iZ8aIUtrgGOw2AkukNf8spUM0LOzNLoCHRepwXQwWmHxP2TI5LzHjjG0SmXGxbya4EmoD5/pAox0ZXJfLO5DUw== +tinymce@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-8.4.0.tgz#403ea8418b48d6120f373bce2f9e4166bb844006" + integrity sha512-Q/0/iLycB7hgSkOBoRqfceOz/7Obs9zIo0DwTRuvrReLxb6qdz/1vI7aVJMcW2BAuW80QqZiTyYdVM2amBkqIg== tinyrainbow@^1.2.0: version "1.2.0" From 001c1bbe2570a668cdff8753d97763cff1b24813 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Tue, 7 Apr 2026 14:44:47 +0930 Subject: [PATCH 16/29] Attempt to resolve a race condition --- src/test/ts/alien/Utils.ts | 2 +- src/test/ts/browser/LoadTest.ts | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/ts/alien/Utils.ts b/src/test/ts/alien/Utils.ts index c15341a..a6785f1 100644 --- a/src/test/ts/alien/Utils.ts +++ b/src/test/ts/alien/Utils.ts @@ -25,7 +25,7 @@ export const removeTinymceElement = () => { }; export const registerCustomElementIfNot = () => { - Optional.from(window.customElements.get('tinymce-editor')).fold(Editor, Fun.noop); + Optional.from(window.customElements?.get('tinymce-editor')).fold(Editor, Fun.noop); }; export const createTinymceElement = (attrs: Record, content?: string) => { diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index a9d4451..05f7b9d 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -35,7 +35,6 @@ describe('LoadTest', () => { after(() => { delete Global.tinymceTestConfig; removeTinymceElement(); - Assertions.assertEq('The editor instance is removed', true, Global.tinymce.get('example_id') === null); deleteTinymce(); }); @@ -43,7 +42,6 @@ describe('LoadTest', () => { Assertions.assertEq('Editor setup callback should be called', true, seenSetup); Assertions.assertEq('Editor init callback should be called', true, seenInit); Assertions.assertEq('An editor instance is registered', true, Global.tinymce.get('example_id') !== null); - Assertions.assertHtmlStructure('', '

Hello world

', editorInstance.getContent() as string); - Assertions.assertEq('An editor instance is registered', true, Global.tinymce.get('example_id') !== null); + Assertions.assertHtmlStructure('The editor has the correct content', '

Hello world

', editorInstance.getContent() as string); }); }); \ No newline at end of file From c8b9043671ec8c025afddb59ad698c35e805f86e Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Tue, 7 Apr 2026 15:03:03 +0930 Subject: [PATCH 17/29] Another go --- package.json | 4 +- src/test/ts/browser/LoadTest.ts | 31 +- yarn.lock | 648 ++++++++++++++++++++++++++------ 3 files changed, 547 insertions(+), 136 deletions(-) diff --git a/package.json b/package.json index 13e885c..46392f4 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,8 @@ "license": "MIT", "devDependencies": { "@ephox/agar": "^8.0.1", - "@ephox/bedrock-client": "^15.0.0", - "@ephox/bedrock-server": "^15.0.0", + "@ephox/bedrock-client": "^16.0.0", + "@ephox/bedrock-server": "^16.2.0", "@ephox/katamari": "^9.1.5", "@ephox/sugar": "^9.2.1", "@ephox/swag": "^4.6.0", diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index 05f7b9d..ed9a7d3 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -3,19 +3,27 @@ import { before, describe, after, it } from '@ephox/bedrock-client'; import { Global } from '@ephox/katamari'; import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; import { VersionLoader } from '@tinymce/miniature'; +import { Editor } from 'tinymce'; describe('LoadTest', () => { - let seenSetup = false; - let seenInit = false; - let editorInstance: any; - before(async () => { await VersionLoader.pLoadVersion('8'); registerCustomElementIfNot(); Global.tinymceTestConfig = { license_key: 'gpl' }; + }); + + after(() => { + delete Global.tinymceTestConfig; + deleteTinymce(); + }); + + it('Should load the editor and execute setup and init callbacks', async () => { + let seenSetup = false; + let seenInit = false; + let editorInstance: Editor | undefined; await new Promise((resolve) => { - Global.customElementTinymceSetup = (editor: any) => { + Global.customElementTinymceSetup = (editor: Editor) => { seenSetup = true; editorInstance = editor; }; @@ -30,18 +38,13 @@ describe('LoadTest', () => { 'id': 'example_id' }, '

Hello world

'); }); - }); - after(() => { - delete Global.tinymceTestConfig; - removeTinymceElement(); - deleteTinymce(); - }); - - it('Should load the editor and execute setup and init callbacks', () => { Assertions.assertEq('Editor setup callback should be called', true, seenSetup); Assertions.assertEq('Editor init callback should be called', true, seenInit); Assertions.assertEq('An editor instance is registered', true, Global.tinymce.get('example_id') !== null); - Assertions.assertHtmlStructure('The editor has the correct content', '

Hello world

', editorInstance.getContent() as string); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + Assertions.assertHtmlStructure('The editor has the correct content', '

Hello world

', editorInstance!.getContent() as string); + + removeTinymceElement(); }); }); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 145b846..adeb704 100644 --- a/yarn.lock +++ b/yarn.lock @@ -603,6 +603,14 @@ "@emnapi/wasi-threads" "1.1.0" tslib "^2.4.0" +"@emnapi/core@^1.5.0": + version "1.9.2" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.9.2.tgz#3870265ecffc7352d01ead62d8d83d8358a2d034" + integrity sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA== + dependencies: + "@emnapi/wasi-threads" "1.2.1" + tslib "^2.4.0" + "@emnapi/runtime@^1.4.3": version "1.5.0" resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.5.0.tgz#9aebfcb9b17195dce3ab53c86787a6b7d058db73" @@ -610,6 +618,13 @@ dependencies: tslib "^2.4.0" +"@emnapi/runtime@^1.5.0": + version "1.9.2" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.9.2.tgz#8b469a3db160817cadb1de9050211a9d1ea84fa2" + integrity sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw== + dependencies: + tslib "^2.4.0" + "@emnapi/wasi-threads@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz#60b2102fddc9ccb78607e4a3cf8403ea69be41bf" @@ -617,6 +632,13 @@ dependencies: tslib "^2.4.0" +"@emnapi/wasi-threads@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz#28fed21a1ba1ce797c44a070abc94d42f3ae8548" + integrity sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w== + dependencies: + tslib "^2.4.0" + "@ephox/agar@^8.0.0", "@ephox/agar@^8.0.1": version "8.0.1" resolved "https://registry.yarnpkg.com/@ephox/agar/-/agar-8.0.1.tgz#6772ed7abd90adee5b08bc6f8baf0cb4f22b8d1c" @@ -639,12 +661,12 @@ "@ephox/bedrock-common" "^13.0.0" "@ephox/dispute" "^1.0.3" -"@ephox/bedrock-client@^15.0.0": - version "15.0.0" - resolved "https://registry.yarnpkg.com/@ephox/bedrock-client/-/bedrock-client-15.0.0.tgz#a2ae8ec5be2b1ff7a4843c32da4879590514d0ed" - integrity sha512-jO1REPlAokzLScK4m9Wcykw6SC5+Bv9pBk3LAjEvNgfxydSlgl2ReYTSsL0ZvQRJguzzpE1T7XD3kOfvtRX0FQ== +"@ephox/bedrock-client@^16.0.0": + version "16.0.0" + resolved "https://registry.yarnpkg.com/@ephox/bedrock-client/-/bedrock-client-16.0.0.tgz#5a7b020b74efea052dc77eb8aea65af28de756cd" + integrity sha512-fsopXp+IRcT1u5mvQrjtPxLr7cRvTbFTiWyjG4gFVGc0iA2Dhmk9fpeEQX5VELi4yxG7xNoVBjnSccjumvLe/Q== dependencies: - "@ephox/bedrock-common" "^15.0.0" + "@ephox/bedrock-common" "^16.0.0" "@ephox/dispute" "^1.0.3" "@ephox/bedrock-common@11 || 12 || 13", "@ephox/bedrock-common@^13.0.0": @@ -654,33 +676,35 @@ dependencies: diff "^5.0.0" -"@ephox/bedrock-common@^15.0.0": - version "15.0.0" - resolved "https://registry.yarnpkg.com/@ephox/bedrock-common/-/bedrock-common-15.0.0.tgz#988020addd4c11922e906dfef26547ec72384797" - integrity sha512-uGR1Oaksv9d9gDEJra2HB/HUCAdcBTiBfKYWEVvu7XofU4lHpoUFlX+7bnDi9h6N0CZ67bEAeqWhTwrN/2dFKw== +"@ephox/bedrock-common@^16.0.0": + version "16.0.0" + resolved "https://registry.yarnpkg.com/@ephox/bedrock-common/-/bedrock-common-16.0.0.tgz#ff02afdf7df417ed530250ca486d5ca253d63140" + integrity sha512-G70iHnw30n1IMISEJTjBGxZU+BmmlvIBJ3MB0pczGpr9fokrW+THfy69ASeMjx2JZ2KhM/HvvbPTyH7OYDk3Zg== dependencies: diff "^5.0.0" -"@ephox/bedrock-runner@^15.0.2": - version "15.0.2" - resolved "https://registry.yarnpkg.com/@ephox/bedrock-runner/-/bedrock-runner-15.0.2.tgz#8f4a1a00861b8219f3db60ccf5a40b2e9fb1e2ea" - integrity sha512-a5rZy4WXkTWHBGn8CBqmZACCrdmNskQzriuu+u8GWtmmJqdrdr6pnHlNqiojzlo1VDM3ptPnUxADGwivsaRxJw== +"@ephox/bedrock-runner@^16.0.0": + version "16.0.0" + resolved "https://registry.yarnpkg.com/@ephox/bedrock-runner/-/bedrock-runner-16.0.0.tgz#36540677009844176fd6f93f71a15b3ddd2af098" + integrity sha512-wXZwe5FHsl/wO+xfwaB9GhPEl5wXHF9IT+JpvmzbwDL/gGS6rD4Ytvpx5HM34fekTWG4tHOY1I5EAFCZG0JiMA== dependencies: - "@ephox/bedrock-common" "^15.0.0" + "@ephox/bedrock-common" "^16.0.0" jquery "^3.4.1" querystringify "^2.1.1" -"@ephox/bedrock-server@^15.0.0": - version "15.0.2" - resolved "https://registry.yarnpkg.com/@ephox/bedrock-server/-/bedrock-server-15.0.2.tgz#3ae3fab478049aff74717de8c4418611f3a41bcb" - integrity sha512-a0iu8h/dsGJwHmg8wntAaKJ+K6EV5YKTBvlu9ezxvZM7YAyfZCvSRd89a3hmXqVI6H+XzRekDxOVazZXsUeBSQ== +"@ephox/bedrock-server@^16.2.0": + version "16.2.0" + resolved "https://registry.yarnpkg.com/@ephox/bedrock-server/-/bedrock-server-16.2.0.tgz#90fca612241130af0e3f3eac25dcbe9e4b56b232" + integrity sha512-WDgs5iZzdpH6HYiWjqSDG3nj5Q2y/xeVeWQccmhMbPtk/IUX7l5mInFyj5dass1oR4/NFnNzttHK7QgKrzR8og== dependencies: "@aws-sdk/client-device-farm" "^3.354.0" - "@ephox/bedrock-client" "^15.0.0" - "@ephox/bedrock-common" "^15.0.0" - "@ephox/bedrock-runner" "^15.0.2" + "@ephox/bedrock-client" "^16.0.0" + "@ephox/bedrock-common" "^16.0.0" + "@ephox/bedrock-runner" "^16.0.0" "@jsdevtools/coverage-istanbul-loader" "^3.0.5" "@lambdatest/node-tunnel" "^4.0.4" + "@rspack/core" "^1.7.9" + "@rspack/dev-server" "^1.2.1" "@wdio/globals" "^8.14.1" async "^3.0.0" chalk "^4.1.1" @@ -702,11 +726,10 @@ mkdirp "^1.0.0" portfinder "^1.0.25" recursive-readdir-sync "^1.0.6" - rollup "^2.0.0" - rollup-plugin-typescript2 "^0.24.0" serve-static "^1.10.2" source-map-loader "^3.0.0" split2 "^4.2.0" + ts-checker-rspack-plugin "^1.3.0" ts-loader "^9.0.0" tsconfig-paths-webpack-plugin "^3.2.0" webdriverio "^8.0.0" @@ -1134,21 +1157,107 @@ merge-source-map "^1.1.0" schema-utils "^2.7.0" +"@jsonjoy.com/base64@17.67.0": + version "17.67.0" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/base64/-/base64-17.67.0.tgz#7eeda3cb41138d77a90408fd2e42b2aba10576d7" + integrity sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw== + "@jsonjoy.com/base64@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@jsonjoy.com/base64/-/base64-1.1.2.tgz#cf8ea9dcb849b81c95f14fc0aaa151c6b54d2578" integrity sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA== +"@jsonjoy.com/buffers@17.67.0", "@jsonjoy.com/buffers@^17.65.0": + version "17.67.0" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/buffers/-/buffers-17.67.0.tgz#5c58dbcdeea8824ce296bd1cfce006c2eb167b3d" + integrity sha512-tfExRpYxBvi32vPs9ZHaTjSP4fHAfzSmcahOfNxtvGHcyJel+aibkPlGeBB+7AoC6hL7lXIE++8okecBxx7lcw== + "@jsonjoy.com/buffers@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@jsonjoy.com/buffers/-/buffers-1.0.0.tgz#ade6895b7d3883d70f87b5743efaa12c71dfef7a" integrity sha512-NDigYR3PHqCnQLXYyoLbnEdzMMvzeiCWo1KOut7Q0CoIqg9tUAPKJ1iq/2nFhc5kZtexzutNY0LFjdwWL3Dw3Q== +"@jsonjoy.com/codegen@17.67.0": + version "17.67.0" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/codegen/-/codegen-17.67.0.tgz#3635fd8769d77e19b75dc5574bc9756019b2e591" + integrity sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q== + "@jsonjoy.com/codegen@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz#5c23f796c47675f166d23b948cdb889184b93207" integrity sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g== +"@jsonjoy.com/fs-core@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/fs-core/-/fs-core-4.57.1.tgz#03c0d7a7bf96030376f7194b9c5c815cb7bf71d7" + integrity sha512-YrEi/ZPmgc+GfdO0esBF04qv8boK9Dg9WpRQw/+vM8Qt3nnVIJWIa8HwZ/LXVZ0DB11XUROM8El/7yYTJX+WtA== + dependencies: + "@jsonjoy.com/fs-node-builtins" "4.57.1" + "@jsonjoy.com/fs-node-utils" "4.57.1" + thingies "^2.5.0" + +"@jsonjoy.com/fs-fsa@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/fs-fsa/-/fs-fsa-4.57.1.tgz#87ffa6cd695b363b58b9ccddc87a66212a1b25fd" + integrity sha512-ooEPvSW/HQDivPDPZMibHGKZf/QS4WRir1czGZmXmp3MsQqLECZEpN0JobrD8iV9BzsuwdIv+PxtWX9WpPLsIA== + dependencies: + "@jsonjoy.com/fs-core" "4.57.1" + "@jsonjoy.com/fs-node-builtins" "4.57.1" + "@jsonjoy.com/fs-node-utils" "4.57.1" + thingies "^2.5.0" + +"@jsonjoy.com/fs-node-builtins@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/fs-node-builtins/-/fs-node-builtins-4.57.1.tgz#a6793654d6ffaead81f040e3becc063a265deb7c" + integrity sha512-XHkFKQ5GSH3uxm8c3ZYXVrexGdscpWKIcMWKFQpMpMJc8gA3AwOMBJXJlgpdJqmrhPyQXxaY9nbkNeYpacC0Og== + +"@jsonjoy.com/fs-node-to-fsa@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/fs-node-to-fsa/-/fs-node-to-fsa-4.57.1.tgz#9011872df67ac302f0b0f7fd13502993a026c306" + integrity sha512-pqGHyWWzNck4jRfaGV39hkqpY5QjRUQ/nRbNT7FYbBa0xf4bDG+TE1Gt2KWZrSkrkZZDE3qZUjYMbjwSliX6pg== + dependencies: + "@jsonjoy.com/fs-fsa" "4.57.1" + "@jsonjoy.com/fs-node-builtins" "4.57.1" + "@jsonjoy.com/fs-node-utils" "4.57.1" + +"@jsonjoy.com/fs-node-utils@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/fs-node-utils/-/fs-node-utils-4.57.1.tgz#e9d030b676f7f4074eb90a42927bac708dc4312c" + integrity sha512-vp+7ZzIB8v43G+GLXTS4oDUSQmhAsRz532QmmWBbdYA20s465JvwhkSFvX9cVTqRRAQg+vZ7zWDaIEh0lFe2gw== + dependencies: + "@jsonjoy.com/fs-node-builtins" "4.57.1" + +"@jsonjoy.com/fs-node@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/fs-node/-/fs-node-4.57.1.tgz#3dae969fe02d9450f5dfc7c12bfe3b859cb1038e" + integrity sha512-3YaKhP8gXEKN+2O49GLNfNb5l2gbnCFHyAaybbA2JkkbQP3dpdef7WcUaHAulg/c5Dg4VncHsA3NWAUSZMR5KQ== + dependencies: + "@jsonjoy.com/fs-core" "4.57.1" + "@jsonjoy.com/fs-node-builtins" "4.57.1" + "@jsonjoy.com/fs-node-utils" "4.57.1" + "@jsonjoy.com/fs-print" "4.57.1" + "@jsonjoy.com/fs-snapshot" "4.57.1" + glob-to-regex.js "^1.0.0" + thingies "^2.5.0" + +"@jsonjoy.com/fs-print@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/fs-print/-/fs-print-4.57.1.tgz#59359be175145cd44e83f7cdfba06cb1fed23313" + integrity sha512-Ynct7ZJmfk6qoXDOKfpovNA36ITUx8rChLmRQtW08J73VOiuNsU8PB6d/Xs7fxJC2ohWR3a5AqyjmLojfrw5yw== + dependencies: + "@jsonjoy.com/fs-node-utils" "4.57.1" + tree-dump "^1.1.0" + +"@jsonjoy.com/fs-snapshot@4.57.1": + version "4.57.1" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/fs-snapshot/-/fs-snapshot-4.57.1.tgz#54cd9073a97e290a1650070f2ee9529a0accdb93" + integrity sha512-/oG8xBNFMbDXTq9J7vepSA1kerS5vpgd3p5QZSPd+nX59uwodGJftI51gDYyHRpP57P3WCQf7LHtBYPqwUg2Bg== + dependencies: + "@jsonjoy.com/buffers" "^17.65.0" + "@jsonjoy.com/fs-node-utils" "4.57.1" + "@jsonjoy.com/json-pack" "^17.65.0" + "@jsonjoy.com/util" "^17.65.0" + "@jsonjoy.com/json-pack@^1.11.0": version "1.14.0" resolved "https://registry.yarnpkg.com/@jsonjoy.com/json-pack/-/json-pack-1.14.0.tgz#eda5255ccdaeafb3aa811ff1ae4814790b958b4f" @@ -1162,6 +1271,27 @@ hyperdyperid "^1.2.0" thingies "^2.5.0" +"@jsonjoy.com/json-pack@^17.65.0": + version "17.67.0" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/json-pack/-/json-pack-17.67.0.tgz#8dd8ff65dd999c5d4d26df46c63915c7bdec093a" + integrity sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w== + dependencies: + "@jsonjoy.com/base64" "17.67.0" + "@jsonjoy.com/buffers" "17.67.0" + "@jsonjoy.com/codegen" "17.67.0" + "@jsonjoy.com/json-pointer" "17.67.0" + "@jsonjoy.com/util" "17.67.0" + hyperdyperid "^1.2.0" + thingies "^2.5.0" + tree-dump "^1.1.0" + +"@jsonjoy.com/json-pointer@17.67.0": + version "17.67.0" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/json-pointer/-/json-pointer-17.67.0.tgz#74439573dc046e0c9a3a552fb94b391bc75313b8" + integrity sha512-+iqOFInH+QZGmSuaybBUNdh7yvNrXvqR+h3wjXm0N/3JK1EyyFAeGJvqnmQL61d1ARLlk/wJdFKSL+LHJ1eaUA== + dependencies: + "@jsonjoy.com/util" "17.67.0" + "@jsonjoy.com/json-pointer@^1.0.1": version "1.0.2" resolved "https://registry.yarnpkg.com/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz#049cb530ac24e84cba08590c5e36b431c4843408" @@ -1170,6 +1300,14 @@ "@jsonjoy.com/codegen" "^1.0.0" "@jsonjoy.com/util" "^1.9.0" +"@jsonjoy.com/util@17.67.0", "@jsonjoy.com/util@^17.65.0": + version "17.67.0" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/util/-/util-17.67.0.tgz#7c4288fc3808233e55c7610101e7bb4590cddd3f" + integrity sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew== + dependencies: + "@jsonjoy.com/buffers" "17.67.0" + "@jsonjoy.com/codegen" "17.67.0" + "@jsonjoy.com/util@^1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@jsonjoy.com/util/-/util-1.9.0.tgz#7ee95586aed0a766b746cd8d8363e336c3c47c46" @@ -1206,6 +1344,58 @@ resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz#4fc56c15c580b9adb7dc3c333a134e540b44bfb1" integrity sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw== +"@module-federation/error-codes@0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@module-federation/error-codes/-/error-codes-0.22.0.tgz#31ccc990dc240d73912ba7bd001f7e35ac751992" + integrity sha512-xF9SjnEy7vTdx+xekjPCV5cIHOGCkdn3pIxo9vU7gEZMIw0SvAEdsy6Uh17xaCpm8V0FWvR0SZoK9Ik6jGOaug== + +"@module-federation/runtime-core@0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@module-federation/runtime-core/-/runtime-core-0.22.0.tgz#7321ec792bb7d1d22bee6162ec43564b769d2a3c" + integrity sha512-GR1TcD6/s7zqItfhC87zAp30PqzvceoeDGYTgF3Vx2TXvsfDrhP6Qw9T4vudDQL3uJRne6t7CzdT29YyVxlgIA== + dependencies: + "@module-federation/error-codes" "0.22.0" + "@module-federation/sdk" "0.22.0" + +"@module-federation/runtime-tools@0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@module-federation/runtime-tools/-/runtime-tools-0.22.0.tgz#36f2a7cb267af208a9d1a237fe9a71b4bf31431e" + integrity sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA== + dependencies: + "@module-federation/runtime" "0.22.0" + "@module-federation/webpack-bundler-runtime" "0.22.0" + +"@module-federation/runtime@0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@module-federation/runtime/-/runtime-0.22.0.tgz#f789c9ef40d846d110711c8221ecc0ad938d43d8" + integrity sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA== + dependencies: + "@module-federation/error-codes" "0.22.0" + "@module-federation/runtime-core" "0.22.0" + "@module-federation/sdk" "0.22.0" + +"@module-federation/sdk@0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@module-federation/sdk/-/sdk-0.22.0.tgz#6ad4c1de85a900c3c80ff26cb87cce253e3a2770" + integrity sha512-x4aFNBKn2KVQRuNVC5A7SnrSCSqyfIWmm1DvubjbO9iKFe7ith5niw8dqSFBekYBg2Fwy+eMg4sEFNVvCAdo6g== + +"@module-federation/webpack-bundler-runtime@0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.22.0.tgz#dcbe8f972d722fe278e6a7c21988d4bee53d401d" + integrity sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA== + dependencies: + "@module-federation/runtime" "0.22.0" + "@module-federation/sdk" "0.22.0" + +"@napi-rs/wasm-runtime@1.0.7": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz#dcfea99a75f06209a235f3d941e3460a51e9b14c" + integrity sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw== + dependencies: + "@emnapi/core" "^1.5.0" + "@emnapi/runtime" "^1.5.0" + "@tybys/wasm-util" "^0.10.1" + "@napi-rs/wasm-runtime@^0.2.11": version "0.2.12" resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz#3e78a8b96e6c33a6c517e1894efbd5385a7cb6f2" @@ -1376,6 +1566,122 @@ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.0.tgz#79bc6c361bd80134402274e7c4a6bb36c88d50c2" integrity sha512-6iKDCVSIUQ8jPMoIV0OytRKniaYyy5EbY/RRydmLW8ZR3cEBhxbWl5ro0rkUNe0ef6sScvhbY79HrjRm8i3vDQ== +"@rspack/binding-darwin-arm64@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.7.11.tgz#ea43ac25a9ff99a9faf6c820f5d174a32974e95c" + integrity sha512-oduECiZVqbO5zlVw+q7Vy65sJFth99fWPTyucwvLJJtJkPL5n17Uiql2cYP6Ijn0pkqtf1SXgK8WjiKLG5bIig== + +"@rspack/binding-darwin-x64@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.7.11.tgz#5c724d91559d642d4a5e6aa4ed380c30bd0f64c0" + integrity sha512-a1+TtTE9ap6RalgFi7FGIgkJP6O4Vy6ctv+9WGJy53E4kuqHR0RygzaiVxCI/GMc/vBT9vY23hyrpWb3d1vtXA== + +"@rspack/binding-linux-arm64-gnu@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.7.11.tgz#429119939bbe9d51a72caf99cffb8febe0f870fe" + integrity sha512-P0QrGRPbTWu6RKWfN0bDtbnEps3rXH0MWIMreZABoUrVmNQKtXR6e73J3ub6a+di5s2+K0M2LJ9Bh2/H4UsDUA== + +"@rspack/binding-linux-arm64-musl@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.7.11.tgz#d939b8c2c5bf35380d3c860402f7063031ef469a" + integrity sha512-6ky7R43VMjWwmx3Yx7Jl7faLBBMAgMDt+/bN35RgwjiPgsIByz65EwytUVuW9rikB43BGHvA/eqlnjLrUzNBqw== + +"@rspack/binding-linux-x64-gnu@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.7.11.tgz#03567317a7e8cfc62d994dcf9683f932fd22054a" + integrity sha512-cuOJMfCOvb2Wgsry5enXJ3iT1FGUjdPqtGUBVupQlEG4ntSYsQ2PtF4wIDVasR3wdxC5nQbipOrDiN/u6fYsdQ== + +"@rspack/binding-linux-x64-musl@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.7.11.tgz#d93c93ea796eae1572b2353a50d58cc6218c53b6" + integrity sha512-CoK37hva4AmHGh3VCsQXmGr40L36m1/AdnN5LEjUX6kx5rEH7/1nEBN6Ii72pejqDVvk9anEROmPDiPw10tpFg== + +"@rspack/binding-wasm32-wasi@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.7.11.tgz#c90235032fb14de50baf535592069923c1308f4e" + integrity sha512-OtrmnPUVJMxjNa3eDMfHyPdtlLRmmp/aIm0fQHlAOATbZvlGm12q7rhPW5BXTu1yh+1rQ1/uqvz+SzKEZXuJaQ== + dependencies: + "@napi-rs/wasm-runtime" "1.0.7" + +"@rspack/binding-win32-arm64-msvc@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.7.11.tgz#0afcfde6a77cdf6fa6a85de4f8a39b94a593aab2" + integrity sha512-lObFW6e5lCWNgTBNwT//yiEDbsxm9QG4BYUojqeXxothuzJ/L6ibXz6+gLMvbOvLGV3nKgkXmx8GvT9WDKR0mA== + +"@rspack/binding-win32-ia32-msvc@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.7.11.tgz#46606834538e84cd0f95f19089695ab122d69586" + integrity sha512-0pYGnZd8PPqNR68zQ8skamqNAXEA1sUfXuAdYcknIIRq2wsbiwFzIc0Pov1cIfHYab37G7sSIPBiOUdOWF5Ivw== + +"@rspack/binding-win32-x64-msvc@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.7.11.tgz#e486a33fc1227ec9cbd70439ef1b32ead1faec68" + integrity sha512-EeQXayoQk/uBkI3pdoXfQBXNIUrADq56L3s/DFyM2pJeUDrWmhfIw2UFIGkYPTMSCo8F2JcdcGM32FGJrSnU0Q== + +"@rspack/binding@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@rspack/binding/-/binding-1.7.11.tgz#30f3e87242d9dcb3744edc22752cf24a9ceb4d61" + integrity sha512-2MGdy2s2HimsDT444Bp5XnALzNRxuBNc7y0JzyuqKbHBywd4x2NeXyhWXXoxufaCFu5PBc9Qq9jyfjW2Aeh06Q== + optionalDependencies: + "@rspack/binding-darwin-arm64" "1.7.11" + "@rspack/binding-darwin-x64" "1.7.11" + "@rspack/binding-linux-arm64-gnu" "1.7.11" + "@rspack/binding-linux-arm64-musl" "1.7.11" + "@rspack/binding-linux-x64-gnu" "1.7.11" + "@rspack/binding-linux-x64-musl" "1.7.11" + "@rspack/binding-wasm32-wasi" "1.7.11" + "@rspack/binding-win32-arm64-msvc" "1.7.11" + "@rspack/binding-win32-ia32-msvc" "1.7.11" + "@rspack/binding-win32-x64-msvc" "1.7.11" + +"@rspack/core@^1.7.9": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@rspack/core/-/core-1.7.11.tgz#8d7d77db3b71332afd22a9c90904fe18a6832e2c" + integrity sha512-rsD9b+Khmot5DwCMiB3cqTQo53ioPG3M/A7BySu8+0+RS7GCxKm+Z+mtsjtG/vsu4Tn2tcqCdZtA3pgLoJB+ew== + dependencies: + "@module-federation/runtime-tools" "0.22.0" + "@rspack/binding" "1.7.11" + "@rspack/lite-tapable" "1.1.0" + +"@rspack/dev-server@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@rspack/dev-server/-/dev-server-1.2.1.tgz#008425971eeb4b4cf063d934151f5e4f9fbbbcec" + integrity sha512-e/ARvskYn2Qdd02qLvc0i6H9BnOmzP0xGHS2XCr7GZ3t2k5uC5ZlLkeN1iEebU0FkAW+6ot89NahFo3nupKuww== + dependencies: + "@types/bonjour" "^3.5.13" + "@types/connect-history-api-fallback" "^1.5.4" + "@types/express" "^4.17.25" + "@types/express-serve-static-core" "^4.17.21" + "@types/serve-index" "^1.9.4" + "@types/serve-static" "^1.15.5" + "@types/sockjs" "^0.3.36" + "@types/ws" "^8.5.10" + ansi-html-community "^0.0.8" + bonjour-service "^1.2.1" + chokidar "^3.6.0" + colorette "^2.0.10" + compression "^1.8.1" + connect-history-api-fallback "^2.0.0" + express "^4.22.1" + graceful-fs "^4.2.6" + http-proxy-middleware "^2.0.9" + ipaddr.js "^2.1.0" + launch-editor "^2.6.1" + open "^10.0.3" + p-retry "^6.2.0" + schema-utils "^4.2.0" + selfsigned "^2.4.1" + serve-index "^1.9.1" + sockjs "^0.3.24" + spdy "^4.0.2" + webpack-dev-middleware "^7.4.2" + ws "^8.18.0" + +"@rspack/lite-tapable@1.1.0", "@rspack/lite-tapable@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@rspack/lite-tapable/-/lite-tapable-1.1.0.tgz#3cfdafeed01078e116bd4f191b684c8b484de425" + integrity sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw== + "@rtsao/scc@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" @@ -1858,7 +2164,7 @@ resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c" integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA== -"@tybys/wasm-util@^0.10.0": +"@tybys/wasm-util@^0.10.0", "@tybys/wasm-util@^0.10.1": version "0.10.1" resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz#ecddd3205cf1e2d5274649ff0eedd2991ed7f414" integrity sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg== @@ -1955,6 +2261,16 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/express@^4.17.25": + version "4.17.25" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.25.tgz#070c8c73a6fee6936d65c195dbbfb7da5026649b" + integrity sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "^1" + "@types/http-cache-semantics@^4.0.2": version "4.0.4" resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" @@ -2060,6 +2376,14 @@ "@types/mime" "^1" "@types/node" "*" +"@types/send@<1": + version "0.17.6" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.6.tgz#aeb5385be62ff58a52cd5459daa509ae91651d25" + integrity sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + "@types/serve-index@^1.9.4": version "1.9.4" resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.4.tgz#e6ae13d5053cb06ed36392110b4f9a49ac4ec898" @@ -2076,6 +2400,15 @@ "@types/node" "*" "@types/send" "*" +"@types/serve-static@^1": + version "1.15.10" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.10.tgz#768169145a778f8f5dfcb6360aead414a3994fee" + integrity sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw== + dependencies: + "@types/http-errors" "*" + "@types/node" "*" + "@types/send" "<1" + "@types/sizzle@^2.3.3": version "2.3.8" resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.8.tgz#518609aefb797da19bf222feb199e8f653ff7627" @@ -3031,6 +3364,24 @@ body-parser@^2.2.1: raw-body "^3.0.1" type-is "^2.0.1" +body-parser@~1.20.3: + version "1.20.4" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.4.tgz#f8e20f4d06ca8a50a71ed329c15dccad1cdc547f" + integrity sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA== + dependencies: + bytes "~3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "~1.2.0" + http-errors "~2.0.1" + iconv-lite "~0.4.24" + on-finished "~2.4.1" + qs "~6.14.0" + raw-body "~2.5.3" + type-is "~1.6.18" + unpipe "~1.0.0" + bonjour-service@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.3.0.tgz#80d867430b5a0da64e82a8047fc1e355bdb71722" @@ -3369,11 +3720,6 @@ comment-parser@1.4.1, comment-parser@^1.4.0, comment-parser@^1.4.1: resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.4.1.tgz#bdafead37961ac079be11eb7ec65c4d021eaf9cc" integrity sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg== -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== - compress-commons@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-6.0.2.tgz#26d31251a66b9d6ba23a84064ecd3a6a71d2609e" @@ -3392,7 +3738,7 @@ compressible@~2.0.18: dependencies: mime-db ">= 1.43.0 < 2" -compression@^1.7.4: +compression@^1.7.4, compression@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/compression/-/compression-1.8.1.tgz#4a45d909ac16509195a9a28bd91094889c180d79" integrity sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w== @@ -3415,7 +3761,7 @@ connect-history-api-fallback@^2.0.0: resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8" integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA== -content-disposition@0.5.4: +content-disposition@0.5.4, content-disposition@~0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== @@ -3454,12 +3800,17 @@ cookie-signature@^1.2.1: resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.2.tgz#57c7fc3cc293acab9fec54d73e15690ebe4a1793" integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg== +cookie-signature@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.7.tgz#ab5dd7ab757c54e60f37ef6550f481c426d10454" + integrity sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA== + cookie@0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9" integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== -cookie@^0.7.1: +cookie@^0.7.1, cookie@~0.7.1: version "0.7.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== @@ -3726,7 +4077,7 @@ depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== -destroy@1.2.0: +destroy@1.2.0, destroy@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== @@ -4357,11 +4708,6 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== -estree-walker@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" - integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== - esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -4466,6 +4812,43 @@ express@^4.21.2: utils-merge "1.0.1" vary "~1.1.2" +express@^4.22.1: + version "4.22.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.22.1.tgz#1de23a09745a4fffdb39247b344bb5eaff382069" + integrity sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "~1.20.3" + content-disposition "~0.5.4" + content-type "~1.0.4" + cookie "~0.7.1" + cookie-signature "~1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~2.0.0" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.3.1" + fresh "~0.5.2" + http-errors "~2.0.0" + merge-descriptors "1.0.3" + methods "~1.1.2" + on-finished "~2.4.1" + parseurl "~1.3.3" + path-to-regexp "~0.1.12" + proxy-addr "~2.0.7" + qs "~6.14.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "~0.19.0" + serve-static "~1.16.2" + setprototypeof "1.2.0" + statuses "~2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + express@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/express/-/express-5.2.1.tgz#8f21d15b6d327f92b4794ecf8cb08a72f956ac04" @@ -4646,14 +5029,18 @@ finalhandler@^2.1.0: parseurl "^1.3.3" statuses "^2.0.1" -find-cache-dir@^3.0.0: - version "3.3.2" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" - integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== +finalhandler@~1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.2.tgz#1ebc2228fc7673aac4a472c310cc05b77d852b88" + integrity sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg== dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" + debug "2.6.9" + encodeurl "~2.0.0" + escape-html "~1.0.3" + on-finished "~2.4.1" + parseurl "~1.3.3" + statuses "~2.0.2" + unpipe "~1.0.0" find-replace@^3.0.0: version "3.0.0" @@ -4662,7 +5049,7 @@ find-replace@^3.0.0: dependencies: array-back "^3.0.1" -find-up@^4.0.0, find-up@^4.1.0: +find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== @@ -4810,7 +5197,7 @@ fp-ts@^2.12.3: resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.16.9.tgz#99628fc5e0bb3b432c4a16d8f4455247380bae8a" integrity sha512-+I2+FnVB+tVaxcYyQkHUq7ZdKScaBlX53A41mxQtpIccsfyv8PzdzP7fzp2AY832T4aoK6UZ5WRX/ebGd8uZuQ== -fresh@0.5.2, fresh@^0.5.2: +fresh@0.5.2, fresh@^0.5.2, fresh@~0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== @@ -4820,15 +5207,6 @@ fresh@^2.0.0: resolved "https://registry.yarnpkg.com/fresh/-/fresh-2.0.0.tgz#8dd7df6a1b3a1b3a5cf186c05a5dd267622635a4" integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A== -fs-extra@8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-extra@^10.0.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" @@ -5006,6 +5384,11 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" +glob-to-regex.js@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz#2b323728271d133830850e32311f40766c5f6413" + integrity sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ== + glob-to-regex.js@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/glob-to-regex.js/-/glob-to-regex.js-1.0.1.tgz#f71cc9cb8441471a9318626160bc8a35e1306b21" @@ -5321,7 +5704,7 @@ http-errors@~1.6.2: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" -http-errors@~2.0.1: +http-errors@~2.0.0, http-errors@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.1.tgz#36d2f65bc909c8790018dd36fb4d93da6caae06b" integrity sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ== @@ -5394,7 +5777,7 @@ hyperdyperid@^1.2.0: resolved "https://registry.yarnpkg.com/hyperdyperid/-/hyperdyperid-1.2.0.tgz#59668d323ada92228d2a869d3e474d5a33b69e6b" integrity sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A== -iconv-lite@0.4.24: +iconv-lite@0.4.24, iconv-lite@~0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -5991,13 +6374,6 @@ json5@^2.1.2, json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== - optionalDependencies: - graceful-fs "^4.1.6" - jsonfile@^6.0.1: version "6.2.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.2.0.tgz#7c265bd1b65de6977478300087c99f1c84383f62" @@ -6221,13 +6597,6 @@ magic-string@^0.30.12: dependencies: "@jridgewell/sourcemap-codec" "^1.5.5" -make-dir@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - make-iterator@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/make-iterator/-/make-iterator-1.0.1.tgz#29b33f312aa8f547c4a5e490f56afcec99133ad6" @@ -6262,6 +6631,26 @@ memfs@^3.4.1: dependencies: fs-monkey "^1.0.4" +memfs@^4.56.10: + version "4.57.1" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-4.57.1.tgz#5ccee42e2aab1cf086c45baf9c4ef1ff4fffb123" + integrity sha512-WvzrWPwMQT+PtbX2Et64R4qXKK0fj/8pO85MrUCzymX3twwCiJCdvntW3HdhG1teLJcHDDLIKx5+c3HckWYZtQ== + dependencies: + "@jsonjoy.com/fs-core" "4.57.1" + "@jsonjoy.com/fs-fsa" "4.57.1" + "@jsonjoy.com/fs-node" "4.57.1" + "@jsonjoy.com/fs-node-builtins" "4.57.1" + "@jsonjoy.com/fs-node-to-fsa" "4.57.1" + "@jsonjoy.com/fs-node-utils" "4.57.1" + "@jsonjoy.com/fs-print" "4.57.1" + "@jsonjoy.com/fs-snapshot" "4.57.1" + "@jsonjoy.com/json-pack" "^1.11.0" + "@jsonjoy.com/util" "^1.9.0" + glob-to-regex.js "^1.0.1" + thingies "^2.5.0" + tree-dump "^1.0.3" + tslib "^2.0.0" + memfs@^4.6.0: version "4.43.0" resolved "https://registry.yarnpkg.com/memfs/-/memfs-4.43.0.tgz#8aeed4d242e29acf57dfdfe93fec4f84280f8df6" @@ -6654,7 +7043,7 @@ obuf@^1.0.0, obuf@^1.1.2: resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== -on-finished@2.4.1, on-finished@^2.4.1: +on-finished@2.4.1, on-finished@^2.4.1, on-finished@~2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== @@ -6877,7 +7266,7 @@ path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6, path-parse@^1.0.7: +path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== @@ -6912,6 +7301,11 @@ path-to-regexp@^8.0.0: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-8.3.0.tgz#aa818a6981f99321003a08987d3cec9c3474cd1f" integrity sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA== +path-to-regexp@~0.1.12: + version "0.1.13" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.13.tgz#9b22ec16bc3ab88d05a0c7e369869421401ab17d" + integrity sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA== + path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -6942,13 +7336,6 @@ picomatch@^4.0.2: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== -pkg-dir@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - pluralize@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" @@ -7086,6 +7473,13 @@ qs@^6.14.1: dependencies: side-channel "^1.1.0" +qs@~6.14.0: + version "6.14.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.2.tgz#b5634cf9d9ad9898e31fba3504e866e8efb6798c" + integrity sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q== + dependencies: + side-channel "^1.1.0" + query-selector-shadow-dom@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/query-selector-shadow-dom/-/query-selector-shadow-dom-1.0.1.tgz#1c7b0058eff4881ac44f45d8f84ede32e9a2f349" @@ -7143,6 +7537,16 @@ raw-body@^3.0.1: iconv-lite "~0.7.0" unpipe "~1.0.0" +raw-body@~2.5.3: + version "2.5.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.3.tgz#11c6650ee770a7de1b494f197927de0c923822e2" + integrity sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA== + dependencies: + bytes "~3.1.2" + http-errors "~2.0.1" + iconv-lite "~0.4.24" + unpipe "~1.0.0" + react-is@^18.0.0: version "18.3.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" @@ -7322,13 +7726,6 @@ resolve-pkg-maps@^1.0.0: resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== -resolve@1.12.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" - integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== - dependencies: - path-parse "^1.0.6" - resolve@^1.10.0, resolve@^1.19.0, resolve@^1.22.10, resolve@^1.22.4, resolve@^1.9.0: version "1.22.10" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" @@ -7392,25 +7789,7 @@ rollup-plugin-dts@^4.2.2: optionalDependencies: "@babel/code-frame" "^7.18.6" -rollup-plugin-typescript2@^0.24.0: - version "0.24.3" - resolved "https://registry.yarnpkg.com/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.24.3.tgz#276fa33a9d584d500da62d3e5400307f4a46bdf2" - integrity sha512-D7yovQlhnRoz7pG/RF0ni+koxgzEShwfAGuOq6OVqKzcATHOvmUt2ePeYVdc9N0adcW1PcTzklUEM0oNWE/POw== - dependencies: - find-cache-dir "^3.0.0" - fs-extra "8.1.0" - resolve "1.12.0" - rollup-pluginutils "2.8.1" - tslib "1.10.0" - -rollup-pluginutils@2.8.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz#8fa6dd0697344938ef26c2c09d2488ce9e33ce97" - integrity sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg== - dependencies: - estree-walker "^0.6.1" - -rollup@^2.0.0, rollup@^2.77.0: +rollup@^2.77.0: version "2.79.2" resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.2.tgz#f150e4a5db4b121a21a747d762f701e5e9f49090" integrity sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ== @@ -7574,7 +7953,7 @@ selfsigned@^2.4.1: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: +semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== @@ -7620,6 +7999,25 @@ send@^1.1.0, send@^1.2.0: range-parser "^1.2.1" statuses "^2.0.1" +send@~0.19.0, send@~0.19.1: + version "0.19.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.2.tgz#59bc0da1b4ea7ad42736fd642b1c4294e114ff29" + integrity sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~2.0.0" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "~0.5.2" + http-errors "~2.0.1" + mime "1.6.0" + ms "2.1.3" + on-finished "~2.4.1" + range-parser "~1.2.1" + statuses "~2.0.2" + serialize-error@^11.0.1: version "11.0.3" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-11.0.3.tgz#b54f439e15da5b4961340fbbd376b6b04aa52e92" @@ -7667,6 +8065,16 @@ serve-static@^2.2.0: parseurl "^1.3.3" send "^1.2.0" +serve-static@~1.16.2: + version "1.16.3" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.3.tgz#a97b74d955778583f3862a4f0b841eb4d5d78cf9" + integrity sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA== + dependencies: + encodeurl "~2.0.0" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "~0.19.1" + set-function-length@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" @@ -7990,7 +8398,7 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== -statuses@^2.0.1, statuses@~2.0.2: +statuses@^2.0.1, statuses@~2.0.1, statuses@~2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.2.tgz#8f75eecef765b5e1cfcdc080da59409ed424e382" integrity sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw== @@ -8316,7 +8724,7 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" integrity sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ== -tree-dump@^1.0.3: +tree-dump@^1.0.3, tree-dump@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/tree-dump/-/tree-dump-1.1.0.tgz#ab29129169dc46004414f5a9d4a3c6e89f13e8a4" integrity sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA== @@ -8326,6 +8734,16 @@ ts-api-utils@^2.1.0: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91" integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ== +ts-checker-rspack-plugin@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-checker-rspack-plugin/-/ts-checker-rspack-plugin-1.3.0.tgz#6d7473b1d2a12811863720925ab1dd209883cb13" + integrity sha512-89oK/BtApjdid1j9CGjPGiYry+EZBhsnTAM481/8ipgr/y2IOgCbW1HPnan+fs5FnzlpUgf9dWGNZ4Ayw3Bd8A== + dependencies: + "@rspack/lite-tapable" "^1.1.0" + chokidar "^3.6.0" + memfs "^4.56.10" + picocolors "^1.1.1" + ts-declaration-location@^1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz#d4068fe9975828b3b453b3ab112b4711d8267688" @@ -8363,11 +8781,6 @@ tsconfig-paths@^3.15.0, tsconfig-paths@^3.9.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" - integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== - tslib@^2.0.0, tslib@^2.1.0: version "2.8.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.0.tgz#d124c86c3c05a40a91e6fdea4021bd31d377971b" @@ -8548,11 +8961,6 @@ undici-types@~7.12.0: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.12.0.tgz#15c5c7475c2a3ba30659529f5cdb4674b622fafb" integrity sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ== -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - universalify@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" From 011d056834fbc2c5a9ed1d33ff02afce755fc665 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Tue, 7 Apr 2026 15:17:09 +0930 Subject: [PATCH 18/29] Run one test --- src/test/ts/browser/LoadTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index ed9a7d3..b61573d 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -17,7 +17,7 @@ describe('LoadTest', () => { deleteTinymce(); }); - it('Should load the editor and execute setup and init callbacks', async () => { + it.only('Should load the editor and execute setup and init callbacks', async () => { let seenSetup = false; let seenInit = false; let editorInstance: Editor | undefined; From 183f113f295c9d6fa46cbf3b712399182e1a0383 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Tue, 7 Apr 2026 15:20:22 +0930 Subject: [PATCH 19/29] Repeat --- package.json | 2 +- src/test/ts/browser/LoadTest.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 46392f4..cf88c9d 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ ], "main": "dist/tinymce-webcomponent.js", "scripts": { - "test": "bedrock-auto -b chrome-headless -d src/test/ts", + "test": "bedrock-auto -b chrome-headless -f src/test/ts/browser/LoadTest.ts", "build": "tsc -p ./tsconfig.json && rollup -c rollup.config.js", "lint": "yarn eslint src/**/*.ts", "serve": "yarn tsx src/demo/ts/Server.ts" diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index b61573d..ed9a7d3 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -17,7 +17,7 @@ describe('LoadTest', () => { deleteTinymce(); }); - it.only('Should load the editor and execute setup and init callbacks', async () => { + it('Should load the editor and execute setup and init callbacks', async () => { let seenSetup = false; let seenInit = false; let editorInstance: Editor | undefined; From 0e528d5796d2662c6d026a0fc6d7e2f6ded28074 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Tue, 7 Apr 2026 15:39:39 +0930 Subject: [PATCH 20/29] Run just one test --- src/test/ts/browser/DisabledTest.ts | 256 ++++++++++++++-------------- 1 file changed, 128 insertions(+), 128 deletions(-) diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index 35bf27a..5f155df 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -1,128 +1,128 @@ -import { Assertions } from '@ephox/agar'; -import { before, describe, it, context, after, afterEach } from '@ephox/bedrock-client'; -import { Global } from '@ephox/katamari'; -import type { TinyMCE, Editor as TinyMCEEditor } from 'tinymce'; -import { VersionLoader, TinyVer } from '@tinymce/miniature'; -import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; -import { Attribute, SugarElement } from '@ephox/sugar'; - -type EditorElement = HTMLElement & { disabled?: boolean }; -declare const tinymce: TinyMCE; - -describe('DisableTest', () => { - let uid = 0; - const nextId = () => `_disabled_test_fn_${uid++}`; - - before(() => { - registerCustomElementIfNot(); - Global.tinymceTestConfig = { license_key: 'gpl' }; - }); - - after(() => { - delete Global.tinymceTestConfig; - }); - - const pCreateEditor = - (attrs: Record = {}): Promise<{ element: SugarElement; editor: TinyMCEEditor }> => new Promise((resolve) => { - const setupFnName = nextId(); - const initFnName = nextId(); - // eslint-disable-next-line prefer-const - let tinymceEl: SugarElement; - let editorInstance: any; - - Global[setupFnName] = (editor: any) => { - editorInstance = editor; - }; - - Global[initFnName] = () => { - resolve({ element: tinymceEl, editor: editorInstance }); - }; - - tinymceEl = createTinymceElement({ - 'setup': setupFnName, - 'on-init': initFnName, - 'config': 'tinymceTestConfig', - ...attrs - }); - }); - - context('When using with Tinymce < 7.6', () => { - before(async () => { - await VersionLoader.pLoadVersion('7.5.0'); - Assertions.assertEq('Tinymce 7.5.0 should be loaded', - '7.5.0', - TinyVer.getVersion(tinymce).major + '.' + TinyVer.getVersion(tinymce).minor + '.' + TinyVer.getVersion(tinymce).patch); - }); - - after(() => { - deleteTinymce(); - }); - - it('Editor should be not be disabled when disabled attribute is present', async () => { - const { editor } = await pCreateEditor(); - Assertions.assertEq('Editor should be in design mode', true, editor.mode.get() === 'design'); - removeTinymceElement(); - }); - }); - - context('When using with Tinymce >= 7.6', () => { - before(async () => { - await VersionLoader.pLoadVersion('8'); - Assertions.assertEq('Tinymce 8 should be loaded', '8', TinyVer.getVersion(tinymce).major + ''); - }); - - afterEach(() => { - removeTinymceElement(); - }); - - after(() => { - deleteTinymce(); - }); - - const pWaitForDisabledStateChange = (editor: any): Promise => - new Promise((resolve) => editor.once('DisabledStateChange', resolve)); - - const assertDisabledState = (el: SugarElement, editor: TinyMCEEditor, expected: boolean) => { - const hasDisabledAtt = Attribute.has(el, 'disabled'); - Assertions.assertEq('Editor should be disabled', expected, editor.options.get('disabled')); - Assertions.assertEq(`disabled attribute should be ${expected ? 'present' : 'absent'}`, expected, hasDisabledAtt); - }; - - it('Editor should be disabled when disabled attribute is present', async () => { - const { element, editor } = await pCreateEditor({ disabled: '' }); - assertDisabledState(element, editor, true); - }); - - it('Editor is not disabled when disabled attribute is absent', async () => { - const { element, editor } = await pCreateEditor(); - assertDisabledState(element, editor, false); - }); - - it('Setting disabled attribute after init disables the editor', async () => { - const { element, editor } = await pCreateEditor(); - assertDisabledState(element, editor, false); - Attribute.set(element, 'disabled', ''); - await pWaitForDisabledStateChange(editor); - assertDisabledState(element, editor, true); - }); - - it('Removing disabled attribute after init enables the editor', async () => { - const { element, editor } = await pCreateEditor({ disabled: '' }); - assertDisabledState(element, editor, true); - Attribute.remove(element, 'disabled'); - await pWaitForDisabledStateChange(editor); - assertDisabledState(element, editor, false); - }); - - it('Updating disabled property directly syncs editor option and attribute', async () => { - const { element, editor } = await pCreateEditor(); - Assertions.assertEq('disabled property should be false initially', false, element.dom.disabled); - element.dom.disabled = true; - await pWaitForDisabledStateChange(editor); - assertDisabledState(element, editor, true); - element.dom.disabled = false; - await pWaitForDisabledStateChange(editor); - assertDisabledState(element, editor, false); - }); - }); -}); +// import { Assertions } from '@ephox/agar'; +// import { before, describe, it, context, after, afterEach } from '@ephox/bedrock-client'; +// import { Global } from '@ephox/katamari'; +// import type { TinyMCE, Editor as TinyMCEEditor } from 'tinymce'; +// import { VersionLoader, TinyVer } from '@tinymce/miniature'; +// import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; +// import { Attribute, SugarElement } from '@ephox/sugar'; + +// type EditorElement = HTMLElement & { disabled?: boolean }; +// declare const tinymce: TinyMCE; + +// describe('DisableTest', () => { +// let uid = 0; +// const nextId = () => `_disabled_test_fn_${uid++}`; + +// before(() => { +// registerCustomElementIfNot(); +// Global.tinymceTestConfig = { license_key: 'gpl' }; +// }); + +// after(() => { +// delete Global.tinymceTestConfig; +// }); + +// const pCreateEditor = +// (attrs: Record = {}): Promise<{ element: SugarElement; editor: TinyMCEEditor }> => new Promise((resolve) => { +// const setupFnName = nextId(); +// const initFnName = nextId(); +// // eslint-disable-next-line prefer-const +// let tinymceEl: SugarElement; +// let editorInstance: any; + +// Global[setupFnName] = (editor: any) => { +// editorInstance = editor; +// }; + +// Global[initFnName] = () => { +// resolve({ element: tinymceEl, editor: editorInstance }); +// }; + +// tinymceEl = createTinymceElement({ +// 'setup': setupFnName, +// 'on-init': initFnName, +// 'config': 'tinymceTestConfig', +// ...attrs +// }); +// }); + +// context('When using with Tinymce < 7.6', () => { +// before(async () => { +// await VersionLoader.pLoadVersion('7.5.0'); +// Assertions.assertEq('Tinymce 7.5.0 should be loaded', +// '7.5.0', +// TinyVer.getVersion(tinymce).major + '.' + TinyVer.getVersion(tinymce).minor + '.' + TinyVer.getVersion(tinymce).patch); +// }); + +// after(() => { +// deleteTinymce(); +// }); + +// it('Editor should be not be disabled when disabled attribute is present', async () => { +// const { editor } = await pCreateEditor(); +// Assertions.assertEq('Editor should be in design mode', true, editor.mode.get() === 'design'); +// removeTinymceElement(); +// }); +// }); + +// context('When using with Tinymce >= 7.6', () => { +// before(async () => { +// await VersionLoader.pLoadVersion('8'); +// Assertions.assertEq('Tinymce 8 should be loaded', '8', TinyVer.getVersion(tinymce).major + ''); +// }); + +// afterEach(() => { +// removeTinymceElement(); +// }); + +// after(() => { +// deleteTinymce(); +// }); + +// const pWaitForDisabledStateChange = (editor: any): Promise => +// new Promise((resolve) => editor.once('DisabledStateChange', resolve)); + +// const assertDisabledState = (el: SugarElement, editor: TinyMCEEditor, expected: boolean) => { +// const hasDisabledAtt = Attribute.has(el, 'disabled'); +// Assertions.assertEq('Editor should be disabled', expected, editor.options.get('disabled')); +// Assertions.assertEq(`disabled attribute should be ${expected ? 'present' : 'absent'}`, expected, hasDisabledAtt); +// }; + +// it('Editor should be disabled when disabled attribute is present', async () => { +// const { element, editor } = await pCreateEditor({ disabled: '' }); +// assertDisabledState(element, editor, true); +// }); + +// it('Editor is not disabled when disabled attribute is absent', async () => { +// const { element, editor } = await pCreateEditor(); +// assertDisabledState(element, editor, false); +// }); + +// it('Setting disabled attribute after init disables the editor', async () => { +// const { element, editor } = await pCreateEditor(); +// assertDisabledState(element, editor, false); +// Attribute.set(element, 'disabled', ''); +// await pWaitForDisabledStateChange(editor); +// assertDisabledState(element, editor, true); +// }); + +// it('Removing disabled attribute after init enables the editor', async () => { +// const { element, editor } = await pCreateEditor({ disabled: '' }); +// assertDisabledState(element, editor, true); +// Attribute.remove(element, 'disabled'); +// await pWaitForDisabledStateChange(editor); +// assertDisabledState(element, editor, false); +// }); + +// it('Updating disabled property directly syncs editor option and attribute', async () => { +// const { element, editor } = await pCreateEditor(); +// Assertions.assertEq('disabled property should be false initially', false, element.dom.disabled); +// element.dom.disabled = true; +// await pWaitForDisabledStateChange(editor); +// assertDisabledState(element, editor, true); +// element.dom.disabled = false; +// await pWaitForDisabledStateChange(editor); +// assertDisabledState(element, editor, false); +// }); +// }); +// }); From 3bbe81875e1a764acc33294ade214cce6f7ba377 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Tue, 7 Apr 2026 15:54:09 +0930 Subject: [PATCH 21/29] Run disbledtest only --- src/test/ts/browser/DisabledTest.ts | 256 ++++++++++++++-------------- src/test/ts/browser/LoadTest.ts | 89 +++++----- 2 files changed, 172 insertions(+), 173 deletions(-) diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index 5f155df..35bf27a 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -1,128 +1,128 @@ -// import { Assertions } from '@ephox/agar'; -// import { before, describe, it, context, after, afterEach } from '@ephox/bedrock-client'; -// import { Global } from '@ephox/katamari'; -// import type { TinyMCE, Editor as TinyMCEEditor } from 'tinymce'; -// import { VersionLoader, TinyVer } from '@tinymce/miniature'; -// import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; -// import { Attribute, SugarElement } from '@ephox/sugar'; - -// type EditorElement = HTMLElement & { disabled?: boolean }; -// declare const tinymce: TinyMCE; - -// describe('DisableTest', () => { -// let uid = 0; -// const nextId = () => `_disabled_test_fn_${uid++}`; - -// before(() => { -// registerCustomElementIfNot(); -// Global.tinymceTestConfig = { license_key: 'gpl' }; -// }); - -// after(() => { -// delete Global.tinymceTestConfig; -// }); - -// const pCreateEditor = -// (attrs: Record = {}): Promise<{ element: SugarElement; editor: TinyMCEEditor }> => new Promise((resolve) => { -// const setupFnName = nextId(); -// const initFnName = nextId(); -// // eslint-disable-next-line prefer-const -// let tinymceEl: SugarElement; -// let editorInstance: any; - -// Global[setupFnName] = (editor: any) => { -// editorInstance = editor; -// }; - -// Global[initFnName] = () => { -// resolve({ element: tinymceEl, editor: editorInstance }); -// }; - -// tinymceEl = createTinymceElement({ -// 'setup': setupFnName, -// 'on-init': initFnName, -// 'config': 'tinymceTestConfig', -// ...attrs -// }); -// }); - -// context('When using with Tinymce < 7.6', () => { -// before(async () => { -// await VersionLoader.pLoadVersion('7.5.0'); -// Assertions.assertEq('Tinymce 7.5.0 should be loaded', -// '7.5.0', -// TinyVer.getVersion(tinymce).major + '.' + TinyVer.getVersion(tinymce).minor + '.' + TinyVer.getVersion(tinymce).patch); -// }); - -// after(() => { -// deleteTinymce(); -// }); - -// it('Editor should be not be disabled when disabled attribute is present', async () => { -// const { editor } = await pCreateEditor(); -// Assertions.assertEq('Editor should be in design mode', true, editor.mode.get() === 'design'); -// removeTinymceElement(); -// }); -// }); - -// context('When using with Tinymce >= 7.6', () => { -// before(async () => { -// await VersionLoader.pLoadVersion('8'); -// Assertions.assertEq('Tinymce 8 should be loaded', '8', TinyVer.getVersion(tinymce).major + ''); -// }); - -// afterEach(() => { -// removeTinymceElement(); -// }); - -// after(() => { -// deleteTinymce(); -// }); - -// const pWaitForDisabledStateChange = (editor: any): Promise => -// new Promise((resolve) => editor.once('DisabledStateChange', resolve)); - -// const assertDisabledState = (el: SugarElement, editor: TinyMCEEditor, expected: boolean) => { -// const hasDisabledAtt = Attribute.has(el, 'disabled'); -// Assertions.assertEq('Editor should be disabled', expected, editor.options.get('disabled')); -// Assertions.assertEq(`disabled attribute should be ${expected ? 'present' : 'absent'}`, expected, hasDisabledAtt); -// }; - -// it('Editor should be disabled when disabled attribute is present', async () => { -// const { element, editor } = await pCreateEditor({ disabled: '' }); -// assertDisabledState(element, editor, true); -// }); - -// it('Editor is not disabled when disabled attribute is absent', async () => { -// const { element, editor } = await pCreateEditor(); -// assertDisabledState(element, editor, false); -// }); - -// it('Setting disabled attribute after init disables the editor', async () => { -// const { element, editor } = await pCreateEditor(); -// assertDisabledState(element, editor, false); -// Attribute.set(element, 'disabled', ''); -// await pWaitForDisabledStateChange(editor); -// assertDisabledState(element, editor, true); -// }); - -// it('Removing disabled attribute after init enables the editor', async () => { -// const { element, editor } = await pCreateEditor({ disabled: '' }); -// assertDisabledState(element, editor, true); -// Attribute.remove(element, 'disabled'); -// await pWaitForDisabledStateChange(editor); -// assertDisabledState(element, editor, false); -// }); - -// it('Updating disabled property directly syncs editor option and attribute', async () => { -// const { element, editor } = await pCreateEditor(); -// Assertions.assertEq('disabled property should be false initially', false, element.dom.disabled); -// element.dom.disabled = true; -// await pWaitForDisabledStateChange(editor); -// assertDisabledState(element, editor, true); -// element.dom.disabled = false; -// await pWaitForDisabledStateChange(editor); -// assertDisabledState(element, editor, false); -// }); -// }); -// }); +import { Assertions } from '@ephox/agar'; +import { before, describe, it, context, after, afterEach } from '@ephox/bedrock-client'; +import { Global } from '@ephox/katamari'; +import type { TinyMCE, Editor as TinyMCEEditor } from 'tinymce'; +import { VersionLoader, TinyVer } from '@tinymce/miniature'; +import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; +import { Attribute, SugarElement } from '@ephox/sugar'; + +type EditorElement = HTMLElement & { disabled?: boolean }; +declare const tinymce: TinyMCE; + +describe('DisableTest', () => { + let uid = 0; + const nextId = () => `_disabled_test_fn_${uid++}`; + + before(() => { + registerCustomElementIfNot(); + Global.tinymceTestConfig = { license_key: 'gpl' }; + }); + + after(() => { + delete Global.tinymceTestConfig; + }); + + const pCreateEditor = + (attrs: Record = {}): Promise<{ element: SugarElement; editor: TinyMCEEditor }> => new Promise((resolve) => { + const setupFnName = nextId(); + const initFnName = nextId(); + // eslint-disable-next-line prefer-const + let tinymceEl: SugarElement; + let editorInstance: any; + + Global[setupFnName] = (editor: any) => { + editorInstance = editor; + }; + + Global[initFnName] = () => { + resolve({ element: tinymceEl, editor: editorInstance }); + }; + + tinymceEl = createTinymceElement({ + 'setup': setupFnName, + 'on-init': initFnName, + 'config': 'tinymceTestConfig', + ...attrs + }); + }); + + context('When using with Tinymce < 7.6', () => { + before(async () => { + await VersionLoader.pLoadVersion('7.5.0'); + Assertions.assertEq('Tinymce 7.5.0 should be loaded', + '7.5.0', + TinyVer.getVersion(tinymce).major + '.' + TinyVer.getVersion(tinymce).minor + '.' + TinyVer.getVersion(tinymce).patch); + }); + + after(() => { + deleteTinymce(); + }); + + it('Editor should be not be disabled when disabled attribute is present', async () => { + const { editor } = await pCreateEditor(); + Assertions.assertEq('Editor should be in design mode', true, editor.mode.get() === 'design'); + removeTinymceElement(); + }); + }); + + context('When using with Tinymce >= 7.6', () => { + before(async () => { + await VersionLoader.pLoadVersion('8'); + Assertions.assertEq('Tinymce 8 should be loaded', '8', TinyVer.getVersion(tinymce).major + ''); + }); + + afterEach(() => { + removeTinymceElement(); + }); + + after(() => { + deleteTinymce(); + }); + + const pWaitForDisabledStateChange = (editor: any): Promise => + new Promise((resolve) => editor.once('DisabledStateChange', resolve)); + + const assertDisabledState = (el: SugarElement, editor: TinyMCEEditor, expected: boolean) => { + const hasDisabledAtt = Attribute.has(el, 'disabled'); + Assertions.assertEq('Editor should be disabled', expected, editor.options.get('disabled')); + Assertions.assertEq(`disabled attribute should be ${expected ? 'present' : 'absent'}`, expected, hasDisabledAtt); + }; + + it('Editor should be disabled when disabled attribute is present', async () => { + const { element, editor } = await pCreateEditor({ disabled: '' }); + assertDisabledState(element, editor, true); + }); + + it('Editor is not disabled when disabled attribute is absent', async () => { + const { element, editor } = await pCreateEditor(); + assertDisabledState(element, editor, false); + }); + + it('Setting disabled attribute after init disables the editor', async () => { + const { element, editor } = await pCreateEditor(); + assertDisabledState(element, editor, false); + Attribute.set(element, 'disabled', ''); + await pWaitForDisabledStateChange(editor); + assertDisabledState(element, editor, true); + }); + + it('Removing disabled attribute after init enables the editor', async () => { + const { element, editor } = await pCreateEditor({ disabled: '' }); + assertDisabledState(element, editor, true); + Attribute.remove(element, 'disabled'); + await pWaitForDisabledStateChange(editor); + assertDisabledState(element, editor, false); + }); + + it('Updating disabled property directly syncs editor option and attribute', async () => { + const { element, editor } = await pCreateEditor(); + Assertions.assertEq('disabled property should be false initially', false, element.dom.disabled); + element.dom.disabled = true; + await pWaitForDisabledStateChange(editor); + assertDisabledState(element, editor, true); + element.dom.disabled = false; + await pWaitForDisabledStateChange(editor); + assertDisabledState(element, editor, false); + }); + }); +}); diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index ed9a7d3..0d4bad9 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -1,50 +1,49 @@ -import { Assertions } from '@ephox/agar'; -import { before, describe, after, it } from '@ephox/bedrock-client'; -import { Global } from '@ephox/katamari'; -import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; -import { VersionLoader } from '@tinymce/miniature'; -import { Editor } from 'tinymce'; +// import { Assertions } from '@ephox/agar'; +// import { before, describe, after, it } from '@ephox/bedrock-client'; +// import { Global } from '@ephox/katamari'; +// import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; +// import { VersionLoader } from '@tinymce/miniature'; +// import { Editor } from 'tinymce'; -describe('LoadTest', () => { - before(async () => { - await VersionLoader.pLoadVersion('8'); - registerCustomElementIfNot(); - Global.tinymceTestConfig = { license_key: 'gpl' }; - }); +// describe('LoadTest', () => { +// before(async () => { +// await VersionLoader.pLoadVersion('8'); +// registerCustomElementIfNot(); +// Global.tinymceTestConfig = { license_key: 'gpl' }; +// }); - after(() => { - delete Global.tinymceTestConfig; - deleteTinymce(); - }); +// after(() => { +// delete Global.tinymceTestConfig; +// removeTinymceElement(); +// deleteTinymce(); +// }); - it('Should load the editor and execute setup and init callbacks', async () => { - let seenSetup = false; - let seenInit = false; - let editorInstance: Editor | undefined; +// it('Should load the editor and execute setup and init callbacks', async () => { +// let seenSetup = false; +// let seenInit = false; +// let editorInstance: Editor | undefined; - await new Promise((resolve) => { - Global.customElementTinymceSetup = (editor: Editor) => { - seenSetup = true; - editorInstance = editor; - }; - Global.customElementTinymceInit = (_evt: unknown) => { - seenInit = true; - resolve({}); - }; - createTinymceElement({ - 'setup': 'customElementTinymceSetup', - 'on-init': 'customElementTinymceInit', - 'config': 'tinymceTestConfig', - 'id': 'example_id' - }, '

Hello world

'); - }); +// await new Promise((resolve) => { +// Global.customElementTinymceSetup = (editor: Editor) => { +// seenSetup = true; +// editorInstance = editor; +// }; +// Global.customElementTinymceInit = (_evt: unknown) => { +// seenInit = true; +// resolve({}); +// }; +// createTinymceElement({ +// 'setup': 'customElementTinymceSetup', +// 'on-init': 'customElementTinymceInit', +// 'config': 'tinymceTestConfig', +// 'id': 'example_id' +// }, '

Hello world

'); +// }); - Assertions.assertEq('Editor setup callback should be called', true, seenSetup); - Assertions.assertEq('Editor init callback should be called', true, seenInit); - Assertions.assertEq('An editor instance is registered', true, Global.tinymce.get('example_id') !== null); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - Assertions.assertHtmlStructure('The editor has the correct content', '

Hello world

', editorInstance!.getContent() as string); - - removeTinymceElement(); - }); -}); \ No newline at end of file +// Assertions.assertEq('Editor setup callback should be called', true, seenSetup); +// Assertions.assertEq('Editor init callback should be called', true, seenInit); +// Assertions.assertEq('An editor instance is registered', true, Global.tinymce.get('example_id') !== null); +// // eslint-disable-next-line @typescript-eslint/no-non-null-assertion +// Assertions.assertHtmlStructure('The editor has the correct content', '

Hello world

', editorInstance!.getContent() as string); +// }); +// }); \ No newline at end of file From 842d0f6786e42da4ca3ed45e216ce937a349626a Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Tue, 7 Apr 2026 16:04:52 +0930 Subject: [PATCH 22/29] Try again --- package.json | 2 +- src/test/ts/browser/DisabledTest.ts | 23 +++++-- src/test/ts/browser/LoadTest.ts | 99 ++++++++++++++++------------- 3 files changed, 74 insertions(+), 50 deletions(-) diff --git a/package.json b/package.json index cf88c9d..46392f4 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ ], "main": "dist/tinymce-webcomponent.js", "scripts": { - "test": "bedrock-auto -b chrome-headless -f src/test/ts/browser/LoadTest.ts", + "test": "bedrock-auto -b chrome-headless -d src/test/ts", "build": "tsc -p ./tsconfig.json && rollup -c rollup.config.js", "lint": "yarn eslint src/**/*.ts", "serve": "yarn tsx src/demo/ts/Server.ts" diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index 35bf27a..492c78c 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -1,7 +1,7 @@ import { Assertions } from '@ephox/agar'; import { before, describe, it, context, after, afterEach } from '@ephox/bedrock-client'; import { Global } from '@ephox/katamari'; -import type { TinyMCE, Editor as TinyMCEEditor } from 'tinymce'; +import type { Editor, TinyMCE, Editor as TinyMCEEditor } from 'tinymce'; import { VersionLoader, TinyVer } from '@tinymce/miniature'; import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; import { Attribute, SugarElement } from '@ephox/sugar'; @@ -30,13 +30,26 @@ describe('DisableTest', () => { let tinymceEl: SugarElement; let editorInstance: any; - Global[setupFnName] = (editor: any) => { + Global[setupFnName] = (editor: Editor) => { + editor.on('SkinLoaded', () => { + if (editor.licenseKeyManager) { + editor.licenseKeyManager.validate({}).then(() => { + resolve({ element: tinymceEl, editor: editorInstance }); + // resolve({ editor, vm }); + }); + } else { + resolve({ element: tinymceEl, editor: editorInstance }); + } + + // No need to wait for the init event to resolve the promise as the init callback will be called after init is complete, but we want to ensure the editor instance is set before any assertions are made in the test. + // editorInstance = editor; + }); editorInstance = editor; }; - Global[initFnName] = () => { - resolve({ element: tinymceEl, editor: editorInstance }); - }; + // Global[initFnName] = () => { + // resolve({ element: tinymceEl, editor: editorInstance }); + // }; tinymceEl = createTinymceElement({ 'setup': setupFnName, diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index 0d4bad9..ba1301a 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -1,49 +1,60 @@ -// import { Assertions } from '@ephox/agar'; -// import { before, describe, after, it } from '@ephox/bedrock-client'; -// import { Global } from '@ephox/katamari'; -// import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; -// import { VersionLoader } from '@tinymce/miniature'; -// import { Editor } from 'tinymce'; +import { Assertions } from '@ephox/agar'; +import { before, describe, after, it } from '@ephox/bedrock-client'; +import { Global } from '@ephox/katamari'; +import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; +import { VersionLoader } from '@tinymce/miniature'; +import { Editor } from 'tinymce'; -// describe('LoadTest', () => { -// before(async () => { -// await VersionLoader.pLoadVersion('8'); -// registerCustomElementIfNot(); -// Global.tinymceTestConfig = { license_key: 'gpl' }; -// }); +describe('LoadTest', () => { + before(async () => { + await VersionLoader.pLoadVersion('8'); + registerCustomElementIfNot(); + Global.tinymceTestConfig = { license_key: 'gpl' }; + }); -// after(() => { -// delete Global.tinymceTestConfig; -// removeTinymceElement(); -// deleteTinymce(); -// }); + after(() => { + delete Global.tinymceTestConfig; + removeTinymceElement(); + deleteTinymce(); + }); -// it('Should load the editor and execute setup and init callbacks', async () => { -// let seenSetup = false; -// let seenInit = false; -// let editorInstance: Editor | undefined; + it('Should load the editor and execute setup and init callbacks', async () => { + let seenSetup = false; + let seenInit = false; + let editorInstance: Editor | undefined; -// await new Promise((resolve) => { -// Global.customElementTinymceSetup = (editor: Editor) => { -// seenSetup = true; -// editorInstance = editor; -// }; -// Global.customElementTinymceInit = (_evt: unknown) => { -// seenInit = true; -// resolve({}); -// }; -// createTinymceElement({ -// 'setup': 'customElementTinymceSetup', -// 'on-init': 'customElementTinymceInit', -// 'config': 'tinymceTestConfig', -// 'id': 'example_id' -// }, '

Hello world

'); -// }); + await new Promise((resolve) => { + Global.customElementTinymceSetup = (editor: Editor) => { + editor.on('SkinLoaded', () => { + if (editor.licenseKeyManager) { + editor.licenseKeyManager.validate({}).then(() => { + resolve({}); + // resolve({ editor, vm }); + }); + } else { + resolve({}); + } + }); + seenSetup = true; + editorInstance = editor; + } -// Assertions.assertEq('Editor setup callback should be called', true, seenSetup); -// Assertions.assertEq('Editor init callback should be called', true, seenInit); -// Assertions.assertEq('An editor instance is registered', true, Global.tinymce.get('example_id') !== null); -// // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -// Assertions.assertHtmlStructure('The editor has the correct content', '

Hello world

', editorInstance!.getContent() as string); -// }); -// }); \ No newline at end of file + Global.customElementTinymceInit = (_evt: unknown) => { + seenInit = true; + // resolve({}); + }; + createTinymceElement({ + 'setup': 'customElementTinymceSetup', + 'on-init': 'customElementTinymceInit', + 'config': 'tinymceTestConfig', + 'id': 'example_id' + }, '

Hello world

'); + }); + + Assertions.assertEq('Editor setup callback should be called', true, seenSetup); + Assertions.assertEq('Editor init callback should be called', true, seenInit); + Assertions.assertEq('An editor instance is registered', true, Global.tinymce.get('example_id') !== null); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + Assertions.assertHtmlStructure('The editor has the correct content', '

Hello world

', editorInstance!.getContent() as string); + }); +}); \ No newline at end of file From ff7b1d02d4dc44fced05dff67f6713b47880a48e Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Tue, 7 Apr 2026 16:10:54 +0930 Subject: [PATCH 23/29] Fix lint errors --- src/test/ts/browser/DisabledTest.ts | 6 ++---- src/test/ts/browser/LoadTest.ts | 4 +++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index 492c78c..6a99b4c 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -35,14 +35,12 @@ describe('DisableTest', () => { if (editor.licenseKeyManager) { editor.licenseKeyManager.validate({}).then(() => { resolve({ element: tinymceEl, editor: editorInstance }); - // resolve({ editor, vm }); + }).catch(() => { + resolve({ element: tinymceEl, editor: editorInstance }); }); } else { resolve({ element: tinymceEl, editor: editorInstance }); } - - // No need to wait for the init event to resolve the promise as the init callback will be called after init is complete, but we want to ensure the editor instance is set before any assertions are made in the test. - // editorInstance = editor; }); editorInstance = editor; }; diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index ba1301a..0dc6608 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -30,6 +30,8 @@ describe('LoadTest', () => { editor.licenseKeyManager.validate({}).then(() => { resolve({}); // resolve({ editor, vm }); + }).catch(() => { + resolve({}); }); } else { resolve({}); @@ -37,7 +39,7 @@ describe('LoadTest', () => { }); seenSetup = true; editorInstance = editor; - } + }; Global.customElementTinymceInit = (_evt: unknown) => { seenInit = true; From f09c73e32ba0aec7de093fab34f41f63e2c75c3d Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Wed, 8 Apr 2026 07:25:48 +0930 Subject: [PATCH 24/29] Another try --- src/test/ts/browser/DisabledTest.ts | 69 +++++++++++++++++++++++++++-- src/test/ts/browser/LoadTest.ts | 16 +++++-- 2 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index 6a99b4c..74199bb 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -45,10 +45,6 @@ describe('DisableTest', () => { editorInstance = editor; }; - // Global[initFnName] = () => { - // resolve({ element: tinymceEl, editor: editorInstance }); - // }; - tinymceEl = createTinymceElement({ 'setup': setupFnName, 'on-init': initFnName, @@ -136,4 +132,69 @@ describe('DisableTest', () => { assertDisabledState(element, editor, false); }); }); + + context('When using with Tinymce >= 8', () => { + before(async () => { + await VersionLoader.pLoadVersion('8'); + Assertions.assertEq('Tinymce 8 should be loaded', '8', TinyVer.getVersion(tinymce).major + ''); + }); + + afterEach(() => { + // eslint-disable-next-line no-console + console.log('Removing editor element'); + removeTinymceElement(); + }); + + after(() => { + // eslint-disable-next-line no-console + console.log('Deleting tinymce global'); + deleteTinymce(); + }); + + const pWaitForDisabledStateChange = (editor: any): Promise => + new Promise((resolve) => editor.once('DisabledStateChange', resolve)); + + const assertDisabledState = (el: SugarElement, editor: TinyMCEEditor, expected: boolean) => { + const hasDisabledAtt = Attribute.has(el, 'disabled'); + Assertions.assertEq('Editor should be disabled', expected, editor.options.get('disabled')); + Assertions.assertEq(`disabled attribute should be ${expected ? 'present' : 'absent'}`, expected, hasDisabledAtt); + }; + + it('Editor should be disabled when disabled attribute is present', async () => { + const { element, editor } = await pCreateEditor({ disabled: '' }); + assertDisabledState(element, editor, true); + }); + + it('Editor is not disabled when disabled attribute is absent', async () => { + const { element, editor } = await pCreateEditor(); + assertDisabledState(element, editor, false); + }); + + it('Setting disabled attribute after init disables the editor', async () => { + const { element, editor } = await pCreateEditor(); + assertDisabledState(element, editor, false); + Attribute.set(element, 'disabled', ''); + await pWaitForDisabledStateChange(editor); + assertDisabledState(element, editor, true); + }); + + it('Removing disabled attribute after init enables the editor', async () => { + const { element, editor } = await pCreateEditor({ disabled: '' }); + assertDisabledState(element, editor, true); + Attribute.remove(element, 'disabled'); + await pWaitForDisabledStateChange(editor); + assertDisabledState(element, editor, false); + }); + + it('Updating disabled property directly syncs editor option and attribute', async () => { + const { element, editor } = await pCreateEditor(); + Assertions.assertEq('disabled property should be false initially', false, element.dom.disabled); + element.dom.disabled = true; + await pWaitForDisabledStateChange(editor); + assertDisabledState(element, editor, true); + element.dom.disabled = false; + await pWaitForDisabledStateChange(editor); + assertDisabledState(element, editor, false); + }); + }); }); diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index 0dc6608..67f8238 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -2,19 +2,26 @@ import { Assertions } from '@ephox/agar'; import { before, describe, after, it } from '@ephox/bedrock-client'; import { Global } from '@ephox/katamari'; import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; -import { VersionLoader } from '@tinymce/miniature'; -import { Editor } from 'tinymce'; +import { TinyVer, VersionLoader } from '@tinymce/miniature'; +import { Editor, TinyMCE } from 'tinymce'; + +declare const tinymce: TinyMCE; describe('LoadTest', () => { before(async () => { - await VersionLoader.pLoadVersion('8'); + try { + await VersionLoader.pLoadVersion('8'); + } catch (err) { + // eslint-disable-next-line no-console + console.trace('Failed to load Tinymce 8: ' + err); + } + Assertions.assertEq('Tinymce 8 should be loaded', '8', TinyVer.getVersion(tinymce).major + ''); registerCustomElementIfNot(); Global.tinymceTestConfig = { license_key: 'gpl' }; }); after(() => { delete Global.tinymceTestConfig; - removeTinymceElement(); deleteTinymce(); }); @@ -58,5 +65,6 @@ describe('LoadTest', () => { Assertions.assertEq('An editor instance is registered', true, Global.tinymce.get('example_id') !== null); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion Assertions.assertHtmlStructure('The editor has the correct content', '

Hello world

', editorInstance!.getContent() as string); + removeTinymceElement(); }); }); \ No newline at end of file From 9448c31b4aa6a6adbcbaaee21551fedc738da6fc Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Wed, 8 Apr 2026 07:37:05 +0930 Subject: [PATCH 25/29] Remove duplicated test --- src/test/ts/browser/DisabledTest.ts | 65 ----------------------------- src/test/ts/browser/LoadTest.ts | 2 - 2 files changed, 67 deletions(-) diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index 74199bb..033977e 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -132,69 +132,4 @@ describe('DisableTest', () => { assertDisabledState(element, editor, false); }); }); - - context('When using with Tinymce >= 8', () => { - before(async () => { - await VersionLoader.pLoadVersion('8'); - Assertions.assertEq('Tinymce 8 should be loaded', '8', TinyVer.getVersion(tinymce).major + ''); - }); - - afterEach(() => { - // eslint-disable-next-line no-console - console.log('Removing editor element'); - removeTinymceElement(); - }); - - after(() => { - // eslint-disable-next-line no-console - console.log('Deleting tinymce global'); - deleteTinymce(); - }); - - const pWaitForDisabledStateChange = (editor: any): Promise => - new Promise((resolve) => editor.once('DisabledStateChange', resolve)); - - const assertDisabledState = (el: SugarElement, editor: TinyMCEEditor, expected: boolean) => { - const hasDisabledAtt = Attribute.has(el, 'disabled'); - Assertions.assertEq('Editor should be disabled', expected, editor.options.get('disabled')); - Assertions.assertEq(`disabled attribute should be ${expected ? 'present' : 'absent'}`, expected, hasDisabledAtt); - }; - - it('Editor should be disabled when disabled attribute is present', async () => { - const { element, editor } = await pCreateEditor({ disabled: '' }); - assertDisabledState(element, editor, true); - }); - - it('Editor is not disabled when disabled attribute is absent', async () => { - const { element, editor } = await pCreateEditor(); - assertDisabledState(element, editor, false); - }); - - it('Setting disabled attribute after init disables the editor', async () => { - const { element, editor } = await pCreateEditor(); - assertDisabledState(element, editor, false); - Attribute.set(element, 'disabled', ''); - await pWaitForDisabledStateChange(editor); - assertDisabledState(element, editor, true); - }); - - it('Removing disabled attribute after init enables the editor', async () => { - const { element, editor } = await pCreateEditor({ disabled: '' }); - assertDisabledState(element, editor, true); - Attribute.remove(element, 'disabled'); - await pWaitForDisabledStateChange(editor); - assertDisabledState(element, editor, false); - }); - - it('Updating disabled property directly syncs editor option and attribute', async () => { - const { element, editor } = await pCreateEditor(); - Assertions.assertEq('disabled property should be false initially', false, element.dom.disabled); - element.dom.disabled = true; - await pWaitForDisabledStateChange(editor); - assertDisabledState(element, editor, true); - element.dom.disabled = false; - await pWaitForDisabledStateChange(editor); - assertDisabledState(element, editor, false); - }); - }); }); diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index 67f8238..42d64b1 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -47,10 +47,8 @@ describe('LoadTest', () => { seenSetup = true; editorInstance = editor; }; - Global.customElementTinymceInit = (_evt: unknown) => { seenInit = true; - // resolve({}); }; createTinymceElement({ 'setup': 'customElementTinymceSetup', From f5a7108f92bf7975b7c4e288c16fe09e53fc2b05 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Wed, 8 Apr 2026 07:58:55 +0930 Subject: [PATCH 26/29] Clear loader saved url --- src/test/ts/browser/LoadTest.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index 42d64b1..b6bc47d 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -4,12 +4,15 @@ import { Global } from '@ephox/katamari'; import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; import { TinyVer, VersionLoader } from '@tinymce/miniature'; import { Editor, TinyMCE } from 'tinymce'; +// eslint-disable-next-line @tinymce/no-direct-imports +import * as Loader from '@tinymce/miniature/lib/main/ts/loader/Loader'; declare const tinymce: TinyMCE; describe('LoadTest', () => { before(async () => { try { + Loader.unload(); await VersionLoader.pLoadVersion('8'); } catch (err) { // eslint-disable-next-line no-console From 789ac6f0ff59cf27e88db453ca7aedf40a73ec43 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Wed, 8 Apr 2026 08:42:02 +0930 Subject: [PATCH 27/29] Fix test failing --- src/test/ts/alien/Utils.ts | 10 +++++++++ src/test/ts/browser/DisabledTest.ts | 21 +++++++----------- src/test/ts/browser/LoadTest.ts | 33 +++++------------------------ 3 files changed, 23 insertions(+), 41 deletions(-) diff --git a/src/test/ts/alien/Utils.ts b/src/test/ts/alien/Utils.ts index a6785f1..70ec850 100644 --- a/src/test/ts/alien/Utils.ts +++ b/src/test/ts/alien/Utils.ts @@ -3,7 +3,10 @@ import { ScriptLoader } from 'src/main/ts/utils/ScriptLoader'; import { Arr, Strings, Optional, Fun } from '@ephox/katamari'; // eslint-disable-next-line @tinymce/no-direct-imports import * as Globals from '@tinymce/miniature/lib/main/ts/loader/Globals'; +// eslint-disable-next-line @tinymce/no-direct-imports +import * as Loader from '@tinymce/miniature/lib/main/ts/loader/Loader'; import Editor from 'src/main/ts/component/Editor'; +import { VersionLoader } from '@tinymce/miniature'; export const deleteTinymce = () => { ScriptLoader.reinitialize(); @@ -36,4 +39,11 @@ export const createTinymceElement = (attrs: Record, content?: st } document.body.appendChild(ce.dom); return ce; +}; + +export const pLoadTinymce = async (version: string) => { + // Clear the URL cached in the loader to ensure a fresh load of the requested version, + // otherwise the loader will skip loading if the same version was previously loaded + Loader.unload(); + await VersionLoader.pLoadVersion(version); }; \ No newline at end of file diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index 033977e..a27cc6e 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -3,7 +3,7 @@ import { before, describe, it, context, after, afterEach } from '@ephox/bedrock- import { Global } from '@ephox/katamari'; import type { Editor, TinyMCE, Editor as TinyMCEEditor } from 'tinymce'; import { VersionLoader, TinyVer } from '@tinymce/miniature'; -import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; +import { createTinymceElement, deleteTinymce, pLoadTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; import { Attribute, SugarElement } from '@ephox/sugar'; type EditorElement = HTMLElement & { disabled?: boolean }; @@ -31,19 +31,14 @@ describe('DisableTest', () => { let editorInstance: any; Global[setupFnName] = (editor: Editor) => { - editor.on('SkinLoaded', () => { - if (editor.licenseKeyManager) { - editor.licenseKeyManager.validate({}).then(() => { - resolve({ element: tinymceEl, editor: editorInstance }); - }).catch(() => { - resolve({ element: tinymceEl, editor: editorInstance }); - }); - } else { - resolve({ element: tinymceEl, editor: editorInstance }); - } - }); editorInstance = editor; }; + Global[initFnName] = () => { + resolve({ + element: tinymceEl, + editor: editorInstance + }); + }; tinymceEl = createTinymceElement({ 'setup': setupFnName, @@ -55,7 +50,7 @@ describe('DisableTest', () => { context('When using with Tinymce < 7.6', () => { before(async () => { - await VersionLoader.pLoadVersion('7.5.0'); + await pLoadTinymce('7.5.0'); Assertions.assertEq('Tinymce 7.5.0 should be loaded', '7.5.0', TinyVer.getVersion(tinymce).major + '.' + TinyVer.getVersion(tinymce).minor + '.' + TinyVer.getVersion(tinymce).patch); diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index b6bc47d..4481d00 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -1,24 +1,12 @@ import { Assertions } from '@ephox/agar'; import { before, describe, after, it } from '@ephox/bedrock-client'; import { Global } from '@ephox/katamari'; -import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; -import { TinyVer, VersionLoader } from '@tinymce/miniature'; -import { Editor, TinyMCE } from 'tinymce'; -// eslint-disable-next-line @tinymce/no-direct-imports -import * as Loader from '@tinymce/miniature/lib/main/ts/loader/Loader'; - -declare const tinymce: TinyMCE; +import { createTinymceElement, deleteTinymce, pLoadTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; +import { Editor } from 'tinymce'; describe('LoadTest', () => { before(async () => { - try { - Loader.unload(); - await VersionLoader.pLoadVersion('8'); - } catch (err) { - // eslint-disable-next-line no-console - console.trace('Failed to load Tinymce 8: ' + err); - } - Assertions.assertEq('Tinymce 8 should be loaded', '8', TinyVer.getVersion(tinymce).major + ''); + await pLoadTinymce('8'); registerCustomElementIfNot(); Global.tinymceTestConfig = { license_key: 'gpl' }; }); @@ -31,27 +19,16 @@ describe('LoadTest', () => { it('Should load the editor and execute setup and init callbacks', async () => { let seenSetup = false; let seenInit = false; - let editorInstance: Editor | undefined; + let editorInstance: Editor; await new Promise((resolve) => { Global.customElementTinymceSetup = (editor: Editor) => { - editor.on('SkinLoaded', () => { - if (editor.licenseKeyManager) { - editor.licenseKeyManager.validate({}).then(() => { - resolve({}); - // resolve({ editor, vm }); - }).catch(() => { - resolve({}); - }); - } else { - resolve({}); - } - }); seenSetup = true; editorInstance = editor; }; Global.customElementTinymceInit = (_evt: unknown) => { seenInit = true; + resolve({}); }; createTinymceElement({ 'setup': 'customElementTinymceSetup', From 977fd85e769090a7dde3e7185cb822d3296a0706 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Wed, 8 Apr 2026 08:59:32 +0930 Subject: [PATCH 28/29] Give headless browser some time to fetch stuffs --- src/test/ts/alien/Utils.ts | 10 ---------- src/test/ts/browser/DisabledTest.ts | 21 +++++++-------------- src/test/ts/browser/LoadTest.ts | 18 +++++++++--------- 3 files changed, 16 insertions(+), 33 deletions(-) diff --git a/src/test/ts/alien/Utils.ts b/src/test/ts/alien/Utils.ts index 70ec850..a6785f1 100644 --- a/src/test/ts/alien/Utils.ts +++ b/src/test/ts/alien/Utils.ts @@ -3,10 +3,7 @@ import { ScriptLoader } from 'src/main/ts/utils/ScriptLoader'; import { Arr, Strings, Optional, Fun } from '@ephox/katamari'; // eslint-disable-next-line @tinymce/no-direct-imports import * as Globals from '@tinymce/miniature/lib/main/ts/loader/Globals'; -// eslint-disable-next-line @tinymce/no-direct-imports -import * as Loader from '@tinymce/miniature/lib/main/ts/loader/Loader'; import Editor from 'src/main/ts/component/Editor'; -import { VersionLoader } from '@tinymce/miniature'; export const deleteTinymce = () => { ScriptLoader.reinitialize(); @@ -39,11 +36,4 @@ export const createTinymceElement = (attrs: Record, content?: st } document.body.appendChild(ce.dom); return ce; -}; - -export const pLoadTinymce = async (version: string) => { - // Clear the URL cached in the loader to ensure a fresh load of the requested version, - // otherwise the loader will skip loading if the same version was previously loaded - Loader.unload(); - await VersionLoader.pLoadVersion(version); }; \ No newline at end of file diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index a27cc6e..f3496bc 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -3,7 +3,7 @@ import { before, describe, it, context, after, afterEach } from '@ephox/bedrock- import { Global } from '@ephox/katamari'; import type { Editor, TinyMCE, Editor as TinyMCEEditor } from 'tinymce'; import { VersionLoader, TinyVer } from '@tinymce/miniature'; -import { createTinymceElement, deleteTinymce, pLoadTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; +import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; import { Attribute, SugarElement } from '@ephox/sugar'; type EditorElement = HTMLElement & { disabled?: boolean }; @@ -25,32 +25,25 @@ describe('DisableTest', () => { const pCreateEditor = (attrs: Record = {}): Promise<{ element: SugarElement; editor: TinyMCEEditor }> => new Promise((resolve) => { const setupFnName = nextId(); - const initFnName = nextId(); - // eslint-disable-next-line prefer-const + // eslint-disable-next-line prefer-const let tinymceEl: SugarElement; - let editorInstance: any; Global[setupFnName] = (editor: Editor) => { - editorInstance = editor; - }; - Global[initFnName] = () => { - resolve({ - element: tinymceEl, - editor: editorInstance + editor.on('SkinLoaded', () => { + setTimeout(() => resolve({ element: tinymceEl, editor }), 500); }); }; tinymceEl = createTinymceElement({ - 'setup': setupFnName, - 'on-init': initFnName, - 'config': 'tinymceTestConfig', + setup: setupFnName, + config: 'tinymceTestConfig', ...attrs }); }); context('When using with Tinymce < 7.6', () => { before(async () => { - await pLoadTinymce('7.5.0'); + await VersionLoader.pLoadVersion('7.5.0'); Assertions.assertEq('Tinymce 7.5.0 should be loaded', '7.5.0', TinyVer.getVersion(tinymce).major + '.' + TinyVer.getVersion(tinymce).minor + '.' + TinyVer.getVersion(tinymce).patch); diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index 4481d00..e947d97 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -1,12 +1,13 @@ import { Assertions } from '@ephox/agar'; import { before, describe, after, it } from '@ephox/bedrock-client'; import { Global } from '@ephox/katamari'; -import { createTinymceElement, deleteTinymce, pLoadTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; +import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; import { Editor } from 'tinymce'; +import { VersionLoader } from '@tinymce/miniature'; describe('LoadTest', () => { before(async () => { - await pLoadTinymce('8'); + await VersionLoader.pLoadVersion('8'); registerCustomElementIfNot(); Global.tinymceTestConfig = { license_key: 'gpl' }; }); @@ -19,16 +20,16 @@ describe('LoadTest', () => { it('Should load the editor and execute setup and init callbacks', async () => { let seenSetup = false; let seenInit = false; - let editorInstance: Editor; - await new Promise((resolve) => { - Global.customElementTinymceSetup = (editor: Editor) => { + const { editor } = await new Promise<{ editor: Editor }>((resolve) => { + Global.customElementTinymceSetup = (ed: Editor) => { seenSetup = true; - editorInstance = editor; + ed.on('SkinLoaded', () => { + setTimeout(() => resolve({ editor: ed }), 500); + }); }; Global.customElementTinymceInit = (_evt: unknown) => { seenInit = true; - resolve({}); }; createTinymceElement({ 'setup': 'customElementTinymceSetup', @@ -41,8 +42,7 @@ describe('LoadTest', () => { Assertions.assertEq('Editor setup callback should be called', true, seenSetup); Assertions.assertEq('Editor init callback should be called', true, seenInit); Assertions.assertEq('An editor instance is registered', true, Global.tinymce.get('example_id') !== null); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - Assertions.assertHtmlStructure('The editor has the correct content', '

Hello world

', editorInstance!.getContent() as string); + Assertions.assertHtmlStructure('The editor has the correct content', '

Hello world

', editor.getContent() as string); removeTinymceElement(); }); }); \ No newline at end of file From 4a7e3a280fcc83e912c7517be26d42f4f34525d9 Mon Sep 17 00:00:00 2001 From: Ben Tran Date: Wed, 8 Apr 2026 10:47:57 +0930 Subject: [PATCH 29/29] Resolve comments --- src/test/ts/alien/Utils.ts | 4 ++-- src/test/ts/browser/DisabledTest.ts | 6 +++--- src/test/ts/browser/LoadTest.ts | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/ts/alien/Utils.ts b/src/test/ts/alien/Utils.ts index a6785f1..5167b49 100644 --- a/src/test/ts/alien/Utils.ts +++ b/src/test/ts/alien/Utils.ts @@ -20,8 +20,8 @@ export const deleteTinymce = () => { Arr.each(elements, Remove.remove); }; -export const removeTinymceElement = () => { - Arr.map(SelectorFilter.all('tinymce-editor'), Remove.remove); +export const removeTinymceElements = () => { + Arr.each(SelectorFilter.all('tinymce-editor'), Remove.remove); }; export const registerCustomElementIfNot = () => { diff --git a/src/test/ts/browser/DisabledTest.ts b/src/test/ts/browser/DisabledTest.ts index f3496bc..f621358 100644 --- a/src/test/ts/browser/DisabledTest.ts +++ b/src/test/ts/browser/DisabledTest.ts @@ -3,7 +3,7 @@ import { before, describe, it, context, after, afterEach } from '@ephox/bedrock- import { Global } from '@ephox/katamari'; import type { Editor, TinyMCE, Editor as TinyMCEEditor } from 'tinymce'; import { VersionLoader, TinyVer } from '@tinymce/miniature'; -import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; +import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElements } from '../alien/Utils'; import { Attribute, SugarElement } from '@ephox/sugar'; type EditorElement = HTMLElement & { disabled?: boolean }; @@ -56,7 +56,7 @@ describe('DisableTest', () => { it('Editor should be not be disabled when disabled attribute is present', async () => { const { editor } = await pCreateEditor(); Assertions.assertEq('Editor should be in design mode', true, editor.mode.get() === 'design'); - removeTinymceElement(); + removeTinymceElements(); }); }); @@ -67,7 +67,7 @@ describe('DisableTest', () => { }); afterEach(() => { - removeTinymceElement(); + removeTinymceElements(); }); after(() => { diff --git a/src/test/ts/browser/LoadTest.ts b/src/test/ts/browser/LoadTest.ts index e947d97..371cbc8 100644 --- a/src/test/ts/browser/LoadTest.ts +++ b/src/test/ts/browser/LoadTest.ts @@ -1,7 +1,7 @@ import { Assertions } from '@ephox/agar'; import { before, describe, after, it } from '@ephox/bedrock-client'; import { Global } from '@ephox/katamari'; -import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElement } from '../alien/Utils'; +import { createTinymceElement, deleteTinymce, registerCustomElementIfNot, removeTinymceElements } from '../alien/Utils'; import { Editor } from 'tinymce'; import { VersionLoader } from '@tinymce/miniature'; @@ -43,6 +43,6 @@ describe('LoadTest', () => { Assertions.assertEq('Editor init callback should be called', true, seenInit); Assertions.assertEq('An editor instance is registered', true, Global.tinymce.get('example_id') !== null); Assertions.assertHtmlStructure('The editor has the correct content', '

Hello world

', editor.getContent() as string); - removeTinymceElement(); + removeTinymceElements(); }); }); \ No newline at end of file