From 1fed96a9093aaac474e36b5cb4013dc50eef60c0 Mon Sep 17 00:00:00 2001 From: Harvey Zhao Date: Tue, 15 Sep 2026 13:26:55 +0800 Subject: [PATCH] build(site): [SITE-07] bind Monaco DOM adaptations and WinJS reference notices --- .gitattributes | 2 + docs/THIRD_PARTY_NOTICES.md | 6 + .../monaco-editor/core-dom/ATTRIBUTION.md | 29 + .../monaco-editor/core-dom/LICENSE.txt | 13 + package.json | 3 +- .../monaco-dom-origins-provenance.json | 105 + .../monaco-dom-origins-validation.json | 2147 +++++++++++++ .../site-vendor/monaco-dom/ATTRIBUTION.md.txt | 29 + .../site-vendor/monaco-dom/vscode-dom.txt | 1623 ++++++++++ .../site-vendor/monaco-dom/winjs-elements.txt | 2676 +++++++++++++++++ .../site-vendor/monaco-dom/winjs-license.txt | 13 + .../changes/2026-09-15-SITE-07-monaco-dom.md | 51 + refactor/plan.md | 2 +- refactor/progress.md | 6 + refactor/risks.json | 7 +- refactor/tasks.json | 4 +- refactor/third-party.json | 5 +- scripts/build-site-notices.mjs | 3 + scripts/site-vendor/manifest.json | 22 + scripts/site-vendor/monaco/README.md | 36 + scripts/site-vendor/monaco/dom-origins.ts | 63 + .../monaco/reproduce-dom-origins.ts | 25 + test/browser/editor-dom.spec.js | 45 + test/browser/site-vendor.spec.js | 1 + test/site-notices.test.js | 22 + 25 files changed, 6931 insertions(+), 7 deletions(-) create mode 100644 docs/licenses/monaco-editor/core-dom/ATTRIBUTION.md create mode 100644 docs/licenses/monaco-editor/core-dom/LICENSE.txt create mode 100644 refactor/baselines/monaco-dom-origins-provenance.json create mode 100644 refactor/baselines/monaco-dom-origins-validation.json create mode 100644 refactor/baselines/site-vendor/monaco-dom/ATTRIBUTION.md.txt create mode 100644 refactor/baselines/site-vendor/monaco-dom/vscode-dom.txt create mode 100644 refactor/baselines/site-vendor/monaco-dom/winjs-elements.txt create mode 100644 refactor/baselines/site-vendor/monaco-dom/winjs-license.txt create mode 100644 refactor/changes/2026-09-15-SITE-07-monaco-dom.md create mode 100644 scripts/site-vendor/monaco/dom-origins.ts create mode 100644 scripts/site-vendor/monaco/reproduce-dom-origins.ts create mode 100644 test/browser/editor-dom.spec.js diff --git a/.gitattributes b/.gitattributes index e07750037..c3fc77c9a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -45,5 +45,7 @@ refactor/baselines/monaco-core-locales.json text eol=lf refactor/baselines/site-vendor/monaco-contributions/** -text whitespace=-trailing-space,cr-at-eol refactor/baselines/site-vendor/monaco-css-build/** -text whitespace=-trailing-space,cr-at-eol refactor/baselines/site-vendor/monaco-node-path/** -text whitespace=-trailing-space,cr-at-eol +refactor/baselines/site-vendor/monaco-dom/** -text whitespace=-trailing-space,cr-at-eol +docs/licenses/monaco-editor/core-dom/** -text whitespace=-trailing-space,cr-at-eol docs/licenses/monaco-editor/core-path/** -text whitespace=-trailing-space,cr-at-eol refactor/baselines/monaco-node-path-fixtures.json text eol=lf diff --git a/docs/THIRD_PARTY_NOTICES.md b/docs/THIRD_PARTY_NOTICES.md index ea022e745..5e5374345 100644 --- a/docs/THIRD_PARTY_NOTICES.md +++ b/docs/THIRD_PARTY_NOTICES.md @@ -121,6 +121,10 @@ Included component: nodejs path (Monaco core) 14.16.0 Source: https://github.com/nodejs/node/blob/bd60e93357a118204ea238d94e7a9e4209d93062/lib/path.js +Included component: WinJS-derived DOM helpers (Monaco core) unversioned adaptation; reference WinJS 4.4.5 + +Source: https://github.com/winjs/winjs/tree/4329b1133b243d9ded3b5a1f98d096ee8e80e889 + - licenses/monaco-editor/LICENSE - licenses/monaco-editor/ThirdPartyNotices.txt - licenses/monaco-editor/codicons/LICENSE @@ -148,6 +152,8 @@ Source: https://github.com/nodejs/node/blob/bd60e93357a118204ea238d94e7a9e4209d9 - licenses/monaco-editor/core-origins/marked-vscode-license.txt - licenses/monaco-editor/core-origins/ATTRIBUTION.md - licenses/monaco-editor/core-path/ATTRIBUTION.md +- licenses/monaco-editor/core-dom/LICENSE.txt +- licenses/monaco-editor/core-dom/ATTRIBUTION.md ## console legacy-vendor-with-TS-adapter diff --git a/docs/licenses/monaco-editor/core-dom/ATTRIBUTION.md b/docs/licenses/monaco-editor/core-dom/ATTRIBUTION.md new file mode 100644 index 000000000..2fc2315f5 --- /dev/null +++ b/docs/licenses/monaco-editor/core-dom/ATTRIBUTION.md @@ -0,0 +1,29 @@ +# WinJS-derived DOM helpers in Monaco + +Monaco 0.30.1 embeds VS Code dom.ts from commit +829382514cb1065f5ebb90f436e1c6103e153953. Its Microsoft/MIT source explicitly +marks SizeUtils, getTopLeftOffset, getTotalWidth, getContentHeight and +getTotalHeight as adapted from WinJS; getContentWidth uses the same dimension +helpers. These six declaration blocks match the editor's archived source map. + +The comment does not name an original WinJS release. That original version +remains unknown. For a reproducible comparison, WinJS 4.4.5 at commit +4329b1133b243d9ded3b5a1f98d096ee8e80e889 supplies _ElementUtilities.js and the +complete Microsoft MIT license included alongside this note. This does not +assert that Monaco bundled unmodified WinJS 4.4.5 or the entire WinJS library. + +Existing adaptations include CSS property access and pixel conversion changes, +separate typed dimension helpers, and position calculations with borders, RTL +scroll handling and shadow-root checks. The WinJS reference has its own computed +style, unit conversion and position implementation. These differences are not +changes introduced by the ArtPlayer refactor. No editor runtime bytes changed. + +Sources: +- https://github.com/microsoft/vscode/blob/829382514cb1065f5ebb90f436e1c6103e153953/src/vs/base/browser/dom.ts +- https://github.com/winjs/winjs/blob/4329b1133b243d9ded3b5a1f98d096ee8e80e889/src/js/WinJS/Utilities/_ElementUtilities.js +- https://github.com/winjs/winjs/blob/4329b1133b243d9ded3b5a1f98d096ee8e80e889/License.txt + +Complete reference terms: [WinJS license](./LICENSE.txt). The editor's existing +Microsoft MIT license and original ThirdPartyNotices are retained. Unicode +data, other embedded sources and complete original core compilation remain +separate review work; this notice is not a claim of complete source clearance. diff --git a/docs/licenses/monaco-editor/core-dom/LICENSE.txt b/docs/licenses/monaco-editor/core-dom/LICENSE.txt new file mode 100644 index 000000000..baf9dc11a --- /dev/null +++ b/docs/licenses/monaco-editor/core-dom/LICENSE.txt @@ -0,0 +1,13 @@ +WinJS + +Copyright (c) Microsoft Corporation + +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/package.json b/package.json index 19537c6b2..5e6a50351 100644 --- a/package.json +++ b/package.json @@ -173,7 +173,8 @@ "verify:monaco-core-build": "node scripts/site-vendor/monaco/reproduce-core-build.ts", "verify:monaco-contributions": "node scripts/site-vendor/monaco/reproduce-contributions.ts", "verify:monaco-css": "node scripts/site-vendor/monaco/reproduce-css.ts", - "verify:monaco-node-path": "node scripts/site-vendor/monaco/reproduce-node-path.ts" + "verify:monaco-node-path": "node scripts/site-vendor/monaco/reproduce-node-path.ts", + "verify:monaco-dom-origins": "node scripts/site-vendor/monaco/reproduce-dom-origins.ts" }, "browserslist": "last 1 Chrome version", "devDependencies": { diff --git a/refactor/baselines/monaco-dom-origins-provenance.json b/refactor/baselines/monaco-dom-origins-provenance.json new file mode 100644 index 000000000..d3b59427b --- /dev/null +++ b/refactor/baselines/monaco-dom-origins-provenance.json @@ -0,0 +1,105 @@ +{ + "schemaVersion": 1, + "task": "SITE-07", + "archives": [ + { + "name": "monaco-editor", + "version": "0.30.1", + "tarball": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.30.1.tgz", + "integrity": "sha512-B/y4+b2O5G2gjuxIFtCE2EkM17R2NM7/3F8x0qcPsqy4V83bitJTIO4TIeZpYlzu/xy6INiY/+84BEm6+7Cmzg==", + "sha256": "d7872ab742036036eca48cd54e43d751bede56742f0689bcf4049bcf701468c7" + }, + { + "name": "monaco-editor-core", + "version": "0.30.1", + "tarball": "https://registry.npmjs.org/monaco-editor-core/-/monaco-editor-core-0.30.1.tgz", + "integrity": "sha512-WNxfchYafMZXVfysqg/ESW4MtOpYLPaIKrzudNlgwYvfYID+O/nwSZI5X+KxW84roVzHsNgFGyOOesfHFZwYUA==", + "sha256": "a3b004061373a7f6217eba6399f1a1de31970bee2eee693aada289035198c5ec" + } + ], + "remotes": [ + { + "source": "refactor/baselines/site-vendor/monaco-dom/winjs-elements.txt", + "sha256": "170254869783ef61cbad53294cc32ffded8d0a74272df3dc29dd3c2b63345ad4", + "gitBlobSha": "6abc27ccf155118eef70d51c653b0ebee03a4008", + "apiUrl": "https://api.github.com/repos/winjs/winjs/contents/src/js/WinJS/Utilities/_ElementUtilities.js?ref=4329b1133b243d9ded3b5a1f98d096ee8e80e889" + }, + { + "source": "refactor/baselines/site-vendor/monaco-dom/winjs-license.txt", + "sha256": "13217bb585c27ee298f49c7aec2ef74578bc0d644880906a89d2c3ccec5d647e", + "gitBlobSha": "baf9dc11a362fe41cb5981195b7981c895df1278", + "apiUrl": "https://api.github.com/repos/winjs/winjs/contents/License.txt?ref=4329b1133b243d9ded3b5a1f98d096ee8e80e889" + }, + { + "source": "refactor/baselines/site-vendor/monaco-dom/vscode-dom.txt", + "sha256": "a195debeedbf20f58cb5f0fd2306867030eb0fa00cc9f5302b5abf3c425bf73c", + "gitBlobSha": "6148eb300923a1ce56a7b9d91c8a534000c5626f", + "apiUrl": "https://api.github.com/repos/microsoft/vscode/contents/src/vs/base/browser/dom.ts?ref=829382514cb1065f5ebb90f436e1c6103e153953" + } + ], + "vscodeSource": "refactor/baselines/site-vendor/monaco-dom/vscode-dom.txt", + "winjsSource": "refactor/baselines/site-vendor/monaco-dom/winjs-elements.txt", + "originalWinjsVersion": null, + "map": { + "archive": "monaco-editor-core-0.30.1", + "member": "package/dev/vs/editor/editor.main.js.map", + "sha256": "22a1b5ff5f423adc4575004d2ae0ae231ba59516e6aa9c2fabe8a006c2730316", + "source": "file:///Users/alex/src/vscode/out-editor-src/vs/base/browser/dom.ts" + }, + "fragments": [ + { + "name": "SizeUtils", + "sha256": "e6f713ff2be5cd6d17e451879bddfe80a284612765c8beb63ffd6d9868b43aae" + }, + { + "name": "getTopLeftOffset", + "sha256": "96fae7b3098e5d64d3fa935c32d53ba27df415e0c7e7547cf859311dc114ec9b" + }, + { + "name": "getTotalWidth", + "sha256": "e2e6c899f46a2823ae10d40a63570338906f6e8c224c70e920f613b616872896" + }, + { + "name": "getContentWidth", + "sha256": "5beab28852e52e549478637b41d1a23af4499278073b6e6d5bc260c05d5b087e" + }, + { + "name": "getContentHeight", + "sha256": "1cc472cf950fb7fe5e2eb7a00e75b7ae3542f98e8eeb3939a309db2c7857678c" + }, + { + "name": "getTotalHeight", + "sha256": "e48172f26d39b0695c2897f05cfb02a0defce160354965083ff1de607484784b" + } + ], + "shipped": { + "archive": "monaco-editor-0.30.1", + "member": "package/min/vs/editor/editor.main.js", + "target": "docs/assets/js/vs/editor/editor.main.js", + "sha256": "05a50ed50bb013b6e7a82d25686186aa7bdff8b8209c7badab00e046b5e99618" + }, + "component": { + "name": "WinJS-derived DOM helpers (Monaco core)", + "version": "unversioned adaptation; reference WinJS 4.4.5", + "tarball": "https://github.com/winjs/winjs/tree/4329b1133b243d9ded3b5a1f98d096ee8e80e889", + "assets": [ + "docs/assets/js/vs/editor/editor.main.js" + ], + "notices": [ + "docs/licenses/monaco-editor/core-dom/LICENSE.txt", + "docs/licenses/monaco-editor/core-dom/ATTRIBUTION.md" + ] + }, + "notices": [ + { + "source": "refactor/baselines/site-vendor/monaco-dom/winjs-license.txt", + "target": "docs/licenses/monaco-editor/core-dom/LICENSE.txt", + "sha256": "13217bb585c27ee298f49c7aec2ef74578bc0d644880906a89d2c3ccec5d647e" + }, + { + "source": "refactor/baselines/site-vendor/monaco-dom/ATTRIBUTION.md.txt", + "target": "docs/licenses/monaco-editor/core-dom/ATTRIBUTION.md", + "sha256": "0858d19261742809cecd7174a0a06b2b0013a4b9560b78aede1edd3dd350da21" + } + ] +} diff --git a/refactor/baselines/monaco-dom-origins-validation.json b/refactor/baselines/monaco-dom-origins-validation.json new file mode 100644 index 000000000..70b5a6141 --- /dev/null +++ b/refactor/baselines/monaco-dom-origins-validation.json @@ -0,0 +1,2147 @@ +{ + "task": "SITE-07", + "status": "checkpoint", + "capturedAt": "2026-09-15T05:26:16.032Z", + "source": "3eb550052531094753207bdadf4b0e32687792de", + "toolchain": { + "node": "24.21.0", + "yarn": "1.22.22", + "parser": "5.9.3" + }, + "input": [ + { + "path": ".gitattributes", + "sha256": "b5969413911b88d54e35928610dc633f5e0d33fe1f85d63d8ee40b0ffe559f65" + }, + { + "path": "package.json", + "sha256": "fe1f827e086b29ee2cfa817eddb0b6e97b69006b4cf10b186ad54d3f52ced1a4" + }, + { + "path": "scripts/build-site-notices.mjs", + "sha256": "aa8f99109aa850cfe406413bf5ebc48a1422fd45a20aa4db1fde5e055be42828" + }, + { + "path": "scripts/site-vendor/manifest.json", + "sha256": "592eda1b34bd52f63c00293ec31706a49a9225ddfe550a2be852143951455429" + }, + { + "path": "scripts/site-vendor/monaco/dom-origins.ts", + "sha256": "ebca59e8338c51df9ea5bd22d1ad796d14d9f2c4f9ebe4fb8a42cdc13d461c15" + }, + { + "path": "scripts/site-vendor/monaco/reproduce-dom-origins.ts", + "sha256": "62d980721349940a0810b38a85aab028003c8f89d1403e782d0bfc2ddedbf4fd" + }, + { + "path": "test/site-notices.test.js", + "sha256": "32ccc4218e1e350484917d87a79e289ead90a64bfb1d1bab415f506a251b0e32" + }, + { + "path": "test/browser/editor-dom.spec.js", + "sha256": "1d5136b9eea73043a565c9f398080ef1a10bc88c5b0d5a69fa6286dd6c38733d" + }, + { + "path": "test/browser/site-vendor.spec.js", + "sha256": "f5c39ff29e547bf4932596938603cd988c83b14d01055405349c2401a8af84fe" + }, + { + "path": "refactor/baselines/monaco-dom-origins-provenance.json", + "sha256": "93639b1ee9d200b6cec2a2f50bcf204d488269d7afad41110eabb84aff85db87" + }, + { + "path": "docs/assets/js/vs/editor/editor.main.js", + "sha256": "05a50ed50bb013b6e7a82d25686186aa7bdff8b8209c7badab00e046b5e99618" + } + ], + "provenance": { + "schemaVersion": 1, + "task": "SITE-07", + "archives": [ + { + "name": "monaco-editor", + "version": "0.30.1", + "tarball": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.30.1.tgz", + "integrity": "sha512-B/y4+b2O5G2gjuxIFtCE2EkM17R2NM7/3F8x0qcPsqy4V83bitJTIO4TIeZpYlzu/xy6INiY/+84BEm6+7Cmzg==", + "sha256": "d7872ab742036036eca48cd54e43d751bede56742f0689bcf4049bcf701468c7" + }, + { + "name": "monaco-editor-core", + "version": "0.30.1", + "tarball": "https://registry.npmjs.org/monaco-editor-core/-/monaco-editor-core-0.30.1.tgz", + "integrity": "sha512-WNxfchYafMZXVfysqg/ESW4MtOpYLPaIKrzudNlgwYvfYID+O/nwSZI5X+KxW84roVzHsNgFGyOOesfHFZwYUA==", + "sha256": "a3b004061373a7f6217eba6399f1a1de31970bee2eee693aada289035198c5ec" + } + ], + "remotes": [ + { + "source": "refactor/baselines/site-vendor/monaco-dom/winjs-elements.txt", + "sha256": "170254869783ef61cbad53294cc32ffded8d0a74272df3dc29dd3c2b63345ad4", + "gitBlobSha": "6abc27ccf155118eef70d51c653b0ebee03a4008", + "apiUrl": "https://api.github.com/repos/winjs/winjs/contents/src/js/WinJS/Utilities/_ElementUtilities.js?ref=4329b1133b243d9ded3b5a1f98d096ee8e80e889" + }, + { + "source": "refactor/baselines/site-vendor/monaco-dom/winjs-license.txt", + "sha256": "13217bb585c27ee298f49c7aec2ef74578bc0d644880906a89d2c3ccec5d647e", + "gitBlobSha": "baf9dc11a362fe41cb5981195b7981c895df1278", + "apiUrl": "https://api.github.com/repos/winjs/winjs/contents/License.txt?ref=4329b1133b243d9ded3b5a1f98d096ee8e80e889" + }, + { + "source": "refactor/baselines/site-vendor/monaco-dom/vscode-dom.txt", + "sha256": "a195debeedbf20f58cb5f0fd2306867030eb0fa00cc9f5302b5abf3c425bf73c", + "gitBlobSha": "6148eb300923a1ce56a7b9d91c8a534000c5626f", + "apiUrl": "https://api.github.com/repos/microsoft/vscode/contents/src/vs/base/browser/dom.ts?ref=829382514cb1065f5ebb90f436e1c6103e153953" + } + ], + "vscodeSource": "refactor/baselines/site-vendor/monaco-dom/vscode-dom.txt", + "winjsSource": "refactor/baselines/site-vendor/monaco-dom/winjs-elements.txt", + "originalWinjsVersion": null, + "map": { + "archive": "monaco-editor-core-0.30.1", + "member": "package/dev/vs/editor/editor.main.js.map", + "sha256": "22a1b5ff5f423adc4575004d2ae0ae231ba59516e6aa9c2fabe8a006c2730316", + "source": "file:///Users/alex/src/vscode/out-editor-src/vs/base/browser/dom.ts" + }, + "fragments": [ + { + "name": "SizeUtils", + "sha256": "e6f713ff2be5cd6d17e451879bddfe80a284612765c8beb63ffd6d9868b43aae" + }, + { + "name": "getTopLeftOffset", + "sha256": "96fae7b3098e5d64d3fa935c32d53ba27df415e0c7e7547cf859311dc114ec9b" + }, + { + "name": "getTotalWidth", + "sha256": "e2e6c899f46a2823ae10d40a63570338906f6e8c224c70e920f613b616872896" + }, + { + "name": "getContentWidth", + "sha256": "5beab28852e52e549478637b41d1a23af4499278073b6e6d5bc260c05d5b087e" + }, + { + "name": "getContentHeight", + "sha256": "1cc472cf950fb7fe5e2eb7a00e75b7ae3542f98e8eeb3939a309db2c7857678c" + }, + { + "name": "getTotalHeight", + "sha256": "e48172f26d39b0695c2897f05cfb02a0defce160354965083ff1de607484784b" + } + ], + "shipped": { + "archive": "monaco-editor-0.30.1", + "member": "package/min/vs/editor/editor.main.js", + "target": "docs/assets/js/vs/editor/editor.main.js", + "sha256": "05a50ed50bb013b6e7a82d25686186aa7bdff8b8209c7badab00e046b5e99618" + }, + "component": { + "name": "WinJS-derived DOM helpers (Monaco core)", + "version": "unversioned adaptation; reference WinJS 4.4.5", + "tarball": "https://github.com/winjs/winjs/tree/4329b1133b243d9ded3b5a1f98d096ee8e80e889", + "assets": [ + "docs/assets/js/vs/editor/editor.main.js" + ], + "notices": [ + "docs/licenses/monaco-editor/core-dom/LICENSE.txt", + "docs/licenses/monaco-editor/core-dom/ATTRIBUTION.md" + ] + }, + "notices": [ + { + "source": "refactor/baselines/site-vendor/monaco-dom/winjs-license.txt", + "target": "docs/licenses/monaco-editor/core-dom/LICENSE.txt", + "sha256": "13217bb585c27ee298f49c7aec2ef74578bc0d644880906a89d2c3ccec5d647e" + }, + { + "source": "refactor/baselines/site-vendor/monaco-dom/ATTRIBUTION.md.txt", + "target": "docs/licenses/monaco-editor/core-dom/ATTRIBUTION.md", + "sha256": "0858d19261742809cecd7174a0a06b2b0013a4b9560b78aede1edd3dd350da21" + } + ] + }, + "verification": { + "archives": 2, + "fixedGitSources": 3, + "exactMappedDeclarations": 6, + "fullDomCompilation": false, + "originalWinjsVersion": null, + "referenceVersion": "4.4.5" + }, + "unit": { + "passed": 30, + "failed": 0, + "skipped": 0, + "log": { + "path": "refactor/.cache/monaco-dom-unit.log", + "sha256": "0a30e030bee26e1c097ebaa48f1da65e8a0d80deb25aa72a1b6c568526b9e320" + } + }, + "checks": [ + { + "check": "types", + "exitCode": 0, + "log": { + "path": "refactor/.cache/monaco-dom-types.log", + "sha256": "dde2c4021aecd7d02de9445bec82e59165ecb27622f3131a79153dad8d7dd3b7" + } + }, + { + "check": "lint", + "exitCode": 0, + "log": { + "path": "refactor/.cache/monaco-dom-lint.log", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + { + "check": "network", + "exitCode": 0, + "log": { + "path": "refactor/.cache/monaco-dom-network.log", + "sha256": "38078fc6cb444026478a6c080f106f160e39eb418fd799e60200b911a14c50a8" + } + }, + { + "check": "offline", + "exitCode": 0, + "log": { + "path": "refactor/.cache/monaco-dom-offline.log", + "sha256": "fc14be63a873bc22e4752f75948c865df7f576d2035d2c6965428174042a9aae" + } + }, + { + "check": "notices-check", + "exitCode": 0, + "log": { + "path": "refactor/.cache/monaco-dom-notices-check.log", + "sha256": "683de74f70eb6fcf109f4607f001e6101f210043ab970765ab10521e5dcd7567" + } + } + ], + "notices": { + "files": 88, + "outputs": 89, + "allOutputsEqualFrozenInputs": true, + "added": [ + { + "path": "docs/licenses/monaco-editor/core-dom/LICENSE.txt", + "sha256": "13217bb585c27ee298f49c7aec2ef74578bc0d644880906a89d2c3ccec5d647e" + }, + { + "path": "docs/licenses/monaco-editor/core-dom/ATTRIBUTION.md", + "sha256": "0858d19261742809cecd7174a0a06b2b0013a4b9560b78aede1edd3dd350da21" + } + ], + "index": { + "path": "docs/THIRD_PARTY_NOTICES.md", + "sha256": "3d3a33b574a8396e1202c33edcf0b2898962564379ab28bd17160522cf5486a3" + } + }, + "browser": { + "report": { + "path": "refactor/.cache/monaco-dom-browser-report.json", + "sha256": "494feea9639c9cbd8b955c7308dcc5c68e7a149dceb248638f4a7a2e980591d9" + }, + "log": { + "path": "refactor/.cache/monaco-dom-browser.log", + "sha256": "72cb55deee1acbd9aa81c6260b53a887716b7718e3f2cedf8427ca46c55e57df" + }, + "stats": { + "startTime": "2026-09-15T05:21:29.650Z", + "duration": 14863.82, + "expected": 6, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "cases": [ + { + "title": "docs Monaco DOM helpers preserve dimensions and offsets through nested scrolling", + "engine": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "status": "passed", + "retry": 0, + "errors": [], + "consoleErrors": [], + "failedRequests": [], + "observations": { + "monaco-dom-origins": [ + { + "scroll": [ + 0, + 0 + ], + "content": [ + 120, + 50 + ], + "total": [ + 144, + 74 + ], + "offset": { + "left": 90, + "top": 491 + }, + "native": { + "left": 90, + "top": 491 + } + }, + { + "scroll": [ + 25, + 35 + ], + "content": [ + 120, + 50 + ], + "total": [ + 144, + 74 + ], + "offset": { + "left": 65, + "top": 456 + }, + "native": { + "left": 65, + "top": 456 + } + }, + { + "scroll": [ + 0, + 0 + ], + "content": [ + 120, + 50 + ], + "total": [ + 144, + 74 + ], + "offset": { + "left": 90, + "top": 491 + }, + "native": { + "left": 90, + "top": 491 + } + } + ] + } + }, + { + "title": "docs Monaco DOM helpers preserve dimensions and offsets through nested scrolling", + "engine": "firefox", + "browser": "155.0", + "platform": "win32", + "status": "passed", + "retry": 0, + "errors": [], + "consoleErrors": [], + "failedRequests": [], + "observations": { + "monaco-dom-origins": [ + { + "scroll": [ + 0, + 0 + ], + "content": [ + 120, + 50 + ], + "total": [ + 144, + 74 + ], + "offset": { + "left": 90, + "top": 492 + }, + "native": { + "left": 90, + "top": 492 + } + }, + { + "scroll": [ + 25, + 35 + ], + "content": [ + 120, + 50 + ], + "total": [ + 144, + 74 + ], + "offset": { + "left": 65, + "top": 457 + }, + "native": { + "left": 65, + "top": 457 + } + }, + { + "scroll": [ + 0, + 0 + ], + "content": [ + 120, + 50 + ], + "total": [ + 144, + 74 + ], + "offset": { + "left": 90, + "top": 492 + }, + "native": { + "left": 90, + "top": 492 + } + } + ] + } + }, + { + "title": "docs Monaco DOM helpers preserve dimensions and offsets through nested scrolling", + "engine": "webkit", + "browser": "26.6", + "platform": "win32", + "status": "passed", + "retry": 0, + "errors": [], + "consoleErrors": [], + "failedRequests": [], + "observations": { + "monaco-dom-origins": [ + { + "scroll": [ + 0, + 0 + ], + "content": [ + 120, + 50 + ], + "total": [ + 144, + 74 + ], + "offset": { + "left": 90, + "top": 494 + }, + "native": { + "left": 90, + "top": 494 + } + }, + { + "scroll": [ + 25, + 35 + ], + "content": [ + 120, + 50 + ], + "total": [ + 144, + 74 + ], + "offset": { + "left": 65, + "top": 459 + }, + "native": { + "left": 65, + "top": 459 + } + }, + { + "scroll": [ + 0, + 0 + ], + "content": [ + 120, + 50 + ], + "total": [ + 144, + 74 + ], + "offset": { + "left": 90, + "top": 494 + }, + "native": { + "left": 90, + "top": 494 + } + } + ] + } + }, + { + "title": "mobile vConsole shows logs and upstream site notice texts are served unchanged", + "engine": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "status": "passed", + "retry": 0, + "errors": [], + "consoleErrors": [], + "failedRequests": [ + { + "url": "http://127.0.0.1:8084/test/pattern.mp4", + "resourceType": "media", + "failure": { + "errorText": "net::ERR_ABORTED" + } + } + ], + "observations": { + "verified-vendor-notices": [ + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/LICENSE", + "sha256": "272588ba6d7c09d6c3bedf3601e37b2ede6d4539d28a9052fcc3038df99cf683" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/babel-runtime/LICENSE", + "sha256": "117da2af0d4ce0fe1c8e19b5cff9dcd806adf973d328d27b11d4448c4ff24f76" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/core-js/LICENSE", + "sha256": "e1dad265f157187a8b0290f57b3c6807d94c322ffbcdf75ab82b638eb52b1789" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/copy-text-to-clipboard/LICENSE", + "sha256": "5c932d88256b4ab958f64a856fa48e8bd1f55bc1d96b8149c65689e0c61789d3" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/mutation-observer/LICENSE", + "sha256": "1e6f3f536e6e589b5c807d144c60b583bc10d78f7ae6cfba4c0baba4a72a8179" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/svelte/LICENSE", + "sha256": "1b790e7defe7121ad9a2e065df61d45f3e4080ffc6a0f79b4a46941bcd70be56" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/regenerator-runtime/LICENSE", + "sha256": "51887a3d47051ac2fce1210562e5b9fe0830a8a8fabeb272c2d586eeb18a05fd" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/style-loader/LICENSE", + "sha256": "9068a8782d2fb4c6e432cfa25334efa56f722822180570802bf86e71b6003b1e" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/css-loader/LICENSE", + "sha256": "9068a8782d2fb4c6e432cfa25334efa56f722822180570802bf86e71b6003b1e" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/webpack/LICENSE", + "sha256": "9068a8782d2fb4c6e432cfa25334efa56f722822180570802bf86e71b6003b1e" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/MIT-LICENSE", + "sha256": "dda328fe74b6a80e515d24827d1f15bdefcf2db82c3bcb9e490032b98dd46217" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/ATTRIBUTION.md", + "sha256": "72e1b273fc12248f5d120f33cdaab54f0421f31cfc2b3e99edd130fb32a6cfc3" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/LICENSE", + "sha256": "33e4ff1a06ef62ba21788ea162564ee8165269a24a9ce6ef301837447eab0ac6" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/ThirdPartyNotices.txt", + "sha256": "b23ab6e9a1a31ce6948a98b16a83474c999a384ece75643dd0affc83ea1724ef" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/codicons/LICENSE", + "sha256": "d6239afa918961b465b07bf7411cbe34ff6685854f58553db7966f4881a0211f" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/codicons/LICENSE-CODE", + "sha256": "9906940f61b1f0b533fa7d99baf55178b2808fbe113ea51dfbfad8572ccd5f2b" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/codicons/README.md", + "sha256": "3d53172e204bcbf282c360fe58bf0697de97ddd27c964a6e48823fb4f7cd6689" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/codicons/ATTRIBUTION.md", + "sha256": "ac4a57ce60aebaec1796b715d075273c4fd849853cd943fb92790c61ad038a5f" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/typescript/LICENSE.txt", + "sha256": "a7d00bfd54525bc694b6e32f64c7ebcf5e6b7ae3657be5cc12767bce74654a47" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/typescript/CopyrightNotice.txt", + "sha256": "0d9e78b962c1f6215aa974365d263c50683b6855db45c6c0ed67ee1002974dc6" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/typescript/ThirdPartyNoticeText.txt", + "sha256": "0a64d2681a1e3c7ccd1c2a146a68812d4a23e66ca7cc1dea0e30dbd81e80c369" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/typescript/ATTRIBUTION.md", + "sha256": "edb4b7526e86fadf7461ffda983f9f56a96472cf1ebf639947948e405ed95321" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/jsonc-parser/LICENSE.md", + "sha256": "c3a24c02d678e5f0711623dcf3ab3f243b273c2633f638a1fa8e35fb7c7f8e4d" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-css-languageservice/LICENSE.md", + "sha256": "c3a24c02d678e5f0711623dcf3ab3f243b273c2633f638a1fa8e35fb7c7f8e4d" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-html-languageservice/LICENSE.md", + "sha256": "c3a24c02d678e5f0711623dcf3ab3f243b273c2633f638a1fa8e35fb7c7f8e4d" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-html-languageservice/thirdpartynotices.txt", + "sha256": "6fac688548f02e656a57234c7f0cb4a74bd8645b4ef2c7a33f5117861b9f3de0" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-json-languageservice/LICENSE.md", + "sha256": "4742836d395a83a45d2278d9b738824d68abb1a03b81d567210a6cbc3e686e12" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-languageserver-textdocument/License.txt", + "sha256": "ec9ee83580841e8eb687aca9867f221503809ba6426c7f876ede17d91b9fcfd0" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-languageserver-textdocument/thirdpartynotices.txt", + "sha256": "a89123562fe364dc8e969e85614eb6c1f8452afe131d6e42bd1314bb2d092b04" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-languageserver-types/License.txt", + "sha256": "ec9ee83580841e8eb687aca9867f221503809ba6426c7f876ede17d91b9fcfd0" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-uri/LICENSE.md", + "sha256": "c669138cb1eb01fbb745e8e460b291e4f2869c14a40061390b6095d845ed4c82" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/beautify-css-NOTICE.txt", + "sha256": "ec728062ceae23091680dda36437fe1fa48975821e047adbb06a76805425e518" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/beautify-html-NOTICE.txt", + "sha256": "25451d033cad3539a2cadfeda7fa5e29eb74e3413917cde63d8210a259fdc893" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/ATTRIBUTION.md", + "sha256": "432cca135809edabcd9ccedd05576138b64b167445999005a6e1550132391d98" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-origins/DOMPurify-LICENSE", + "sha256": "8b6902e953e2eb2876412a4ba75291758b77e88e220962e3423af4d080db1a59" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-origins/marked-LICENSE", + "sha256": "8e3a3f82f59a60958f56ca08f445647c32a4733dc7ca6c2c46f6eb898471ab9c" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-origins/marked-vscode-license.txt", + "sha256": "43624283832b560f19539ec6d5766b7281acd4a63ada62e494c4e63c7a849bdb" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-origins/ATTRIBUTION.md", + "sha256": "3a0ab7f1036d6b1397bf94ff2700375b97db2db3bd576d195dc6d8a88e1a758e" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-path/ATTRIBUTION.md", + "sha256": "40583c701c0bcbd8e10935652a0a8b02e2073b0ef040fb7be7b939c437d8b8dc" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-dom/LICENSE.txt", + "sha256": "13217bb585c27ee298f49c7aec2ef74578bc0d644880906a89d2c3ccec5d647e" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-dom/ATTRIBUTION.md", + "sha256": "0858d19261742809cecd7174a0a06b2b0013a4b9560b78aede1edd3dd350da21" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/console-feed/console-feed-3.2.2-LICENSE", + "sha256": "52412d7bc7ce4157ea628bbaacb8829e0a9cb3c58f57f99176126bc8cf2bfc85" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react/react-17.0.2-LICENSE", + "sha256": "52412d7bc7ce4157ea628bbaacb8829e0a9cb3c58f57f99176126bc8cf2bfc85" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-dom/react-dom-17.0.2-LICENSE", + "sha256": "52412d7bc7ce4157ea628bbaacb8829e0a9cb3c58f57f99176126bc8cf2bfc85" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/scheduler/scheduler-0.20.2-LICENSE", + "sha256": "52412d7bc7ce4157ea628bbaacb8829e0a9cb3c58f57f99176126bc8cf2bfc85" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/object-assign/object-assign-4.1.1-license", + "sha256": "6fb9754611c20f6649f68805e8c990e83261f29316e29de9e6cedae607b8634c" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-is/react-is-16.13.1-LICENSE", + "sha256": "52412d7bc7ce4157ea628bbaacb8829e0a9cb3c58f57f99176126bc8cf2bfc85" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/prop-types/prop-types-15.7.2-LICENSE", + "sha256": "f657f99d3fb9647db92628e96007aabb46e5f04f33e49999075aab8e250ca7ce" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/shallowequal/shallowequal-1.1.0-LICENSE", + "sha256": "709e45bb17277819ce27e9abe5dc8e56fe93081e54adb6e6385517f28aa11ac4" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/process/process-0.11.10-LICENSE", + "sha256": "59a400d04c5078579acc27ddd6452c1bdf763f9506e01364700935fbb1a7c91b" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/hoist-non-react-statics/hoist-non-react-statics-3.3.2-LICENSE.md", + "sha256": "eb32ff0ec52b6ea86e3d3e06c6ad1b68ee03798b6729af13919f6d5c14b368f3" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/is-dom/is-dom-1.1.0-LICENSE", + "sha256": "ba38703a10a53a91d4ff87bc1d930714104ead8d53f3f86936b7772c440be96f" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/is-object/is-object-1.0.2-LICENSE", + "sha256": "950429b35f82e225a613a0638e7933855a4ce05172bd36dc060093ba58793bbe" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/is-window/is-window-1.0.2-LICENSE", + "sha256": "6f19793f004670a8c873dde23d0f970eb32dd3bba8078980a42a4fb71cb1a048" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/linkifyjs/linkifyjs-2.1.9-LICENSE", + "sha256": "c66691e7e051cf0e1538a2c7d33f337b1dfe37bb0726724917dd1ceaf043a2df" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-core/emotion-core-10.3.0-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-css/emotion-css-10.0.27-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-cache/emotion-cache-10.0.29-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-styled/emotion-styled-10.0.27-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-styled-base/emotion-styled-base-10.3.0-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-theming/emotion-theming-10.3.0-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/styled-components/styled-components-5.3.3-UPSTREAM-LICENSE", + "sha256": "5b893305a717230e5b0024ff5ca3eec1dc05ba600c9b140730488d97ce56f1e6" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/babel-runtime/babel-runtime-7.16.3-LICENSE", + "sha256": "117da2af0d4ce0fe1c8e19b5cff9dcd806adf973d328d27b11d4448c4ff24f76" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-sheet/emotion-sheet-0.9.4-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-stylis/emotion-stylis-0.8.5-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-weak-memoize/emotion-weak-memoize-0.2.5-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-utils/emotion-utils-0.11.3-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-hash/emotion-hash-0.8.0-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-unitless/emotion-unitless-0.7.5-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-memoize/emotion-memoize-0.7.4-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-serialize/emotion-serialize-0.11.16-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-is-prop-valid/emotion-is-prop-valid-0.8.8-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-inspector/react-inspector-5.1.1-LICENSE", + "sha256": "62d1c62e4b7eaee1a57e4a27b5cf6f2c0dc554b88326fc40bc512f150b340deb" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/parcel-bundler/parcel-bundler-1.12.5-LICENSE", + "sha256": "5cfba9d5711264d45a2431a53c79f597cef12720cc7c764db2602daa92d0bd2a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/chromium-string-utils/LICENSE", + "sha256": "7a209dd1b94cabdb5ea9c6f9164b9546ffa5daaa671e7767d49510db055f5c51" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/stylis-rule-sheet/LICENSE", + "sha256": "99a75da65634b772687781c054ffe679569c1770c398f96427677899fe0ca8d7" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-inspector-babel/LICENSE", + "sha256": "117da2af0d4ce0fe1c8e19b5cff9dcd806adf973d328d27b11d4448c4ff24f76" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/regenerator-runtime/LICENSE", + "sha256": "51887a3d47051ac2fce1210562e5b9fe0830a8a8fabeb272c2d586eeb18a05fd" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/simple-html-tokenizer/LICENSE", + "sha256": "c41881de2a9f2200936648343500524be154eb79f649582f9582dd251b051b11" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/replicator/LICENSE", + "sha256": "52f634086a97b3861a35afff7acf703ddbd5add8e617f6a1f540ae2f2c621284" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/stylis/LICENSE", + "sha256": "045109dfd0547aa898408d08593e1adc41e9705519ba8a20baff89e7c6c52e91" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/murmurhash-js/README.md", + "sha256": "73b67c593a2a0d6395bfe90d3bad32556ed5e7ce71883062efebc643d4e4b7b4" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/murmurhash2/PUBLIC-DOMAIN.txt", + "sha256": "50e13b0a1963f0b382255d2425df245dbdfd209201621e8c157687caedbbb949" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/stackoverflow/LICENSE", + "sha256": "28a9529c7d0bb4dc51f4bf5c116a3d16ef247a052f7591466768ddf563fd1cf5" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/stackoverflow/SOURCE.js", + "sha256": "966fdc4a37e65e90c2dc1f6ba9385e572c75ce4c0647d35f3ce566ed9ef7f6bb" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/stackoverflow/ATTRIBUTION.md", + "sha256": "4ac7ae9b19a1201b6cfe6af1d35ec85d015a2de8fb1aac6b03796145e648a667" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-pure-render/LICENSE", + "sha256": "65a1f00f35ea469048896fbfec3c5faed7d3fe7c7e0be2a0478470b59d9e1439" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-pure-render/ATTRIBUTION.md", + "sha256": "9069fed07cc10fc36ef6b168ab0a75c3f1c882c077d5117b992f5c96d1eea0cc" + } + ] + } + }, + { + "title": "mobile vConsole shows logs and upstream site notice texts are served unchanged", + "engine": "firefox", + "browser": "155.0", + "platform": "win32", + "status": "passed", + "retry": 0, + "errors": [], + "consoleErrors": [], + "failedRequests": [], + "observations": { + "verified-vendor-notices": [ + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/LICENSE", + "sha256": "272588ba6d7c09d6c3bedf3601e37b2ede6d4539d28a9052fcc3038df99cf683" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/babel-runtime/LICENSE", + "sha256": "117da2af0d4ce0fe1c8e19b5cff9dcd806adf973d328d27b11d4448c4ff24f76" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/core-js/LICENSE", + "sha256": "e1dad265f157187a8b0290f57b3c6807d94c322ffbcdf75ab82b638eb52b1789" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/copy-text-to-clipboard/LICENSE", + "sha256": "5c932d88256b4ab958f64a856fa48e8bd1f55bc1d96b8149c65689e0c61789d3" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/mutation-observer/LICENSE", + "sha256": "1e6f3f536e6e589b5c807d144c60b583bc10d78f7ae6cfba4c0baba4a72a8179" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/svelte/LICENSE", + "sha256": "1b790e7defe7121ad9a2e065df61d45f3e4080ffc6a0f79b4a46941bcd70be56" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/regenerator-runtime/LICENSE", + "sha256": "51887a3d47051ac2fce1210562e5b9fe0830a8a8fabeb272c2d586eeb18a05fd" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/style-loader/LICENSE", + "sha256": "9068a8782d2fb4c6e432cfa25334efa56f722822180570802bf86e71b6003b1e" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/css-loader/LICENSE", + "sha256": "9068a8782d2fb4c6e432cfa25334efa56f722822180570802bf86e71b6003b1e" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/webpack/LICENSE", + "sha256": "9068a8782d2fb4c6e432cfa25334efa56f722822180570802bf86e71b6003b1e" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/MIT-LICENSE", + "sha256": "dda328fe74b6a80e515d24827d1f15bdefcf2db82c3bcb9e490032b98dd46217" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/ATTRIBUTION.md", + "sha256": "72e1b273fc12248f5d120f33cdaab54f0421f31cfc2b3e99edd130fb32a6cfc3" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/LICENSE", + "sha256": "33e4ff1a06ef62ba21788ea162564ee8165269a24a9ce6ef301837447eab0ac6" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/ThirdPartyNotices.txt", + "sha256": "b23ab6e9a1a31ce6948a98b16a83474c999a384ece75643dd0affc83ea1724ef" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/codicons/LICENSE", + "sha256": "d6239afa918961b465b07bf7411cbe34ff6685854f58553db7966f4881a0211f" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/codicons/LICENSE-CODE", + "sha256": "9906940f61b1f0b533fa7d99baf55178b2808fbe113ea51dfbfad8572ccd5f2b" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/codicons/README.md", + "sha256": "3d53172e204bcbf282c360fe58bf0697de97ddd27c964a6e48823fb4f7cd6689" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/codicons/ATTRIBUTION.md", + "sha256": "ac4a57ce60aebaec1796b715d075273c4fd849853cd943fb92790c61ad038a5f" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/typescript/LICENSE.txt", + "sha256": "a7d00bfd54525bc694b6e32f64c7ebcf5e6b7ae3657be5cc12767bce74654a47" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/typescript/CopyrightNotice.txt", + "sha256": "0d9e78b962c1f6215aa974365d263c50683b6855db45c6c0ed67ee1002974dc6" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/typescript/ThirdPartyNoticeText.txt", + "sha256": "0a64d2681a1e3c7ccd1c2a146a68812d4a23e66ca7cc1dea0e30dbd81e80c369" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/typescript/ATTRIBUTION.md", + "sha256": "edb4b7526e86fadf7461ffda983f9f56a96472cf1ebf639947948e405ed95321" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/jsonc-parser/LICENSE.md", + "sha256": "c3a24c02d678e5f0711623dcf3ab3f243b273c2633f638a1fa8e35fb7c7f8e4d" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-css-languageservice/LICENSE.md", + "sha256": "c3a24c02d678e5f0711623dcf3ab3f243b273c2633f638a1fa8e35fb7c7f8e4d" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-html-languageservice/LICENSE.md", + "sha256": "c3a24c02d678e5f0711623dcf3ab3f243b273c2633f638a1fa8e35fb7c7f8e4d" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-html-languageservice/thirdpartynotices.txt", + "sha256": "6fac688548f02e656a57234c7f0cb4a74bd8645b4ef2c7a33f5117861b9f3de0" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-json-languageservice/LICENSE.md", + "sha256": "4742836d395a83a45d2278d9b738824d68abb1a03b81d567210a6cbc3e686e12" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-languageserver-textdocument/License.txt", + "sha256": "ec9ee83580841e8eb687aca9867f221503809ba6426c7f876ede17d91b9fcfd0" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-languageserver-textdocument/thirdpartynotices.txt", + "sha256": "a89123562fe364dc8e969e85614eb6c1f8452afe131d6e42bd1314bb2d092b04" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-languageserver-types/License.txt", + "sha256": "ec9ee83580841e8eb687aca9867f221503809ba6426c7f876ede17d91b9fcfd0" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-uri/LICENSE.md", + "sha256": "c669138cb1eb01fbb745e8e460b291e4f2869c14a40061390b6095d845ed4c82" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/beautify-css-NOTICE.txt", + "sha256": "ec728062ceae23091680dda36437fe1fa48975821e047adbb06a76805425e518" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/beautify-html-NOTICE.txt", + "sha256": "25451d033cad3539a2cadfeda7fa5e29eb74e3413917cde63d8210a259fdc893" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/ATTRIBUTION.md", + "sha256": "432cca135809edabcd9ccedd05576138b64b167445999005a6e1550132391d98" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-origins/DOMPurify-LICENSE", + "sha256": "8b6902e953e2eb2876412a4ba75291758b77e88e220962e3423af4d080db1a59" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-origins/marked-LICENSE", + "sha256": "8e3a3f82f59a60958f56ca08f445647c32a4733dc7ca6c2c46f6eb898471ab9c" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-origins/marked-vscode-license.txt", + "sha256": "43624283832b560f19539ec6d5766b7281acd4a63ada62e494c4e63c7a849bdb" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-origins/ATTRIBUTION.md", + "sha256": "3a0ab7f1036d6b1397bf94ff2700375b97db2db3bd576d195dc6d8a88e1a758e" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-path/ATTRIBUTION.md", + "sha256": "40583c701c0bcbd8e10935652a0a8b02e2073b0ef040fb7be7b939c437d8b8dc" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-dom/LICENSE.txt", + "sha256": "13217bb585c27ee298f49c7aec2ef74578bc0d644880906a89d2c3ccec5d647e" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-dom/ATTRIBUTION.md", + "sha256": "0858d19261742809cecd7174a0a06b2b0013a4b9560b78aede1edd3dd350da21" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/console-feed/console-feed-3.2.2-LICENSE", + "sha256": "52412d7bc7ce4157ea628bbaacb8829e0a9cb3c58f57f99176126bc8cf2bfc85" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react/react-17.0.2-LICENSE", + "sha256": "52412d7bc7ce4157ea628bbaacb8829e0a9cb3c58f57f99176126bc8cf2bfc85" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-dom/react-dom-17.0.2-LICENSE", + "sha256": "52412d7bc7ce4157ea628bbaacb8829e0a9cb3c58f57f99176126bc8cf2bfc85" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/scheduler/scheduler-0.20.2-LICENSE", + "sha256": "52412d7bc7ce4157ea628bbaacb8829e0a9cb3c58f57f99176126bc8cf2bfc85" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/object-assign/object-assign-4.1.1-license", + "sha256": "6fb9754611c20f6649f68805e8c990e83261f29316e29de9e6cedae607b8634c" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-is/react-is-16.13.1-LICENSE", + "sha256": "52412d7bc7ce4157ea628bbaacb8829e0a9cb3c58f57f99176126bc8cf2bfc85" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/prop-types/prop-types-15.7.2-LICENSE", + "sha256": "f657f99d3fb9647db92628e96007aabb46e5f04f33e49999075aab8e250ca7ce" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/shallowequal/shallowequal-1.1.0-LICENSE", + "sha256": "709e45bb17277819ce27e9abe5dc8e56fe93081e54adb6e6385517f28aa11ac4" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/process/process-0.11.10-LICENSE", + "sha256": "59a400d04c5078579acc27ddd6452c1bdf763f9506e01364700935fbb1a7c91b" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/hoist-non-react-statics/hoist-non-react-statics-3.3.2-LICENSE.md", + "sha256": "eb32ff0ec52b6ea86e3d3e06c6ad1b68ee03798b6729af13919f6d5c14b368f3" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/is-dom/is-dom-1.1.0-LICENSE", + "sha256": "ba38703a10a53a91d4ff87bc1d930714104ead8d53f3f86936b7772c440be96f" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/is-object/is-object-1.0.2-LICENSE", + "sha256": "950429b35f82e225a613a0638e7933855a4ce05172bd36dc060093ba58793bbe" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/is-window/is-window-1.0.2-LICENSE", + "sha256": "6f19793f004670a8c873dde23d0f970eb32dd3bba8078980a42a4fb71cb1a048" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/linkifyjs/linkifyjs-2.1.9-LICENSE", + "sha256": "c66691e7e051cf0e1538a2c7d33f337b1dfe37bb0726724917dd1ceaf043a2df" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-core/emotion-core-10.3.0-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-css/emotion-css-10.0.27-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-cache/emotion-cache-10.0.29-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-styled/emotion-styled-10.0.27-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-styled-base/emotion-styled-base-10.3.0-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-theming/emotion-theming-10.3.0-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/styled-components/styled-components-5.3.3-UPSTREAM-LICENSE", + "sha256": "5b893305a717230e5b0024ff5ca3eec1dc05ba600c9b140730488d97ce56f1e6" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/babel-runtime/babel-runtime-7.16.3-LICENSE", + "sha256": "117da2af0d4ce0fe1c8e19b5cff9dcd806adf973d328d27b11d4448c4ff24f76" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-sheet/emotion-sheet-0.9.4-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-stylis/emotion-stylis-0.8.5-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-weak-memoize/emotion-weak-memoize-0.2.5-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-utils/emotion-utils-0.11.3-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-hash/emotion-hash-0.8.0-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-unitless/emotion-unitless-0.7.5-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-memoize/emotion-memoize-0.7.4-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-serialize/emotion-serialize-0.11.16-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-is-prop-valid/emotion-is-prop-valid-0.8.8-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-inspector/react-inspector-5.1.1-LICENSE", + "sha256": "62d1c62e4b7eaee1a57e4a27b5cf6f2c0dc554b88326fc40bc512f150b340deb" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/parcel-bundler/parcel-bundler-1.12.5-LICENSE", + "sha256": "5cfba9d5711264d45a2431a53c79f597cef12720cc7c764db2602daa92d0bd2a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/chromium-string-utils/LICENSE", + "sha256": "7a209dd1b94cabdb5ea9c6f9164b9546ffa5daaa671e7767d49510db055f5c51" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/stylis-rule-sheet/LICENSE", + "sha256": "99a75da65634b772687781c054ffe679569c1770c398f96427677899fe0ca8d7" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-inspector-babel/LICENSE", + "sha256": "117da2af0d4ce0fe1c8e19b5cff9dcd806adf973d328d27b11d4448c4ff24f76" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/regenerator-runtime/LICENSE", + "sha256": "51887a3d47051ac2fce1210562e5b9fe0830a8a8fabeb272c2d586eeb18a05fd" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/simple-html-tokenizer/LICENSE", + "sha256": "c41881de2a9f2200936648343500524be154eb79f649582f9582dd251b051b11" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/replicator/LICENSE", + "sha256": "52f634086a97b3861a35afff7acf703ddbd5add8e617f6a1f540ae2f2c621284" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/stylis/LICENSE", + "sha256": "045109dfd0547aa898408d08593e1adc41e9705519ba8a20baff89e7c6c52e91" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/murmurhash-js/README.md", + "sha256": "73b67c593a2a0d6395bfe90d3bad32556ed5e7ce71883062efebc643d4e4b7b4" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/murmurhash2/PUBLIC-DOMAIN.txt", + "sha256": "50e13b0a1963f0b382255d2425df245dbdfd209201621e8c157687caedbbb949" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/stackoverflow/LICENSE", + "sha256": "28a9529c7d0bb4dc51f4bf5c116a3d16ef247a052f7591466768ddf563fd1cf5" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/stackoverflow/SOURCE.js", + "sha256": "966fdc4a37e65e90c2dc1f6ba9385e572c75ce4c0647d35f3ce566ed9ef7f6bb" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/stackoverflow/ATTRIBUTION.md", + "sha256": "4ac7ae9b19a1201b6cfe6af1d35ec85d015a2de8fb1aac6b03796145e648a667" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-pure-render/LICENSE", + "sha256": "65a1f00f35ea469048896fbfec3c5faed7d3fe7c7e0be2a0478470b59d9e1439" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-pure-render/ATTRIBUTION.md", + "sha256": "9069fed07cc10fc36ef6b168ab0a75c3f1c882c077d5117b992f5c96d1eea0cc" + } + ] + } + }, + { + "title": "mobile vConsole shows logs and upstream site notice texts are served unchanged", + "engine": "webkit", + "browser": "26.6", + "platform": "win32", + "status": "passed", + "retry": 0, + "errors": [], + "consoleErrors": [], + "failedRequests": [], + "observations": { + "verified-vendor-notices": [ + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/LICENSE", + "sha256": "272588ba6d7c09d6c3bedf3601e37b2ede6d4539d28a9052fcc3038df99cf683" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/babel-runtime/LICENSE", + "sha256": "117da2af0d4ce0fe1c8e19b5cff9dcd806adf973d328d27b11d4448c4ff24f76" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/core-js/LICENSE", + "sha256": "e1dad265f157187a8b0290f57b3c6807d94c322ffbcdf75ab82b638eb52b1789" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/copy-text-to-clipboard/LICENSE", + "sha256": "5c932d88256b4ab958f64a856fa48e8bd1f55bc1d96b8149c65689e0c61789d3" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/mutation-observer/LICENSE", + "sha256": "1e6f3f536e6e589b5c807d144c60b583bc10d78f7ae6cfba4c0baba4a72a8179" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/svelte/LICENSE", + "sha256": "1b790e7defe7121ad9a2e065df61d45f3e4080ffc6a0f79b4a46941bcd70be56" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/regenerator-runtime/LICENSE", + "sha256": "51887a3d47051ac2fce1210562e5b9fe0830a8a8fabeb272c2d586eeb18a05fd" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/style-loader/LICENSE", + "sha256": "9068a8782d2fb4c6e432cfa25334efa56f722822180570802bf86e71b6003b1e" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/css-loader/LICENSE", + "sha256": "9068a8782d2fb4c6e432cfa25334efa56f722822180570802bf86e71b6003b1e" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/webpack/LICENSE", + "sha256": "9068a8782d2fb4c6e432cfa25334efa56f722822180570802bf86e71b6003b1e" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/MIT-LICENSE", + "sha256": "dda328fe74b6a80e515d24827d1f15bdefcf2db82c3bcb9e490032b98dd46217" + }, + { + "component": "vconsole", + "version": "3.15.0", + "url": "http://127.0.0.1:8084/licenses/vconsole/ATTRIBUTION.md", + "sha256": "72e1b273fc12248f5d120f33cdaab54f0421f31cfc2b3e99edd130fb32a6cfc3" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/LICENSE", + "sha256": "33e4ff1a06ef62ba21788ea162564ee8165269a24a9ce6ef301837447eab0ac6" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/ThirdPartyNotices.txt", + "sha256": "b23ab6e9a1a31ce6948a98b16a83474c999a384ece75643dd0affc83ea1724ef" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/codicons/LICENSE", + "sha256": "d6239afa918961b465b07bf7411cbe34ff6685854f58553db7966f4881a0211f" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/codicons/LICENSE-CODE", + "sha256": "9906940f61b1f0b533fa7d99baf55178b2808fbe113ea51dfbfad8572ccd5f2b" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/codicons/README.md", + "sha256": "3d53172e204bcbf282c360fe58bf0697de97ddd27c964a6e48823fb4f7cd6689" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/codicons/ATTRIBUTION.md", + "sha256": "ac4a57ce60aebaec1796b715d075273c4fd849853cd943fb92790c61ad038a5f" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/typescript/LICENSE.txt", + "sha256": "a7d00bfd54525bc694b6e32f64c7ebcf5e6b7ae3657be5cc12767bce74654a47" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/typescript/CopyrightNotice.txt", + "sha256": "0d9e78b962c1f6215aa974365d263c50683b6855db45c6c0ed67ee1002974dc6" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/typescript/ThirdPartyNoticeText.txt", + "sha256": "0a64d2681a1e3c7ccd1c2a146a68812d4a23e66ca7cc1dea0e30dbd81e80c369" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/typescript/ATTRIBUTION.md", + "sha256": "edb4b7526e86fadf7461ffda983f9f56a96472cf1ebf639947948e405ed95321" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/jsonc-parser/LICENSE.md", + "sha256": "c3a24c02d678e5f0711623dcf3ab3f243b273c2633f638a1fa8e35fb7c7f8e4d" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-css-languageservice/LICENSE.md", + "sha256": "c3a24c02d678e5f0711623dcf3ab3f243b273c2633f638a1fa8e35fb7c7f8e4d" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-html-languageservice/LICENSE.md", + "sha256": "c3a24c02d678e5f0711623dcf3ab3f243b273c2633f638a1fa8e35fb7c7f8e4d" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-html-languageservice/thirdpartynotices.txt", + "sha256": "6fac688548f02e656a57234c7f0cb4a74bd8645b4ef2c7a33f5117861b9f3de0" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-json-languageservice/LICENSE.md", + "sha256": "4742836d395a83a45d2278d9b738824d68abb1a03b81d567210a6cbc3e686e12" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-languageserver-textdocument/License.txt", + "sha256": "ec9ee83580841e8eb687aca9867f221503809ba6426c7f876ede17d91b9fcfd0" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-languageserver-textdocument/thirdpartynotices.txt", + "sha256": "a89123562fe364dc8e969e85614eb6c1f8452afe131d6e42bd1314bb2d092b04" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-languageserver-types/License.txt", + "sha256": "ec9ee83580841e8eb687aca9867f221503809ba6426c7f876ede17d91b9fcfd0" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/vscode-uri/LICENSE.md", + "sha256": "c669138cb1eb01fbb745e8e460b291e4f2869c14a40061390b6095d845ed4c82" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/beautify-css-NOTICE.txt", + "sha256": "ec728062ceae23091680dda36437fe1fa48975821e047adbb06a76805425e518" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/beautify-html-NOTICE.txt", + "sha256": "25451d033cad3539a2cadfeda7fa5e29eb74e3413917cde63d8210a259fdc893" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/language-services/ATTRIBUTION.md", + "sha256": "432cca135809edabcd9ccedd05576138b64b167445999005a6e1550132391d98" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-origins/DOMPurify-LICENSE", + "sha256": "8b6902e953e2eb2876412a4ba75291758b77e88e220962e3423af4d080db1a59" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-origins/marked-LICENSE", + "sha256": "8e3a3f82f59a60958f56ca08f445647c32a4733dc7ca6c2c46f6eb898471ab9c" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-origins/marked-vscode-license.txt", + "sha256": "43624283832b560f19539ec6d5766b7281acd4a63ada62e494c4e63c7a849bdb" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-origins/ATTRIBUTION.md", + "sha256": "3a0ab7f1036d6b1397bf94ff2700375b97db2db3bd576d195dc6d8a88e1a758e" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-path/ATTRIBUTION.md", + "sha256": "40583c701c0bcbd8e10935652a0a8b02e2073b0ef040fb7be7b939c437d8b8dc" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-dom/LICENSE.txt", + "sha256": "13217bb585c27ee298f49c7aec2ef74578bc0d644880906a89d2c3ccec5d647e" + }, + { + "component": "monaco-editor", + "version": "0.30.1", + "url": "http://127.0.0.1:8084/licenses/monaco-editor/core-dom/ATTRIBUTION.md", + "sha256": "0858d19261742809cecd7174a0a06b2b0013a4b9560b78aede1edd3dd350da21" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/console-feed/console-feed-3.2.2-LICENSE", + "sha256": "52412d7bc7ce4157ea628bbaacb8829e0a9cb3c58f57f99176126bc8cf2bfc85" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react/react-17.0.2-LICENSE", + "sha256": "52412d7bc7ce4157ea628bbaacb8829e0a9cb3c58f57f99176126bc8cf2bfc85" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-dom/react-dom-17.0.2-LICENSE", + "sha256": "52412d7bc7ce4157ea628bbaacb8829e0a9cb3c58f57f99176126bc8cf2bfc85" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/scheduler/scheduler-0.20.2-LICENSE", + "sha256": "52412d7bc7ce4157ea628bbaacb8829e0a9cb3c58f57f99176126bc8cf2bfc85" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/object-assign/object-assign-4.1.1-license", + "sha256": "6fb9754611c20f6649f68805e8c990e83261f29316e29de9e6cedae607b8634c" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-is/react-is-16.13.1-LICENSE", + "sha256": "52412d7bc7ce4157ea628bbaacb8829e0a9cb3c58f57f99176126bc8cf2bfc85" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/prop-types/prop-types-15.7.2-LICENSE", + "sha256": "f657f99d3fb9647db92628e96007aabb46e5f04f33e49999075aab8e250ca7ce" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/shallowequal/shallowequal-1.1.0-LICENSE", + "sha256": "709e45bb17277819ce27e9abe5dc8e56fe93081e54adb6e6385517f28aa11ac4" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/process/process-0.11.10-LICENSE", + "sha256": "59a400d04c5078579acc27ddd6452c1bdf763f9506e01364700935fbb1a7c91b" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/hoist-non-react-statics/hoist-non-react-statics-3.3.2-LICENSE.md", + "sha256": "eb32ff0ec52b6ea86e3d3e06c6ad1b68ee03798b6729af13919f6d5c14b368f3" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/is-dom/is-dom-1.1.0-LICENSE", + "sha256": "ba38703a10a53a91d4ff87bc1d930714104ead8d53f3f86936b7772c440be96f" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/is-object/is-object-1.0.2-LICENSE", + "sha256": "950429b35f82e225a613a0638e7933855a4ce05172bd36dc060093ba58793bbe" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/is-window/is-window-1.0.2-LICENSE", + "sha256": "6f19793f004670a8c873dde23d0f970eb32dd3bba8078980a42a4fb71cb1a048" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/linkifyjs/linkifyjs-2.1.9-LICENSE", + "sha256": "c66691e7e051cf0e1538a2c7d33f337b1dfe37bb0726724917dd1ceaf043a2df" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-core/emotion-core-10.3.0-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-css/emotion-css-10.0.27-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-cache/emotion-cache-10.0.29-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-styled/emotion-styled-10.0.27-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-styled-base/emotion-styled-base-10.3.0-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-theming/emotion-theming-10.3.0-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/styled-components/styled-components-5.3.3-UPSTREAM-LICENSE", + "sha256": "5b893305a717230e5b0024ff5ca3eec1dc05ba600c9b140730488d97ce56f1e6" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/babel-runtime/babel-runtime-7.16.3-LICENSE", + "sha256": "117da2af0d4ce0fe1c8e19b5cff9dcd806adf973d328d27b11d4448c4ff24f76" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-sheet/emotion-sheet-0.9.4-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-stylis/emotion-stylis-0.8.5-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-weak-memoize/emotion-weak-memoize-0.2.5-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-utils/emotion-utils-0.11.3-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-hash/emotion-hash-0.8.0-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-unitless/emotion-unitless-0.7.5-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-memoize/emotion-memoize-0.7.4-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-serialize/emotion-serialize-0.11.16-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/emotion-is-prop-valid/emotion-is-prop-valid-0.8.8-LICENSE", + "sha256": "6e8d23763cf7cb707ad8f6677aa502ebeca1dda447e6d6e57f6549c1625b9c4a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-inspector/react-inspector-5.1.1-LICENSE", + "sha256": "62d1c62e4b7eaee1a57e4a27b5cf6f2c0dc554b88326fc40bc512f150b340deb" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/parcel-bundler/parcel-bundler-1.12.5-LICENSE", + "sha256": "5cfba9d5711264d45a2431a53c79f597cef12720cc7c764db2602daa92d0bd2a" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/chromium-string-utils/LICENSE", + "sha256": "7a209dd1b94cabdb5ea9c6f9164b9546ffa5daaa671e7767d49510db055f5c51" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/stylis-rule-sheet/LICENSE", + "sha256": "99a75da65634b772687781c054ffe679569c1770c398f96427677899fe0ca8d7" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-inspector-babel/LICENSE", + "sha256": "117da2af0d4ce0fe1c8e19b5cff9dcd806adf973d328d27b11d4448c4ff24f76" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/regenerator-runtime/LICENSE", + "sha256": "51887a3d47051ac2fce1210562e5b9fe0830a8a8fabeb272c2d586eeb18a05fd" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/simple-html-tokenizer/LICENSE", + "sha256": "c41881de2a9f2200936648343500524be154eb79f649582f9582dd251b051b11" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/replicator/LICENSE", + "sha256": "52f634086a97b3861a35afff7acf703ddbd5add8e617f6a1f540ae2f2c621284" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/stylis/LICENSE", + "sha256": "045109dfd0547aa898408d08593e1adc41e9705519ba8a20baff89e7c6c52e91" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/murmurhash-js/README.md", + "sha256": "73b67c593a2a0d6395bfe90d3bad32556ed5e7ce71883062efebc643d4e4b7b4" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/murmurhash2/PUBLIC-DOMAIN.txt", + "sha256": "50e13b0a1963f0b382255d2425df245dbdfd209201621e8c157687caedbbb949" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/stackoverflow/LICENSE", + "sha256": "28a9529c7d0bb4dc51f4bf5c116a3d16ef247a052f7591466768ddf563fd1cf5" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/stackoverflow/SOURCE.js", + "sha256": "966fdc4a37e65e90c2dc1f6ba9385e572c75ce4c0647d35f3ce566ed9ef7f6bb" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/stackoverflow/ATTRIBUTION.md", + "sha256": "4ac7ae9b19a1201b6cfe6af1d35ec85d015a2de8fb1aac6b03796145e648a667" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-pure-render/LICENSE", + "sha256": "65a1f00f35ea469048896fbfec3c5faed7d3fe7c7e0be2a0478470b59d9e1439" + }, + { + "component": "console", + "version": "legacy-vendor-with-TS-adapter", + "url": "http://127.0.0.1:8084/licenses/console/react-pure-render/ATTRIBUTION.md", + "sha256": "9069fed07cc10fc36ef6b168ab0a75c3f1c882c077d5117b992f5c96d1eea0cc" + } + ] + } + } + ] + }, + "limitations": [ + "Original WinJS adaptation version is unknown;4.4.5 is a fixed comparison only.", + "Six mapped source blocks and exact shipped archive bytes do not prove full original DOM/core compilation.", + "Unicode and other embedded-origin review and SITE-07/VENDOR-06 remain open.", + "No runtime, CSS, worker, player API or dependency changed.", + "No remote deployment, physical-device signoff or release review claimed." + ] +} diff --git a/refactor/baselines/site-vendor/monaco-dom/ATTRIBUTION.md.txt b/refactor/baselines/site-vendor/monaco-dom/ATTRIBUTION.md.txt new file mode 100644 index 000000000..2fc2315f5 --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-dom/ATTRIBUTION.md.txt @@ -0,0 +1,29 @@ +# WinJS-derived DOM helpers in Monaco + +Monaco 0.30.1 embeds VS Code dom.ts from commit +829382514cb1065f5ebb90f436e1c6103e153953. Its Microsoft/MIT source explicitly +marks SizeUtils, getTopLeftOffset, getTotalWidth, getContentHeight and +getTotalHeight as adapted from WinJS; getContentWidth uses the same dimension +helpers. These six declaration blocks match the editor's archived source map. + +The comment does not name an original WinJS release. That original version +remains unknown. For a reproducible comparison, WinJS 4.4.5 at commit +4329b1133b243d9ded3b5a1f98d096ee8e80e889 supplies _ElementUtilities.js and the +complete Microsoft MIT license included alongside this note. This does not +assert that Monaco bundled unmodified WinJS 4.4.5 or the entire WinJS library. + +Existing adaptations include CSS property access and pixel conversion changes, +separate typed dimension helpers, and position calculations with borders, RTL +scroll handling and shadow-root checks. The WinJS reference has its own computed +style, unit conversion and position implementation. These differences are not +changes introduced by the ArtPlayer refactor. No editor runtime bytes changed. + +Sources: +- https://github.com/microsoft/vscode/blob/829382514cb1065f5ebb90f436e1c6103e153953/src/vs/base/browser/dom.ts +- https://github.com/winjs/winjs/blob/4329b1133b243d9ded3b5a1f98d096ee8e80e889/src/js/WinJS/Utilities/_ElementUtilities.js +- https://github.com/winjs/winjs/blob/4329b1133b243d9ded3b5a1f98d096ee8e80e889/License.txt + +Complete reference terms: [WinJS license](./LICENSE.txt). The editor's existing +Microsoft MIT license and original ThirdPartyNotices are retained. Unicode +data, other embedded sources and complete original core compilation remain +separate review work; this notice is not a claim of complete source clearance. diff --git a/refactor/baselines/site-vendor/monaco-dom/vscode-dom.txt b/refactor/baselines/site-vendor/monaco-dom/vscode-dom.txt new file mode 100644 index 000000000..6148eb300 --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-dom/vscode-dom.txt @@ -0,0 +1,1623 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as browser from 'vs/base/browser/browser'; +import { BrowserFeatures } from 'vs/base/browser/canIUse'; +import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { IMouseEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import { TimeoutTimer } from 'vs/base/common/async'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { Emitter, Event } from 'vs/base/common/event'; +import * as dompurify from 'vs/base/browser/dompurify/dompurify'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { FileAccess, RemoteAuthorities, Schemas } from 'vs/base/common/network'; +import * as platform from 'vs/base/common/platform'; +import { withNullAsUndefined } from 'vs/base/common/types'; +import { URI } from 'vs/base/common/uri'; + +export function clearNode(node: HTMLElement): void { + while (node.firstChild) { + node.firstChild.remove(); + } +} + +/** + * @deprecated Use node.isConnected directly + */ +export function isInDOM(node: Node | null): boolean { + return node?.isConnected ?? false; +} + +class DomListener implements IDisposable { + + private _handler: (e: any) => void; + private _node: EventTarget; + private readonly _type: string; + private readonly _options: boolean | AddEventListenerOptions; + + constructor(node: EventTarget, type: string, handler: (e: any) => void, options?: boolean | AddEventListenerOptions) { + this._node = node; + this._type = type; + this._handler = handler; + this._options = (options || false); + this._node.addEventListener(this._type, this._handler, this._options); + } + + public dispose(): void { + if (!this._handler) { + // Already disposed + return; + } + + this._node.removeEventListener(this._type, this._handler, this._options); + + // Prevent leakers from holding on to the dom or handler func + this._node = null!; + this._handler = null!; + } +} + +export function addDisposableListener(node: EventTarget, type: K, handler: (event: GlobalEventHandlersEventMap[K]) => void, useCapture?: boolean): IDisposable; +export function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, useCapture?: boolean): IDisposable; +export function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, options: AddEventListenerOptions): IDisposable; +export function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, useCaptureOrOptions?: boolean | AddEventListenerOptions): IDisposable { + return new DomListener(node, type, handler, useCaptureOrOptions); +} + +export interface IAddStandardDisposableListenerSignature { + (node: HTMLElement, type: 'click', handler: (event: IMouseEvent) => void, useCapture?: boolean): IDisposable; + (node: HTMLElement, type: 'mousedown', handler: (event: IMouseEvent) => void, useCapture?: boolean): IDisposable; + (node: HTMLElement, type: 'keydown', handler: (event: IKeyboardEvent) => void, useCapture?: boolean): IDisposable; + (node: HTMLElement, type: 'keypress', handler: (event: IKeyboardEvent) => void, useCapture?: boolean): IDisposable; + (node: HTMLElement, type: 'keyup', handler: (event: IKeyboardEvent) => void, useCapture?: boolean): IDisposable; + (node: HTMLElement, type: string, handler: (event: any) => void, useCapture?: boolean): IDisposable; +} +function _wrapAsStandardMouseEvent(handler: (e: IMouseEvent) => void): (e: MouseEvent) => void { + return function (e: MouseEvent) { + return handler(new StandardMouseEvent(e)); + }; +} +function _wrapAsStandardKeyboardEvent(handler: (e: IKeyboardEvent) => void): (e: KeyboardEvent) => void { + return function (e: KeyboardEvent) { + return handler(new StandardKeyboardEvent(e)); + }; +} +export let addStandardDisposableListener: IAddStandardDisposableListenerSignature = function addStandardDisposableListener(node: HTMLElement, type: string, handler: (event: any) => void, useCapture?: boolean): IDisposable { + let wrapHandler = handler; + + if (type === 'click' || type === 'mousedown') { + wrapHandler = _wrapAsStandardMouseEvent(handler); + } else if (type === 'keydown' || type === 'keypress' || type === 'keyup') { + wrapHandler = _wrapAsStandardKeyboardEvent(handler); + } + + return addDisposableListener(node, type, wrapHandler, useCapture); +}; + +export let addStandardDisposableGenericMouseDownListner = function addStandardDisposableListener(node: HTMLElement, handler: (event: any) => void, useCapture?: boolean): IDisposable { + let wrapHandler = _wrapAsStandardMouseEvent(handler); + + return addDisposableGenericMouseDownListner(node, wrapHandler, useCapture); +}; + +export let addStandardDisposableGenericMouseUpListner = function addStandardDisposableListener(node: HTMLElement, handler: (event: any) => void, useCapture?: boolean): IDisposable { + let wrapHandler = _wrapAsStandardMouseEvent(handler); + + return addDisposableGenericMouseUpListner(node, wrapHandler, useCapture); +}; +export function addDisposableGenericMouseDownListner(node: EventTarget, handler: (event: any) => void, useCapture?: boolean): IDisposable { + return addDisposableListener(node, platform.isIOS && BrowserFeatures.pointerEvents ? EventType.POINTER_DOWN : EventType.MOUSE_DOWN, handler, useCapture); +} + +export function addDisposableGenericMouseMoveListner(node: EventTarget, handler: (event: any) => void, useCapture?: boolean): IDisposable { + return addDisposableListener(node, platform.isIOS && BrowserFeatures.pointerEvents ? EventType.POINTER_MOVE : EventType.MOUSE_MOVE, handler, useCapture); +} + +export function addDisposableGenericMouseUpListner(node: EventTarget, handler: (event: any) => void, useCapture?: boolean): IDisposable { + return addDisposableListener(node, platform.isIOS && BrowserFeatures.pointerEvents ? EventType.POINTER_UP : EventType.MOUSE_UP, handler, useCapture); +} +export function addDisposableNonBubblingMouseOutListener(node: Element, handler: (event: MouseEvent) => void): IDisposable { + return addDisposableListener(node, 'mouseout', (e: MouseEvent) => { + // Mouse out bubbles, so this is an attempt to ignore faux mouse outs coming from children elements + let toElement: Node | null = (e.relatedTarget); + while (toElement && toElement !== node) { + toElement = toElement.parentNode; + } + if (toElement === node) { + return; + } + + handler(e); + }); +} + +export function addDisposableNonBubblingPointerOutListener(node: Element, handler: (event: MouseEvent) => void): IDisposable { + return addDisposableListener(node, 'pointerout', (e: MouseEvent) => { + // Mouse out bubbles, so this is an attempt to ignore faux mouse outs coming from children elements + let toElement: Node | null = (e.relatedTarget); + while (toElement && toElement !== node) { + toElement = toElement.parentNode; + } + if (toElement === node) { + return; + } + + handler(e); + }); +} + +interface IRequestAnimationFrame { + (callback: (time: number) => void): number; +} +let _animationFrame: IRequestAnimationFrame | null = null; +function doRequestAnimationFrame(callback: (time: number) => void): number { + if (!_animationFrame) { + const emulatedRequestAnimationFrame = (callback: (time: number) => void): any => { + return setTimeout(() => callback(new Date().getTime()), 0); + }; + _animationFrame = ( + self.requestAnimationFrame + || (self).msRequestAnimationFrame + || (self).webkitRequestAnimationFrame + || (self).mozRequestAnimationFrame + || (self).oRequestAnimationFrame + || emulatedRequestAnimationFrame + ); + } + return _animationFrame.call(self, callback); +} + +/** + * Schedule a callback to be run at the next animation frame. + * This allows multiple parties to register callbacks that should run at the next animation frame. + * If currently in an animation frame, `runner` will be executed immediately. + * @return token that can be used to cancel the scheduled runner (only if `runner` was not executed immediately). + */ +export let runAtThisOrScheduleAtNextAnimationFrame: (runner: () => void, priority?: number) => IDisposable; +/** + * Schedule a callback to be run at the next animation frame. + * This allows multiple parties to register callbacks that should run at the next animation frame. + * If currently in an animation frame, `runner` will be executed at the next animation frame. + * @return token that can be used to cancel the scheduled runner. + */ +export let scheduleAtNextAnimationFrame: (runner: () => void, priority?: number) => IDisposable; + +class AnimationFrameQueueItem implements IDisposable { + + private _runner: () => void; + public priority: number; + private _canceled: boolean; + + constructor(runner: () => void, priority: number = 0) { + this._runner = runner; + this.priority = priority; + this._canceled = false; + } + + public dispose(): void { + this._canceled = true; + } + + public execute(): void { + if (this._canceled) { + return; + } + + try { + this._runner(); + } catch (e) { + onUnexpectedError(e); + } + } + + // Sort by priority (largest to lowest) + public static sort(a: AnimationFrameQueueItem, b: AnimationFrameQueueItem): number { + return b.priority - a.priority; + } +} + +(function () { + /** + * The runners scheduled at the next animation frame + */ + let NEXT_QUEUE: AnimationFrameQueueItem[] = []; + /** + * The runners scheduled at the current animation frame + */ + let CURRENT_QUEUE: AnimationFrameQueueItem[] | null = null; + /** + * A flag to keep track if the native requestAnimationFrame was already called + */ + let animFrameRequested = false; + /** + * A flag to indicate if currently handling a native requestAnimationFrame callback + */ + let inAnimationFrameRunner = false; + + let animationFrameRunner = () => { + animFrameRequested = false; + + CURRENT_QUEUE = NEXT_QUEUE; + NEXT_QUEUE = []; + + inAnimationFrameRunner = true; + while (CURRENT_QUEUE.length > 0) { + CURRENT_QUEUE.sort(AnimationFrameQueueItem.sort); + let top = CURRENT_QUEUE.shift()!; + top.execute(); + } + inAnimationFrameRunner = false; + }; + + scheduleAtNextAnimationFrame = (runner: () => void, priority: number = 0) => { + let item = new AnimationFrameQueueItem(runner, priority); + NEXT_QUEUE.push(item); + + if (!animFrameRequested) { + animFrameRequested = true; + doRequestAnimationFrame(animationFrameRunner); + } + + return item; + }; + + runAtThisOrScheduleAtNextAnimationFrame = (runner: () => void, priority?: number) => { + if (inAnimationFrameRunner) { + let item = new AnimationFrameQueueItem(runner, priority); + CURRENT_QUEUE!.push(item); + return item; + } else { + return scheduleAtNextAnimationFrame(runner, priority); + } + }; +})(); + +export function measure(callback: () => void): IDisposable { + return scheduleAtNextAnimationFrame(callback, 10000 /* must be early */); +} + +export function modify(callback: () => void): IDisposable { + return scheduleAtNextAnimationFrame(callback, -10000 /* must be late */); +} + +/** + * Add a throttled listener. `handler` is fired at most every 8.33333ms or with the next animation frame (if browser supports it). + */ +export interface IEventMerger { + (lastEvent: R | null, currentEvent: E): R; +} + +export interface DOMEvent { + preventDefault(): void; + stopPropagation(): void; +} + +const MINIMUM_TIME_MS = 8; +const DEFAULT_EVENT_MERGER: IEventMerger = function (lastEvent: DOMEvent | null, currentEvent: DOMEvent) { + return currentEvent; +}; + +class TimeoutThrottledDomListener extends Disposable { + + constructor(node: any, type: string, handler: (event: R) => void, eventMerger: IEventMerger = DEFAULT_EVENT_MERGER, minimumTimeMs: number = MINIMUM_TIME_MS) { + super(); + + let lastEvent: R | null = null; + let lastHandlerTime = 0; + let timeout = this._register(new TimeoutTimer()); + + let invokeHandler = () => { + lastHandlerTime = (new Date()).getTime(); + handler(lastEvent); + lastEvent = null; + }; + + this._register(addDisposableListener(node, type, (e) => { + + lastEvent = eventMerger(lastEvent, e); + let elapsedTime = (new Date()).getTime() - lastHandlerTime; + + if (elapsedTime >= minimumTimeMs) { + timeout.cancel(); + invokeHandler(); + } else { + timeout.setIfNotSet(invokeHandler, minimumTimeMs - elapsedTime); + } + })); + } +} + +export function addDisposableThrottledListener(node: any, type: string, handler: (event: R) => void, eventMerger?: IEventMerger, minimumTimeMs?: number): IDisposable { + return new TimeoutThrottledDomListener(node, type, handler, eventMerger, minimumTimeMs); +} + +export function getComputedStyle(el: HTMLElement): CSSStyleDeclaration { + return document.defaultView!.getComputedStyle(el, null); +} + +export function getClientArea(element: HTMLElement): Dimension { + + // Try with DOM clientWidth / clientHeight + if (element !== document.body) { + return new Dimension(element.clientWidth, element.clientHeight); + } + + // If visual view port exits and it's on mobile, it should be used instead of window innerWidth / innerHeight, or document.body.clientWidth / document.body.clientHeight + if (platform.isIOS && window.visualViewport) { + return new Dimension(window.visualViewport.width, window.visualViewport.height); + } + + // Try innerWidth / innerHeight + if (window.innerWidth && window.innerHeight) { + return new Dimension(window.innerWidth, window.innerHeight); + } + + // Try with document.body.clientWidth / document.body.clientHeight + if (document.body && document.body.clientWidth && document.body.clientHeight) { + return new Dimension(document.body.clientWidth, document.body.clientHeight); + } + + // Try with document.documentElement.clientWidth / document.documentElement.clientHeight + if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientHeight) { + return new Dimension(document.documentElement.clientWidth, document.documentElement.clientHeight); + } + + throw new Error('Unable to figure out browser width and height'); +} + +class SizeUtils { + // Adapted from WinJS + // Converts a CSS positioning string for the specified element to pixels. + private static convertToPixels(element: HTMLElement, value: string): number { + return parseFloat(value) || 0; + } + + private static getDimension(element: HTMLElement, cssPropertyName: string, jsPropertyName: string): number { + let computedStyle: CSSStyleDeclaration = getComputedStyle(element); + let value = '0'; + if (computedStyle) { + if (computedStyle.getPropertyValue) { + value = computedStyle.getPropertyValue(cssPropertyName); + } else { + // IE8 + value = (computedStyle).getAttribute(jsPropertyName); + } + } + return SizeUtils.convertToPixels(element, value); + } + + static getBorderLeftWidth(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'border-left-width', 'borderLeftWidth'); + } + static getBorderRightWidth(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'border-right-width', 'borderRightWidth'); + } + static getBorderTopWidth(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'border-top-width', 'borderTopWidth'); + } + static getBorderBottomWidth(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'border-bottom-width', 'borderBottomWidth'); + } + + static getPaddingLeft(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'padding-left', 'paddingLeft'); + } + static getPaddingRight(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'padding-right', 'paddingRight'); + } + static getPaddingTop(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'padding-top', 'paddingTop'); + } + static getPaddingBottom(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'padding-bottom', 'paddingBottom'); + } + + static getMarginLeft(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'margin-left', 'marginLeft'); + } + static getMarginTop(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'margin-top', 'marginTop'); + } + static getMarginRight(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'margin-right', 'marginRight'); + } + static getMarginBottom(element: HTMLElement): number { + return SizeUtils.getDimension(element, 'margin-bottom', 'marginBottom'); + } +} + +// ---------------------------------------------------------------------------------------- +// Position & Dimension + +export interface IDimension { + readonly width: number; + readonly height: number; +} + +export class Dimension implements IDimension { + + static readonly None = new Dimension(0, 0); + + constructor( + public readonly width: number, + public readonly height: number, + ) { } + + with(width: number = this.width, height: number = this.height): Dimension { + if (width !== this.width || height !== this.height) { + return new Dimension(width, height); + } else { + return this; + } + } + + static is(obj: unknown): obj is IDimension { + return typeof obj === 'object' && typeof (obj).height === 'number' && typeof (obj).width === 'number'; + } + + static lift(obj: IDimension): Dimension { + if (obj instanceof Dimension) { + return obj; + } else { + return new Dimension(obj.width, obj.height); + } + } + + static equals(a: Dimension | undefined, b: Dimension | undefined): boolean { + if (a === b) { + return true; + } + if (!a || !b) { + return false; + } + return a.width === b.width && a.height === b.height; + } +} + +export function getTopLeftOffset(element: HTMLElement): { left: number; top: number; } { + // Adapted from WinJS.Utilities.getPosition + // and added borders to the mix + + let offsetParent = element.offsetParent; + let top = element.offsetTop; + let left = element.offsetLeft; + + while ( + (element = element.parentNode) !== null + && element !== document.body + && element !== document.documentElement + ) { + top -= element.scrollTop; + const c = isShadowRoot(element) ? null : getComputedStyle(element); + if (c) { + left -= c.direction !== 'rtl' ? element.scrollLeft : -element.scrollLeft; + } + + if (element === offsetParent) { + left += SizeUtils.getBorderLeftWidth(element); + top += SizeUtils.getBorderTopWidth(element); + top += element.offsetTop; + left += element.offsetLeft; + offsetParent = element.offsetParent; + } + } + + return { + left: left, + top: top + }; +} + +export interface IDomNodePagePosition { + left: number; + top: number; + width: number; + height: number; +} + +export function size(element: HTMLElement, width: number | null, height: number | null): void { + if (typeof width === 'number') { + element.style.width = `${width}px`; + } + + if (typeof height === 'number') { + element.style.height = `${height}px`; + } +} + +export function position(element: HTMLElement, top: number, right?: number, bottom?: number, left?: number, position: string = 'absolute'): void { + if (typeof top === 'number') { + element.style.top = `${top}px`; + } + + if (typeof right === 'number') { + element.style.right = `${right}px`; + } + + if (typeof bottom === 'number') { + element.style.bottom = `${bottom}px`; + } + + if (typeof left === 'number') { + element.style.left = `${left}px`; + } + + element.style.position = position; +} + +/** + * Returns the position of a dom node relative to the entire page. + */ +export function getDomNodePagePosition(domNode: HTMLElement): IDomNodePagePosition { + let bb = domNode.getBoundingClientRect(); + return { + left: bb.left + StandardWindow.scrollX, + top: bb.top + StandardWindow.scrollY, + width: bb.width, + height: bb.height + }; +} + +export interface IStandardWindow { + readonly scrollX: number; + readonly scrollY: number; +} + +export const StandardWindow: IStandardWindow = new class implements IStandardWindow { + get scrollX(): number { + if (typeof window.scrollX === 'number') { + // modern browsers + return window.scrollX; + } else { + return document.body.scrollLeft + document.documentElement!.scrollLeft; + } + } + + get scrollY(): number { + if (typeof window.scrollY === 'number') { + // modern browsers + return window.scrollY; + } else { + return document.body.scrollTop + document.documentElement!.scrollTop; + } + } +}; + +// Adapted from WinJS +// Gets the width of the element, including margins. +export function getTotalWidth(element: HTMLElement): number { + let margin = SizeUtils.getMarginLeft(element) + SizeUtils.getMarginRight(element); + return element.offsetWidth + margin; +} + +export function getContentWidth(element: HTMLElement): number { + let border = SizeUtils.getBorderLeftWidth(element) + SizeUtils.getBorderRightWidth(element); + let padding = SizeUtils.getPaddingLeft(element) + SizeUtils.getPaddingRight(element); + return element.offsetWidth - border - padding; +} + +export function getTotalScrollWidth(element: HTMLElement): number { + let margin = SizeUtils.getMarginLeft(element) + SizeUtils.getMarginRight(element); + return element.scrollWidth + margin; +} + +// Adapted from WinJS +// Gets the height of the content of the specified element. The content height does not include borders or padding. +export function getContentHeight(element: HTMLElement): number { + let border = SizeUtils.getBorderTopWidth(element) + SizeUtils.getBorderBottomWidth(element); + let padding = SizeUtils.getPaddingTop(element) + SizeUtils.getPaddingBottom(element); + return element.offsetHeight - border - padding; +} + +// Adapted from WinJS +// Gets the height of the element, including its margins. +export function getTotalHeight(element: HTMLElement): number { + let margin = SizeUtils.getMarginTop(element) + SizeUtils.getMarginBottom(element); + return element.offsetHeight + margin; +} + +// Gets the left coordinate of the specified element relative to the specified parent. +function getRelativeLeft(element: HTMLElement, parent: HTMLElement): number { + if (element === null) { + return 0; + } + + let elementPosition = getTopLeftOffset(element); + let parentPosition = getTopLeftOffset(parent); + return elementPosition.left - parentPosition.left; +} + +export function getLargestChildWidth(parent: HTMLElement, children: HTMLElement[]): number { + let childWidths = children.map((child) => { + return Math.max(getTotalScrollWidth(child), getTotalWidth(child)) + getRelativeLeft(child, parent) || 0; + }); + let maxWidth = Math.max(...childWidths); + return maxWidth; +} + +// ---------------------------------------------------------------------------------------- + +export function isAncestor(testChild: Node | null, testAncestor: Node | null): boolean { + while (testChild) { + if (testChild === testAncestor) { + return true; + } + testChild = testChild.parentNode; + } + + return false; +} + +const parentFlowToDataKey = 'parentFlowToElementId'; + +/** + * Set an explicit parent to use for nodes that are not part of the + * regular dom structure. + */ +export function setParentFlowTo(fromChildElement: HTMLElement, toParentElement: Element): void { + fromChildElement.dataset[parentFlowToDataKey] = toParentElement.id; +} + +function getParentFlowToElement(node: HTMLElement): HTMLElement | null { + const flowToParentId = node.dataset[parentFlowToDataKey]; + if (typeof flowToParentId === 'string') { + return document.getElementById(flowToParentId); + } + return null; +} + +/** + * Check if `testAncestor` is an ancestor of `testChild`, observing the explicit + * parents set by `setParentFlowTo`. + */ +export function isAncestorUsingFlowTo(testChild: Node, testAncestor: Node): boolean { + let node: Node | null = testChild; + while (node) { + if (node === testAncestor) { + return true; + } + + if (node instanceof HTMLElement) { + const flowToParentElement = getParentFlowToElement(node); + if (flowToParentElement) { + node = flowToParentElement; + continue; + } + } + node = node.parentNode; + } + + return false; +} + +export function findParentWithClass(node: HTMLElement, clazz: string, stopAtClazzOrNode?: string | HTMLElement): HTMLElement | null { + while (node && node.nodeType === node.ELEMENT_NODE) { + if (node.classList.contains(clazz)) { + return node; + } + + if (stopAtClazzOrNode) { + if (typeof stopAtClazzOrNode === 'string') { + if (node.classList.contains(stopAtClazzOrNode)) { + return null; + } + } else { + if (node === stopAtClazzOrNode) { + return null; + } + } + } + + node = node.parentNode; + } + + return null; +} + +export function hasParentWithClass(node: HTMLElement, clazz: string, stopAtClazzOrNode?: string | HTMLElement): boolean { + return !!findParentWithClass(node, clazz, stopAtClazzOrNode); +} + +export function isShadowRoot(node: Node): node is ShadowRoot { + return ( + node && !!(node).host && !!(node).mode + ); +} + +export function isInShadowDOM(domNode: Node): boolean { + return !!getShadowRoot(domNode); +} + +export function getShadowRoot(domNode: Node): ShadowRoot | null { + while (domNode.parentNode) { + if (domNode === document.body) { + // reached the body + return null; + } + domNode = domNode.parentNode; + } + return isShadowRoot(domNode) ? domNode : null; +} + +export function getActiveElement(): Element | null { + let result = document.activeElement; + + while (result?.shadowRoot) { + result = result.shadowRoot.activeElement; + } + + return result; +} + +export function createStyleSheet(container: HTMLElement = document.getElementsByTagName('head')[0]): HTMLStyleElement { + let style = document.createElement('style'); + style.type = 'text/css'; + style.media = 'screen'; + container.appendChild(style); + return style; +} + +export function createMetaElement(container: HTMLElement = document.getElementsByTagName('head')[0]): HTMLMetaElement { + let meta = document.createElement('meta'); + container.appendChild(meta); + return meta; +} + +let _sharedStyleSheet: HTMLStyleElement | null = null; +function getSharedStyleSheet(): HTMLStyleElement { + if (!_sharedStyleSheet) { + _sharedStyleSheet = createStyleSheet(); + } + return _sharedStyleSheet; +} + +function getDynamicStyleSheetRules(style: any) { + if (style?.sheet?.rules) { + // Chrome, IE + return style.sheet.rules; + } + if (style?.sheet?.cssRules) { + // FF + return style.sheet.cssRules; + } + return []; +} + +export function createCSSRule(selector: string, cssText: string, style: HTMLStyleElement = getSharedStyleSheet()): void { + if (!style || !cssText) { + return; + } + + (style.sheet).insertRule(selector + '{' + cssText + '}', 0); +} + +export function removeCSSRulesContainingSelector(ruleName: string, style: HTMLStyleElement = getSharedStyleSheet()): void { + if (!style) { + return; + } + + let rules = getDynamicStyleSheetRules(style); + let toDelete: number[] = []; + for (let i = 0; i < rules.length; i++) { + let rule = rules[i]; + if (rule.selectorText.indexOf(ruleName) !== -1) { + toDelete.push(i); + } + } + + for (let i = toDelete.length - 1; i >= 0; i--) { + (style.sheet).deleteRule(toDelete[i]); + } +} + +export function isHTMLElement(o: any): o is HTMLElement { + if (typeof HTMLElement === 'object') { + return o instanceof HTMLElement; + } + return o && typeof o === 'object' && o.nodeType === 1 && typeof o.nodeName === 'string'; +} + +export const EventType = { + // Mouse + CLICK: 'click', + AUXCLICK: 'auxclick', + DBLCLICK: 'dblclick', + MOUSE_UP: 'mouseup', + MOUSE_DOWN: 'mousedown', + MOUSE_OVER: 'mouseover', + MOUSE_MOVE: 'mousemove', + MOUSE_OUT: 'mouseout', + MOUSE_ENTER: 'mouseenter', + MOUSE_LEAVE: 'mouseleave', + MOUSE_WHEEL: 'wheel', + POINTER_UP: 'pointerup', + POINTER_DOWN: 'pointerdown', + POINTER_MOVE: 'pointermove', + CONTEXT_MENU: 'contextmenu', + WHEEL: 'wheel', + // Keyboard + KEY_DOWN: 'keydown', + KEY_PRESS: 'keypress', + KEY_UP: 'keyup', + // HTML Document + LOAD: 'load', + BEFORE_UNLOAD: 'beforeunload', + UNLOAD: 'unload', + ABORT: 'abort', + ERROR: 'error', + RESIZE: 'resize', + SCROLL: 'scroll', + FULLSCREEN_CHANGE: 'fullscreenchange', + WK_FULLSCREEN_CHANGE: 'webkitfullscreenchange', + // Form + SELECT: 'select', + CHANGE: 'change', + SUBMIT: 'submit', + RESET: 'reset', + FOCUS: 'focus', + FOCUS_IN: 'focusin', + FOCUS_OUT: 'focusout', + BLUR: 'blur', + INPUT: 'input', + // Local Storage + STORAGE: 'storage', + // Drag + DRAG_START: 'dragstart', + DRAG: 'drag', + DRAG_ENTER: 'dragenter', + DRAG_LEAVE: 'dragleave', + DRAG_OVER: 'dragover', + DROP: 'drop', + DRAG_END: 'dragend', + // Animation + ANIMATION_START: browser.isWebKit ? 'webkitAnimationStart' : 'animationstart', + ANIMATION_END: browser.isWebKit ? 'webkitAnimationEnd' : 'animationend', + ANIMATION_ITERATION: browser.isWebKit ? 'webkitAnimationIteration' : 'animationiteration' +} as const; + +export interface EventLike { + preventDefault(): void; + stopPropagation(): void; +} + +export const EventHelper = { + stop: function (e: EventLike, cancelBubble?: boolean) { + if (e.preventDefault) { + e.preventDefault(); + } else { + // IE8 + (e).returnValue = false; + } + + if (cancelBubble) { + if (e.stopPropagation) { + e.stopPropagation(); + } else { + // IE8 + (e).cancelBubble = true; + } + } + } +}; + +export interface IFocusTracker extends Disposable { + onDidFocus: Event; + onDidBlur: Event; + refreshState?(): void; +} + +export function saveParentsScrollTop(node: Element): number[] { + let r: number[] = []; + for (let i = 0; node && node.nodeType === node.ELEMENT_NODE; i++) { + r[i] = node.scrollTop; + node = node.parentNode; + } + return r; +} + +export function restoreParentsScrollTop(node: Element, state: number[]): void { + for (let i = 0; node && node.nodeType === node.ELEMENT_NODE; i++) { + if (node.scrollTop !== state[i]) { + node.scrollTop = state[i]; + } + node = node.parentNode; + } +} + +class FocusTracker extends Disposable implements IFocusTracker { + + private readonly _onDidFocus = this._register(new Emitter()); + public readonly onDidFocus: Event = this._onDidFocus.event; + + private readonly _onDidBlur = this._register(new Emitter()); + public readonly onDidBlur: Event = this._onDidBlur.event; + + private _refreshStateHandler: () => void; + + constructor(element: HTMLElement | Window) { + super(); + let hasFocus = isAncestor(document.activeElement, element); + let loosingFocus = false; + + const onFocus = () => { + loosingFocus = false; + if (!hasFocus) { + hasFocus = true; + this._onDidFocus.fire(); + } + }; + + const onBlur = () => { + if (hasFocus) { + loosingFocus = true; + window.setTimeout(() => { + if (loosingFocus) { + loosingFocus = false; + hasFocus = false; + this._onDidBlur.fire(); + } + }, 0); + } + }; + + this._refreshStateHandler = () => { + let currentNodeHasFocus = isAncestor(document.activeElement, element); + if (currentNodeHasFocus !== hasFocus) { + if (hasFocus) { + onBlur(); + } else { + onFocus(); + } + } + }; + + this._register(addDisposableListener(element, EventType.FOCUS, onFocus, true)); + this._register(addDisposableListener(element, EventType.BLUR, onBlur, true)); + } + + refreshState() { + this._refreshStateHandler(); + } +} + +export function trackFocus(element: HTMLElement | Window): IFocusTracker { + return new FocusTracker(element); +} + +export function after(sibling: HTMLElement, child: T): T { + sibling.after(child); + return child; +} + +export function append(parent: HTMLElement, child: T): T; +export function append(parent: HTMLElement, ...children: (T | string)[]): void; +export function append(parent: HTMLElement, ...children: (T | string)[]): T | void { + parent.append(...children); + if (children.length === 1 && typeof children[0] !== 'string') { + return children[0]; + } +} + +export function prepend(parent: HTMLElement, child: T): T { + parent.insertBefore(child, parent.firstChild); + return child; +} + +/** + * Removes all children from `parent` and appends `children` + */ +export function reset(parent: HTMLElement, ...children: Array): void { + parent.innerText = ''; + append(parent, ...children); +} + +const SELECTOR_REGEX = /([\w\-]+)?(#([\w\-]+))?((\.([\w\-]+))*)/; + +export enum Namespace { + HTML = 'http://www.w3.org/1999/xhtml', + SVG = 'http://www.w3.org/2000/svg' +} + +function _$(namespace: Namespace, description: string, attrs?: { [key: string]: any; }, ...children: Array): T { + let match = SELECTOR_REGEX.exec(description); + + if (!match) { + throw new Error('Bad use of emmet'); + } + + attrs = { ...(attrs || {}) }; + + let tagName = match[1] || 'div'; + let result: T; + + if (namespace !== Namespace.HTML) { + result = document.createElementNS(namespace as string, tagName) as T; + } else { + result = document.createElement(tagName) as unknown as T; + } + + if (match[3]) { + result.id = match[3]; + } + if (match[4]) { + result.className = match[4].replace(/\./g, ' ').trim(); + } + + Object.keys(attrs).forEach(name => { + const value = attrs![name]; + + if (typeof value === 'undefined') { + return; + } + + if (/^on\w+$/.test(name)) { + (result)[name] = value; + } else if (name === 'selected') { + if (value) { + result.setAttribute(name, 'true'); + } + + } else { + result.setAttribute(name, value); + } + }); + + result.append(...children); + + return result as T; +} + +export function $(description: string, attrs?: { [key: string]: any; }, ...children: Array): T { + return _$(Namespace.HTML, description, attrs, ...children); +} + +$.SVG = function (description: string, attrs?: { [key: string]: any; }, ...children: Array): T { + return _$(Namespace.SVG, description, attrs, ...children); +}; + +export function join(nodes: Node[], separator: Node | string): Node[] { + const result: Node[] = []; + + nodes.forEach((node, index) => { + if (index > 0) { + if (separator instanceof Node) { + result.push(separator.cloneNode()); + } else { + result.push(document.createTextNode(separator)); + } + } + + result.push(node); + }); + + return result; +} + +export function show(...elements: HTMLElement[]): void { + for (let element of elements) { + element.style.display = ''; + element.removeAttribute('aria-hidden'); + } +} + +export function hide(...elements: HTMLElement[]): void { + for (let element of elements) { + element.style.display = 'none'; + element.setAttribute('aria-hidden', 'true'); + } +} + +function findParentWithAttribute(node: Node | null, attribute: string): HTMLElement | null { + while (node && node.nodeType === node.ELEMENT_NODE) { + if (node instanceof HTMLElement && node.hasAttribute(attribute)) { + return node; + } + + node = node.parentNode; + } + + return null; +} + +export function removeTabIndexAndUpdateFocus(node: HTMLElement): void { + if (!node || !node.hasAttribute('tabIndex')) { + return; + } + + // If we are the currently focused element and tabIndex is removed, + // standard DOM behavior is to move focus to the element. We + // typically never want that, rather put focus to the closest element + // in the hierarchy of the parent DOM nodes. + if (document.activeElement === node) { + let parentFocusable = findParentWithAttribute(node.parentElement, 'tabIndex'); + if (parentFocusable) { + parentFocusable.focus(); + } + } + + node.removeAttribute('tabindex'); +} + +export function getElementsByTagName(tag: string): HTMLElement[] { + return Array.prototype.slice.call(document.getElementsByTagName(tag), 0); +} + +export function finalHandler(fn: (event: T) => any): (event: T) => any { + return e => { + e.preventDefault(); + e.stopPropagation(); + fn(e); + }; +} + +export function domContentLoaded(): Promise { + return new Promise(resolve => { + const readyState = document.readyState; + if (readyState === 'complete' || (document && document.body !== null)) { + resolve(undefined); + } else { + window.addEventListener('DOMContentLoaded', resolve, false); + } + }); +} + +/** + * Find a value usable for a dom node size such that the likelihood that it would be + * displayed with constant screen pixels size is as high as possible. + * + * e.g. We would desire for the cursors to be 2px (CSS px) wide. Under a devicePixelRatio + * of 1.25, the cursor will be 2.5 screen pixels wide. Depending on how the dom node aligns/"snaps" + * with the screen pixels, it will sometimes be rendered with 2 screen pixels, and sometimes with 3 screen pixels. + */ +export function computeScreenAwareSize(cssPx: number): number { + const screenPx = window.devicePixelRatio * cssPx; + return Math.max(1, Math.floor(screenPx)) / window.devicePixelRatio; +} + +/** + * Open safely a new window. This is the best way to do so, but you cannot tell + * if the window was opened or if it was blocked by the browser's popup blocker. + * If you want to tell if the browser blocked the new window, use `windowOpenNoOpenerWithSuccess`. + * + * See https://github.com/microsoft/monaco-editor/issues/601 + * To protect against malicious code in the linked site, particularly phishing attempts, + * the window.opener should be set to null to prevent the linked site from having access + * to change the location of the current page. + * See https://mathiasbynens.github.io/rel-noopener/ + */ +export function windowOpenNoOpener(url: string): void { + // By using 'noopener' in the `windowFeatures` argument, the newly created window will + // not be able to use `window.opener` to reach back to the current page. + // See https://stackoverflow.com/a/46958731 + // See https://developer.mozilla.org/en-US/docs/Web/API/Window/open#noopener + // However, this also doesn't allow us to realize if the browser blocked + // the creation of the window. + window.open(url, '_blank', 'noopener'); +} + +/** + * Open safely a new window. This technique is not appropriate in certain contexts, + * like for example when the JS context is executing inside a sandboxed iframe. + * If it is not necessary to know if the browser blocked the new window, use + * `windowOpenNoOpener`. + * + * See https://github.com/microsoft/monaco-editor/issues/601 + * See https://github.com/microsoft/monaco-editor/issues/2474 + * See https://mathiasbynens.github.io/rel-noopener/ + */ +export function windowOpenNoOpenerWithSuccess(url: string): boolean { + const newTab = window.open(); + if (newTab) { + (newTab as any).opener = null; + newTab.location.href = url; + return true; + } + return false; +} + +export function animate(fn: () => void): IDisposable { + const step = () => { + fn(); + stepDisposable = scheduleAtNextAnimationFrame(step); + }; + + let stepDisposable = scheduleAtNextAnimationFrame(step); + return toDisposable(() => stepDisposable.dispose()); +} + +RemoteAuthorities.setPreferredWebSchema(/^https:/.test(window.location.href) ? 'https' : 'http'); + +/** + * returns url('...') + */ +export function asCSSUrl(uri: URI): string { + if (!uri) { + return `url('')`; + } + return `url('${FileAccess.asBrowserUri(uri).toString(true).replace(/'/g, '%27')}')`; +} + +export function asCSSPropertyValue(value: string) { + return `'${value.replace(/'/g, '%27')}'`; +} + +export function triggerDownload(dataOrUri: Uint8Array | URI, name: string): void { + + // If the data is provided as Buffer, we create a + // blob URL out of it to produce a valid link + let url: string; + if (URI.isUri(dataOrUri)) { + url = dataOrUri.toString(true); + } else { + const blob = new Blob([dataOrUri]); + url = URL.createObjectURL(blob); + + // Ensure to free the data from DOM eventually + setTimeout(() => URL.revokeObjectURL(url)); + } + + // In order to download from the browser, the only way seems + // to be creating a element with download attribute that + // points to the file to download. + // See also https://developers.google.com/web/updates/2011/08/Downloading-resources-in-HTML5-a-download + const anchor = document.createElement('a'); + document.body.appendChild(anchor); + anchor.download = name; + anchor.href = url; + anchor.click(); + + // Ensure to remove the element from DOM eventually + setTimeout(() => document.body.removeChild(anchor)); +} + +export function triggerUpload(): Promise { + return new Promise(resolve => { + + // In order to upload to the browser, create a + // input element of type `file` and click it + // to gather the selected files + const input = document.createElement('input'); + document.body.appendChild(input); + input.type = 'file'; + input.multiple = true; + + // Resolve once the input event has fired once + Event.once(Event.fromDOMEventEmitter(input, 'input'))(() => { + resolve(withNullAsUndefined(input.files)); + }); + + input.click(); + + // Ensure to remove the element from DOM eventually + setTimeout(() => document.body.removeChild(input)); + }); +} + +export enum DetectedFullscreenMode { + + /** + * The document is fullscreen, e.g. because an element + * in the document requested to be fullscreen. + */ + DOCUMENT = 1, + + /** + * The browser is fullscreen, e.g. because the user enabled + * native window fullscreen for it. + */ + BROWSER +} + +export interface IDetectedFullscreen { + + /** + * Figure out if the document is fullscreen or the browser. + */ + mode: DetectedFullscreenMode; + + /** + * Whether we know for sure that we are in fullscreen mode or + * it is a guess. + */ + guess: boolean; +} + +export function detectFullscreen(): IDetectedFullscreen | null { + + // Browser fullscreen: use DOM APIs to detect + if (document.fullscreenElement || (document).webkitFullscreenElement || (document).webkitIsFullScreen) { + return { mode: DetectedFullscreenMode.DOCUMENT, guess: false }; + } + + // There is no standard way to figure out if the browser + // is using native fullscreen. Via checking on screen + // height and comparing that to window height, we can guess + // it though. + + if (window.innerHeight === screen.height) { + // if the height of the window matches the screen height, we can + // safely assume that the browser is fullscreen because no browser + // chrome is taking height away (e.g. like toolbars). + return { mode: DetectedFullscreenMode.BROWSER, guess: false }; + } + + if (platform.isMacintosh || platform.isLinux) { + // macOS and Linux do not properly report `innerHeight`, only Windows does + if (window.outerHeight === screen.height && window.outerWidth === screen.width) { + // if the height of the browser matches the screen height, we can + // only guess that we are in fullscreen. It is also possible that + // the user has turned off taskbars in the OS and the browser is + // simply able to span the entire size of the screen. + return { mode: DetectedFullscreenMode.BROWSER, guess: true }; + } + } + + // Not in fullscreen + return null; +} + +// -- sanitize and trusted html + +/** + * Sanitizes the given `value` and reset the given `node` with it. + */ +export function safeInnerHtml(node: HTMLElement, value: string): void { + const options: dompurify.Config = { + ALLOWED_TAGS: ['a', 'button', 'blockquote', 'code', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'input', 'label', 'li', 'p', 'pre', 'select', 'small', 'span', 'strong', 'textarea', 'ul', 'ol'], + ALLOWED_ATTR: ['href', 'data-href', 'data-command', 'target', 'title', 'name', 'src', 'alt', 'class', 'id', 'role', 'tabindex', 'style', 'data-code', 'width', 'height', 'align', 'x-dispatch', 'required', 'checked', 'placeholder', 'type'], + RETURN_DOM: false, + RETURN_DOM_FRAGMENT: false, + }; + + const allowedProtocols = [Schemas.http, Schemas.https, Schemas.command]; + + // https://github.com/cure53/DOMPurify/blob/main/demos/hooks-scheme-allowlist.html + dompurify.addHook('afterSanitizeAttributes', (node) => { + // build an anchor to map URLs to + const anchor = document.createElement('a'); + + // check all href/src attributes for validity + for (const attr in ['href', 'src']) { + if (node.hasAttribute(attr)) { + anchor.href = node.getAttribute(attr) as string; + if (!allowedProtocols.includes(anchor.protocol)) { + node.removeAttribute(attr); + } + } + } + }); + + try { + const html = dompurify.sanitize(value, { ...options, RETURN_TRUSTED_TYPE: true }); + node.innerHTML = html as unknown as string; + } finally { + dompurify.removeHook('afterSanitizeAttributes'); + } +} + +/** + * Convert a Unicode string to a string in which each 16-bit unit occupies only one byte + * + * From https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa + */ +function toBinary(str: string): string { + const codeUnits = new Uint16Array(str.length); + for (let i = 0; i < codeUnits.length; i++) { + codeUnits[i] = str.charCodeAt(i); + } + let binary = ''; + const uint8array = new Uint8Array(codeUnits.buffer); + for (let i = 0; i < uint8array.length; i++) { + binary += String.fromCharCode(uint8array[i]); + } + return binary; +} + +/** + * Version of the global `btoa` function that handles multi-byte characters instead + * of throwing an exception. + */ +export function multibyteAwareBtoa(str: string): string { + return btoa(toBinary(str)); +} + +/** + * Typings for the https://wicg.github.io/file-system-access + * + * Use `supported(window)` to find out if the browser supports this kind of API. + */ +export namespace WebFileSystemAccess { + + export function supported(obj: any & Window): boolean { + if (typeof obj?.showDirectoryPicker === 'function') { + return true; + } + + return false; + } +} + +type ModifierKey = 'alt' | 'ctrl' | 'shift' | 'meta'; + +export interface IModifierKeyStatus { + altKey: boolean; + shiftKey: boolean; + ctrlKey: boolean; + metaKey: boolean; + lastKeyPressed?: ModifierKey; + lastKeyReleased?: ModifierKey; + event?: KeyboardEvent; +} + +export class ModifierKeyEmitter extends Emitter { + + private readonly _subscriptions = new DisposableStore(); + private _keyStatus: IModifierKeyStatus; + private static instance: ModifierKeyEmitter; + + private constructor() { + super(); + + this._keyStatus = { + altKey: false, + shiftKey: false, + ctrlKey: false, + metaKey: false + }; + + this._subscriptions.add(addDisposableListener(window, 'keydown', e => { + if (e.defaultPrevented) { + return; + } + + const event = new StandardKeyboardEvent(e); + // If Alt-key keydown event is repeated, ignore it #112347 + // Only known to be necessary for Alt-Key at the moment #115810 + if (event.keyCode === KeyCode.Alt && e.repeat) { + return; + } + + if (e.altKey && !this._keyStatus.altKey) { + this._keyStatus.lastKeyPressed = 'alt'; + } else if (e.ctrlKey && !this._keyStatus.ctrlKey) { + this._keyStatus.lastKeyPressed = 'ctrl'; + } else if (e.metaKey && !this._keyStatus.metaKey) { + this._keyStatus.lastKeyPressed = 'meta'; + } else if (e.shiftKey && !this._keyStatus.shiftKey) { + this._keyStatus.lastKeyPressed = 'shift'; + } else if (event.keyCode !== KeyCode.Alt) { + this._keyStatus.lastKeyPressed = undefined; + } else { + return; + } + + this._keyStatus.altKey = e.altKey; + this._keyStatus.ctrlKey = e.ctrlKey; + this._keyStatus.metaKey = e.metaKey; + this._keyStatus.shiftKey = e.shiftKey; + + if (this._keyStatus.lastKeyPressed) { + this._keyStatus.event = e; + this.fire(this._keyStatus); + } + }, true)); + + this._subscriptions.add(addDisposableListener(window, 'keyup', e => { + if (e.defaultPrevented) { + return; + } + + if (!e.altKey && this._keyStatus.altKey) { + this._keyStatus.lastKeyReleased = 'alt'; + } else if (!e.ctrlKey && this._keyStatus.ctrlKey) { + this._keyStatus.lastKeyReleased = 'ctrl'; + } else if (!e.metaKey && this._keyStatus.metaKey) { + this._keyStatus.lastKeyReleased = 'meta'; + } else if (!e.shiftKey && this._keyStatus.shiftKey) { + this._keyStatus.lastKeyReleased = 'shift'; + } else { + this._keyStatus.lastKeyReleased = undefined; + } + + if (this._keyStatus.lastKeyPressed !== this._keyStatus.lastKeyReleased) { + this._keyStatus.lastKeyPressed = undefined; + } + + this._keyStatus.altKey = e.altKey; + this._keyStatus.ctrlKey = e.ctrlKey; + this._keyStatus.metaKey = e.metaKey; + this._keyStatus.shiftKey = e.shiftKey; + + if (this._keyStatus.lastKeyReleased) { + this._keyStatus.event = e; + this.fire(this._keyStatus); + } + }, true)); + + this._subscriptions.add(addDisposableListener(document.body, 'mousedown', () => { + this._keyStatus.lastKeyPressed = undefined; + }, true)); + + this._subscriptions.add(addDisposableListener(document.body, 'mouseup', () => { + this._keyStatus.lastKeyPressed = undefined; + }, true)); + + this._subscriptions.add(addDisposableListener(document.body, 'mousemove', e => { + if (e.buttons) { + this._keyStatus.lastKeyPressed = undefined; + } + }, true)); + + this._subscriptions.add(addDisposableListener(window, 'blur', () => { + this.resetKeyStatus(); + })); + } + + get keyStatus(): IModifierKeyStatus { + return this._keyStatus; + } + + get isModifierPressed(): boolean { + return this._keyStatus.altKey || this._keyStatus.ctrlKey || this._keyStatus.metaKey || this._keyStatus.shiftKey; + } + + /** + * Allows to explicitly reset the key status based on more knowledge (#109062) + */ + resetKeyStatus(): void { + this.doResetKeyStatus(); + this.fire(this._keyStatus); + } + + private doResetKeyStatus(): void { + this._keyStatus = { + altKey: false, + shiftKey: false, + ctrlKey: false, + metaKey: false + }; + } + + static getInstance() { + if (!ModifierKeyEmitter.instance) { + ModifierKeyEmitter.instance = new ModifierKeyEmitter(); + } + + return ModifierKeyEmitter.instance; + } + + override dispose() { + super.dispose(); + this._subscriptions.dispose(); + } +} + +export function getCookieValue(name: string): string | undefined { + const match = document.cookie.match('(^|[^;]+)\\s*' + name + '\\s*=\\s*([^;]+)'); // See https://stackoverflow.com/a/25490531 + + return match ? match.pop() : undefined; +} + +export function addMatchMediaChangeListener(query: string, callback: () => void): void { + const mediaQueryList = window.matchMedia(query); + if (typeof mediaQueryList.addEventListener === 'function') { + mediaQueryList.addEventListener('change', callback); + } else { + // Safari 13.x + mediaQueryList.addListener(callback); + } +} + +export const enum ZIndex { + SASH = 35, + SuggestWidget = 40, + Hover = 50, + DragImage = 1000, + MenubarMenuItemsHolder = 2000, // quick-input-widget + ContextView = 2500, + ModalDialog = 2600, + PaneDropOverlay = 10000 +} diff --git a/refactor/baselines/site-vendor/monaco-dom/winjs-elements.txt b/refactor/baselines/site-vendor/monaco-dom/winjs-elements.txt new file mode 100644 index 000000000..6abc27ccf --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-dom/winjs-elements.txt @@ -0,0 +1,2676 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. +define([ + 'exports', + '../Core/_Global', + '../Core/_Base', + '../Core/_BaseUtils', + '../Core/_WinRT', + '../Promise', + '../Scheduler' +], function elementUtilities(exports, _Global, _Base, _BaseUtils, _WinRT, Promise, Scheduler) { + "use strict"; + + // not supported in WebWorker + if (!_Global.document) { + return; + } + + var _zoomToDuration = 167; + + // Firefox's implementation of getComputedStyle returns null when called within + // an iframe that is display:none. This is a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=548397 + // _getComputedStyle is a helper which is guaranteed to return an object whose keys + // map to strings. + var defaultComputedStyle = null; + function getDefaultComputedStyle() { + if (!defaultComputedStyle) { + defaultComputedStyle = {}; + Object.keys(_Global.CSS2Properties.prototype).forEach(function (cssProperty) { + defaultComputedStyle[cssProperty] = ""; + }); + } + return defaultComputedStyle; + } + function _getComputedStyle(element, pseudoElement) { + // jscs:disable disallowDirectGetComputedStyle + return _Global.getComputedStyle(element, pseudoElement) || getDefaultComputedStyle(); + // jscs:enable disallowDirectGetComputedStyle + } + + function removeEmpties(arr) { + var len = arr.length; + for (var i = len - 1; i >= 0; i--) { + if (!arr[i]) { + arr.splice(i, 1); + len--; + } + } + return len; + } + + function getClassName(e) { + var name = e.className || ""; + if (typeof (name) === "string") { + return name; + } else { + return name.baseVal || ""; + } + } + function setClassName(e, value) { + // SVG elements (which use e.className.baseVal) are never undefined, + // so this logic makes the comparison a bit more compact. + // + var name = e.className || ""; + if (typeof (name) === "string") { + e.className = value; + } else { + e.className.baseVal = value; + } + return e; + } + function addClass(e, name) { + /// + /// + /// Adds the specified class(es) to the specified element. Multiple classes can be added using space delimited names. + /// + /// + /// The element to which to add the class. + /// + /// + /// The name of the class to add, multiple classes can be added using space delimited names + /// + /// + /// The element. + /// + /// + if (e.classList) { + // Fastpath: adding a single class, no need to string split the argument + if (name.indexOf(" ") < 0) { + e.classList.add(name); + } else { + var namesToAdd = name.split(" "); + removeEmpties(namesToAdd); + + for (var i = 0, len = namesToAdd.length; i < len; i++) { + e.classList.add(namesToAdd[i]); + } + } + return e; + } else { + var className = getClassName(e); + var names = className.split(" "); + var l = removeEmpties(names); + var toAdd; + + // we have a fast path for the common case of a single name in the class name + // + if (name.indexOf(" ") >= 0) { + var namesToAdd = name.split(" "); + removeEmpties(namesToAdd); + for (var i = 0; i < l; i++) { + var found = namesToAdd.indexOf(names[i]); + if (found >= 0) { + namesToAdd.splice(found, 1); + } + } + if (namesToAdd.length > 0) { + toAdd = namesToAdd.join(" "); + } + } else { + var saw = false; + for (var i = 0; i < l; i++) { + if (names[i] === name) { + saw = true; + break; + } + } + if (!saw) { toAdd = name; } + + } + if (toAdd) { + if (l > 0 && names[0].length > 0) { + setClassName(e, className + " " + toAdd); + } else { + setClassName(e, toAdd); + } + } + return e; + } + } + function removeClass(e, name) { + /// + /// + /// Removes the specified class from the specified element. + /// + /// + /// The element from which to remove the class. + /// + /// + /// The name of the class to remove. + /// + /// + /// The element. + /// + /// + if (e.classList) { + + // Fastpath: Nothing to remove + if (e.classList.length === 0) { + return e; + } + var namesToRemove = name.split(" "); + removeEmpties(namesToRemove); + + for (var i = 0, len = namesToRemove.length; i < len; i++) { + e.classList.remove(namesToRemove[i]); + } + return e; + } else { + var original = getClassName(e); + var namesToRemove; + var namesToRemoveLen; + + if (name.indexOf(" ") >= 0) { + namesToRemove = name.split(" "); + namesToRemoveLen = removeEmpties(namesToRemove); + } else { + // early out for the case where you ask to remove a single + // name and that name isn't found. + // + if (original.indexOf(name) < 0) { + return e; + } + namesToRemove = [name]; + namesToRemoveLen = 1; + } + var removed; + var names = original.split(" "); + var namesLen = removeEmpties(names); + + for (var i = namesLen - 1; i >= 0; i--) { + if (namesToRemove.indexOf(names[i]) >= 0) { + names.splice(i, 1); + removed = true; + } + } + + if (removed) { + setClassName(e, names.join(" ")); + } + return e; + } + } + function toggleClass(e, name) { + /// + /// + /// Toggles (adds or removes) the specified class on the specified element. + /// If the class is present, it is removed; if it is absent, it is added. + /// + /// + /// The element on which to toggle the class. + /// + /// + /// The name of the class to toggle. + /// + /// + /// The element. + /// + /// + if (e.classList) { + e.classList.toggle(name); + return e; + } else { + var className = getClassName(e); + var names = className.trim().split(" "); + var l = names.length; + var found = false; + for (var i = 0; i < l; i++) { + if (names[i] === name) { + found = true; + } + } + if (!found) { + if (l > 0 && names[0].length > 0) { + setClassName(e, className + " " + name); + } else { + setClassName(e, className + name); + } + } else { + setClassName(e, names.reduce(function (r, e) { + if (e === name) { + return r; + } else if (r && r.length > 0) { + return r + " " + e; + } else { + return e; + } + }, "")); + } + return e; + } + } + + // Only set the attribute if its value has changed + function setAttribute(element, attribute, value) { + if (element.getAttribute(attribute) !== "" + value) { + element.setAttribute(attribute, value); + } + } + + function _clamp(value, lowerBound, upperBound, defaultValue) { + var n = Math.max(lowerBound, Math.min(upperBound, +value)); + return n === 0 ? 0 : n || Math.max(lowerBound, Math.min(upperBound, defaultValue)); + } + var _pixelsRE = /^-?\d+\.?\d*(px)?$/i; + var _numberRE = /^-?\d+/i; + function convertToPixels(element, value) { + /// + /// + /// Converts a CSS positioning string for the specified element to pixels. + /// + /// + /// The element. + /// + /// + /// The CSS positioning string. + /// + /// + /// The number of pixels. + /// + /// + if (!_pixelsRE.test(value) && _numberRE.test(value)) { + var previousValue = element.style.left; + + element.style.left = value; + value = element.style.pixelLeft; + + element.style.left = previousValue; + + return value; + } else { + return Math.round(parseFloat(value)) || 0; + } + } + + function getDimension(element, property) { + return convertToPixels(element, _getComputedStyle(element, null)[property]); + } + + function _convertToPrecisePixels(value) { + return parseFloat(value) || 0; + } + function _getPreciseDimension(element, property) { + return _convertToPrecisePixels(_getComputedStyle(element, null)[property]); + } + function _getPreciseMargins(element) { + var style = _getComputedStyle(element); + return { + top: _convertToPrecisePixels(style.marginTop), + right: _convertToPrecisePixels(style.marginRight), + bottom: _convertToPrecisePixels(style.marginBottom), + left: _convertToPrecisePixels(style.marginLeft), + }; + } + + var _MSGestureEvent = _Global.MSGestureEvent || { + MSGESTURE_FLAG_BEGIN: 1, + MSGESTURE_FLAG_CANCEL: 4, + MSGESTURE_FLAG_END: 2, + MSGESTURE_FLAG_INERTIA: 8, + MSGESTURE_FLAG_NONE: 0 + }; + + var _MSManipulationEvent = _Global.MSManipulationEvent || { + MS_MANIPULATION_STATE_ACTIVE: 1, + MS_MANIPULATION_STATE_CANCELLED: 6, + MS_MANIPULATION_STATE_COMMITTED: 7, + MS_MANIPULATION_STATE_DRAGGING: 5, + MS_MANIPULATION_STATE_INERTIA: 2, + MS_MANIPULATION_STATE_PRESELECT: 3, + MS_MANIPULATION_STATE_SELECTING: 4, + MS_MANIPULATION_STATE_STOPPED: 0 + }; + + var _MSPointerEvent = _Global.MSPointerEvent || { + MSPOINTER_TYPE_TOUCH: "touch", + MSPOINTER_TYPE_PEN: "pen", + MSPOINTER_TYPE_MOUSE: "mouse", + }; + + // Helpers for managing element._eventsMap for custom events + // + + function addListenerToEventMap(element, type, listener, useCapture, data) { + var eventNameLowercase = type.toLowerCase(); + if (!element._eventsMap) { + element._eventsMap = {}; + } + if (!element._eventsMap[eventNameLowercase]) { + element._eventsMap[eventNameLowercase] = []; + } + element._eventsMap[eventNameLowercase].push({ + listener: listener, + useCapture: useCapture, + data: data + }); + } + + function removeListenerFromEventMap(element, type, listener, useCapture) { + var eventNameLowercase = type.toLowerCase(); + var mappedEvents = element._eventsMap && element._eventsMap[eventNameLowercase]; + if (mappedEvents) { + for (var i = mappedEvents.length - 1; i >= 0; i--) { + var mapping = mappedEvents[i]; + if (mapping.listener === listener && (!!useCapture === !!mapping.useCapture)) { + mappedEvents.splice(i, 1); + return mapping; + } + } + } + return null; + } + + function lookupListeners(element, type) { + var eventNameLowercase = type.toLowerCase(); + return element._eventsMap && element._eventsMap[eventNameLowercase] && element._eventsMap[eventNameLowercase].slice(0) || []; + } + + // Custom focusin/focusout events + // Generally, use these instead of using the browser's blur/focus/focusout/focusin events directly. + // However, this doesn't support the window object. If you need to listen to focus events on the window, + // use the browser's events directly. + // + // In order to send our custom focusin/focusout events synchronously on every browser, we feature detect + // for native "focusin" and "focusout" since every browser that supports them will fire them synchronously. + // Every browser in our support matrix, except for IE, also fires focus/blur synchronously, we fall back to + // those events in browsers such as Firefox that do not have native support for focusin/focusout. + + function bubbleEvent(element, type, eventObject) { + while (element) { + var handlers = lookupListeners(element, type); + for (var i = 0, len = handlers.length; i < len; i++) { + handlers[i].listener.call(element, eventObject); + } + + element = element.parentNode; + } + } + + function prepareFocusEvent(eventObject) { + // If an iframe is involved, then relatedTarget should be null. + if (eventObject.relatedTarget && eventObject.relatedTarget.tagName === "IFRAME" || + eventObject.target && eventObject.target.tagName === "IFRAME") { + eventObject.relatedTarget = null; + } + + return eventObject; + } + + var nativeSupportForFocusIn = "onfocusin" in _Global.document.documentElement; + var activeElement = null; + _Global.addEventListener(nativeSupportForFocusIn ? "focusout" : "blur", function (eventObject) { + // Fires focusout when focus move to another window or into an iframe. + if (eventObject.target === _Global) { + var previousActiveElement = activeElement; + if (previousActiveElement) { + bubbleEvent(previousActiveElement, "focusout", prepareFocusEvent({ + type: "focusout", + target: previousActiveElement, + relatedTarget: null + })); + } + activeElement = null; + } + }); + + _Global.document.documentElement.addEventListener(nativeSupportForFocusIn ? "focusin" : "focus", function (eventObject) { + var previousActiveElement = activeElement; + activeElement = eventObject.target; + if (previousActiveElement) { + bubbleEvent(previousActiveElement, "focusout", prepareFocusEvent({ + type: "focusout", + target: previousActiveElement, + relatedTarget: activeElement + })); + } + if (activeElement) { + bubbleEvent(activeElement, "focusin", prepareFocusEvent({ + type: "focusin", + target: activeElement, + relatedTarget: previousActiveElement + })); + } + }, true); + + function registerBubbleListener(element, type, listener, useCapture) { + if (useCapture) { + throw "This custom WinJS event only supports bubbling"; + } + addListenerToEventMap(element, type, listener, useCapture); + } + + // Custom pointer events + // + + // Sets the properties in *overrideProperties* on the object. Delegates all other + // property accesses to *eventObject*. + // + // The purpose of PointerEventProxy is that it allows us to customize properties on + // an eventObject despite those properties being unwritable and unconfigurable. + var PointerEventProxy = function (eventObject, overrideProperties) { + overrideProperties = overrideProperties || {}; + this.__eventObject = eventObject; + var that = this; + Object.keys(overrideProperties).forEach(function (propertyName) { + Object.defineProperty(that, propertyName, { + value: overrideProperties[propertyName] + }); + }); + }; + + // Define PointerEventProxy properties which should be delegated to the original eventObject. + [ + "altKey", "AT_TARGET", "bubbles", "BUBBLING_PHASE", "button", "buttons", + "cancelable", "cancelBubble", "CAPTURING_PHASE", "clientX", "clientY", + "ctrlKey", "currentTarget", "defaultPrevented", "detail", "eventPhase", + "fromElement", "getModifierState", "height", "hwTimestamp", "initEvent", + "initMouseEvent", "initPointerEvent", "initUIEvent", "isPrimary", "isTrusted", + "layerX", "layerY", "metaKey", "offsetX", "offsetY", "pageX", "pageY", + "pointerId", "pointerType", "pressure", "preventDefault", "relatedTarget", + "rotation", "screenX", "screenY", "shiftKey", "srcElement", "stopImmediatePropagation", + "stopPropagation", "target", "tiltX", "tiltY", "timeStamp", "toElement", "type", + "view", "which", "width", "x", "y", "_normalizedType", "_fakedBySemanticZoom" + ].forEach(function (propertyName) { + Object.defineProperty(PointerEventProxy.prototype, propertyName, { + get: function () { + var value = this.__eventObject[propertyName]; + return typeof value === "function" ? value.bind(this.__eventObject) : value; + }, + configurable: true + }); + }); + + function touchEventTranslator(callback, eventObject) { + var changedTouches = eventObject.changedTouches, + retVal = null; + + if (!changedTouches) { + return retVal; + } + + for (var i = 0, len = changedTouches.length; i < len; i++) { + var touchObject = changedTouches[i]; + var pointerEventObject = new PointerEventProxy(eventObject, { + pointerType: _MSPointerEvent.MSPOINTER_TYPE_TOUCH, + pointerId: touchObject.identifier, + isPrimary: i === 0, + screenX: touchObject.screenX, + screenY: touchObject.screenY, + clientX: touchObject.clientX, + clientY: touchObject.clientY, + pageX: touchObject.pageX, + pageY: touchObject.pageY, + radiusX: touchObject.radiusX, + radiusY: touchObject.radiusY, + rotationAngle: touchObject.rotationAngle, + force: touchObject.force, + _currentTouch: touchObject + }); + var newRetVal = callback(pointerEventObject); + retVal = retVal || newRetVal; + } + return retVal; + } + + function mouseEventTranslator(callback, eventObject) { + eventObject.pointerType = _MSPointerEvent.MSPOINTER_TYPE_MOUSE; + eventObject.pointerId = -1; + eventObject.isPrimary = true; + return callback(eventObject); + } + + function mspointerEventTranslator(callback, eventObject) { + return callback(eventObject); + } + + var eventTranslations = { + pointerdown: { + touch: "touchstart", + mspointer: "MSPointerDown", + mouse: "mousedown" + }, + pointerup: { + touch: "touchend", + mspointer: "MSPointerUp", + mouse: "mouseup" + }, + pointermove: { + touch: "touchmove", + mspointer: "MSPointerMove", + mouse: "mousemove" + }, + pointerenter: { + touch: "touchenter", + mspointer: "MSPointerEnter", + mouse: "mouseenter" + }, + pointerover: { + touch: null, + mspointer: "MSPointerOver", + mouse: "mouseover" + }, + pointerout: { + touch: "touchleave", + mspointer: "MSPointerOut", + mouse: "mouseout" + }, + pointercancel: { + touch: "touchcancel", + mspointer: "MSPointerCancel", + mouse: null + } + }; + + function registerPointerEvent(element, type, callback, capture) { + var eventNameLowercase = type.toLowerCase(); + + var mouseWrapper, + touchWrapper, + mspointerWrapper; + var translations = eventTranslations[eventNameLowercase]; + + // Browsers fire a touch event and then a mouse event when the input is touch. touchHandled is used to prevent invoking the pointer callback twice. + var touchHandled; + + // If we are in IE10, we should use MSPointer as it provides a better interface than touch events + if (_Global.MSPointerEvent) { + mspointerWrapper = function (eventObject) { + eventObject._normalizedType = eventNameLowercase; + touchHandled = true; + return mspointerEventTranslator(callback, eventObject); + }; + element.addEventListener(translations.mspointer, mspointerWrapper, capture); + } else { + // Otherwise, use a mouse and touch event + if (translations.mouse) { + mouseWrapper = function (eventObject) { + eventObject._normalizedType = eventNameLowercase; + if (!touchHandled) { + return mouseEventTranslator(callback, eventObject); + } + touchHandled = false; + }; + element.addEventListener(translations.mouse, mouseWrapper, capture); + } + if (translations.touch) { + touchWrapper = function (eventObject) { + eventObject._normalizedType = eventNameLowercase; + touchHandled = true; + return touchEventTranslator(callback, eventObject); + }; + element.addEventListener(translations.touch, touchWrapper, capture); + } + } + + addListenerToEventMap(element, type, callback, capture, { + mouseWrapper: mouseWrapper, + touchWrapper: touchWrapper, + mspointerWrapper: mspointerWrapper + }); + } + + function unregisterPointerEvent(element, type, callback, capture) { + var eventNameLowercase = type.toLowerCase(); + + var mapping = removeListenerFromEventMap(element, type, callback, capture); + if (mapping) { + var translations = eventTranslations[eventNameLowercase]; + if (mapping.data.mouseWrapper) { + element.removeEventListener(translations.mouse, mapping.data.mouseWrapper, capture); + } + if (mapping.data.touchWrapper) { + element.removeEventListener(translations.touch, mapping.data.touchWrapper, capture); + } + if (mapping.data.mspointerWrapper) { + element.removeEventListener(translations.mspointer, mapping.data.mspointerWrapper, capture); + } + } + } + + // Custom events dispatch table. Event names should be lowercased. + // + + var customEvents = { + focusout: { + register: registerBubbleListener, + unregister: removeListenerFromEventMap + }, + focusin: { + register: registerBubbleListener, + unregister: removeListenerFromEventMap + }, + }; + if (!_Global.PointerEvent) { + var pointerEventEntry = { + register: registerPointerEvent, + unregister: unregisterPointerEvent + }; + + customEvents.pointerdown = pointerEventEntry; + customEvents.pointerup = pointerEventEntry; + customEvents.pointermove = pointerEventEntry; + customEvents.pointerenter = pointerEventEntry; + customEvents.pointerover = pointerEventEntry; + customEvents.pointerout = pointerEventEntry; + customEvents.pointercancel = pointerEventEntry; + } + + // The MutationObserverShim only supports the following configuration: + // attributes + // attributeFilter + var MutationObserverShim = _Base.Class.define( + function MutationObserverShim_ctor(callback) { + this._callback = callback; + this._toDispose = []; + this._attributeFilter = []; + this._scheduled = false; + this._pendingChanges = []; + this._observerCount = 0; + this._handleCallback = this._handleCallback.bind(this); + this._targetElements = []; + }, + { + observe: function MutationObserverShim_observe(element, configuration) { + if (this._targetElements.indexOf(element) === -1) { + this._targetElements.push(element); + } + this._observerCount++; + if (configuration.attributes) { + this._addRemovableListener(element, "DOMAttrModified", this._handleCallback); + } + if (configuration.attributeFilter) { + this._attributeFilter = configuration.attributeFilter; + } + }, + disconnect: function MutationObserverShim_disconnect() { + this._observerCount = 0; + this._targetElements = []; + this._toDispose.forEach(function (disposeFunc) { + disposeFunc(); + }); + }, + _addRemovableListener: function MutationObserverShim_addRemovableListener(target, event, listener) { + target.addEventListener(event, listener); + this._toDispose.push(function () { + target.removeEventListener(event, listener); + }); + }, + _handleCallback: function MutationObserverShim_handleCallback(evt) { + + // prevent multiple events from firing when nesting observers + evt.stopPropagation(); + + var attrName = evt.attrName; + if (this._attributeFilter.length && this._attributeFilter.indexOf(attrName) === -1) { + return; + } + + // subtree:true is not currently supported + if (this._targetElements.indexOf(evt.target) === -1) { + return; + } + + var isAriaMutation = attrName.indexOf("aria") >= 0; + + // DOM mutation events use different naming for this attribute + if (attrName === 'tabindex') { + attrName = 'tabIndex'; + } + + this._pendingChanges.push({ + type: 'attributes', + target: evt.target, + attributeName: attrName + }); + + if (this._observerCount === 1 && !isAriaMutation) { + this._dispatchEvent(); + } else if (this._scheduled === false) { + this._scheduled = true; + _BaseUtils._setImmediate(this._dispatchEvent.bind(this)); + } + + }, + _dispatchEvent: function MutationObserverShim_dispatchEvent() { + try { + this._callback(this._pendingChanges); + } + finally { + this._pendingChanges = []; + this._scheduled = false; + } + } + }, + { + _isShim: true + } + ); + + var _MutationObserver = _Global.MutationObserver || MutationObserverShim; + + // Lazily init singleton on first access. + var _resizeNotifier = null; + + // Class to provide a global listener for window.onresize events. + // This keeps individual elements from having to listen to window.onresize + // and having to dispose themselves to avoid leaks. + var ResizeNotifier = _Base.Class.define( + function ElementResizer_ctor() { + _Global.addEventListener("resize", this._handleResize.bind(this)); + }, + { + subscribe: function ElementResizer_subscribe(element, handler) { + element.addEventListener(this._resizeEvent, handler); + addClass(element, this._resizeClass); + }, + unsubscribe: function ElementResizer_unsubscribe(element, handler) { + removeClass(element, this._resizeClass); + element.removeEventListener(this._resizeEvent, handler); + }, + _handleResize: function ElementResizer_handleResize() { + var resizables = _Global.document.querySelectorAll('.' + this._resizeClass); + var length = resizables.length; + for (var i = 0; i < length; i++) { + var event = _Global.document.createEvent("Event"); + event.initEvent(this._resizeEvent, false, true); + resizables[i].dispatchEvent(event); + } + }, + _resizeClass: { get: function () { return 'win-element-resize'; } }, + _resizeEvent: { get: function () { return 'WinJSElementResize'; } } + } + ); + + // - object: The object on which GenericListener will listen for events. + // - objectName: A string representing the name of *object*. This will be + // incorporated into the names of the events and classNames created by + // GenericListener. + // - options + // - registerThruWinJSCustomEvents: If true, will register for events using + // _exports._addEventListener so that you can take advantage of WinJS's custom + // events (e.g. focusin, pointer*). Otherwise, registers directly on *object* + // using its add/removeEventListener methods. + var GenericListener = _Base.Class.define( + function GenericListener_ctor(objectName, object, options) { + options = options || {}; + this.registerThruWinJSCustomEvents = !!options.registerThruWinJSCustomEvents; + + this.objectName = objectName; + this.object = object; + this.capture = {}; + this.bubble = {}; + }, + { + addEventListener: function GenericListener_addEventListener(element, name, listener, capture) { + name = name.toLowerCase(); + var handlers = this._getHandlers(capture); + var handler = handlers[name]; + + if (!handler) { + handler = this._getListener(name, capture); + handler.refCount = 0; + handlers[name] = handler; + + if (this.registerThruWinJSCustomEvents) { + exports._addEventListener(this.object, name, handler, capture); + } else { + this.object.addEventListener(name, handler, capture); + } + } + + handler.refCount++; + element.addEventListener(this._getEventName(name, capture), listener); + addClass(element, this._getClassName(name, capture)); + }, + removeEventListener: function GenericListener_removeEventListener(element, name, listener, capture) { + name = name.toLowerCase(); + var handlers = this._getHandlers(capture); + var handler = handlers[name]; + + if (handler) { + handler.refCount--; + if (handler.refCount === 0) { + if (this.registerThruWinJSCustomEvents) { + exports._removeEventListener(this.object, name, handler, capture); + } else { + this.object.removeEventListener(name, handler, capture); + } + delete handlers[name]; + } + } + + removeClass(element, this._getClassName(name, capture)); + element.removeEventListener(this._getEventName(name, capture), listener); + }, + + _getHandlers: function GenericListener_getHandlers(capture) { + if (capture) { + return this.capture; + } else { + return this.bubble; + } + }, + + _getClassName: function GenericListener_getClassName(name, capture) { + var captureSuffix = capture ? 'capture' : 'bubble'; + return 'win-' + this.objectName.toLowerCase() + '-event-' + name + captureSuffix; + }, + + _getEventName: function GenericListener_getEventName(name, capture) { + var captureSuffix = capture ? 'capture' : 'bubble'; + return 'WinJS' + this.objectName + 'Event-' + name + captureSuffix; + }, + + _getListener: function GenericListener_getListener(name, capture) { + var listener = function GenericListener_generatedListener(ev) { + + var targets = _Global.document.querySelectorAll('.' + this._getClassName(name, capture)); + var length = targets.length; + var handled = false; + for (var i = 0; i < length; i++) { + var event = _Global.document.createEvent("Event"); + event.initEvent(this._getEventName(name, capture), false, true); + event.detail = { originalEvent: ev }; + var doDefault = targets[i].dispatchEvent(event); + handled = handled || !doDefault; + } + return handled; + }; + + return listener.bind(this); + } + } + ); + + var determinedRTLEnvironment = false, + usingWebkitScrollCoordinates = false, + usingFirefoxScrollCoordinates = false; + function determineRTLEnvironment() { + var element = _Global.document.createElement("div"); + element.style.direction = "rtl"; + element.innerHTML = "" + + "
" + + "
" + + "
"; + _Global.document.body.appendChild(element); + var elementScroller = element.firstChild; + if (elementScroller.scrollLeft > 0) { + usingWebkitScrollCoordinates = true; + } + elementScroller.scrollLeft += 100; + if (elementScroller.scrollLeft === 0) { + usingFirefoxScrollCoordinates = true; + } + _Global.document.body.removeChild(element); + determinedRTLEnvironment = true; + } + + function getAdjustedScrollPosition(element) { + var computedStyle = _getComputedStyle(element), + scrollLeft = element.scrollLeft; + if (computedStyle.direction === "rtl") { + if (!determinedRTLEnvironment) { + determineRTLEnvironment(); + } + if (usingWebkitScrollCoordinates) { + scrollLeft = element.scrollWidth - element.clientWidth - scrollLeft; + } + scrollLeft = Math.abs(scrollLeft); + } + + return { + scrollLeft: scrollLeft, + scrollTop: element.scrollTop + }; + } + + function setAdjustedScrollPosition(element, scrollLeft, scrollTop) { + if (scrollLeft !== undefined) { + var computedStyle = _getComputedStyle(element); + if (computedStyle.direction === "rtl") { + if (!determinedRTLEnvironment) { + determineRTLEnvironment(); + } + if (usingFirefoxScrollCoordinates) { + scrollLeft = -scrollLeft; + } else if (usingWebkitScrollCoordinates) { + scrollLeft = element.scrollWidth - element.clientWidth - scrollLeft; + } + } + element.scrollLeft = scrollLeft; + } + + if (scrollTop !== undefined) { + element.scrollTop = scrollTop; + } + } + + function getScrollPosition(element) { + /// + /// + /// Gets the scrollLeft and scrollTop of the specified element, adjusting the scrollLeft to change from browser specific coordinates to logical coordinates when in RTL. + /// + /// + /// The element. + /// + /// + /// An object with two properties: scrollLeft and scrollTop + /// + /// + return getAdjustedScrollPosition(element); + } + + function setScrollPosition(element, position) { + /// + /// + /// Sets the scrollLeft and scrollTop of the specified element, changing the scrollLeft from logical coordinates to browser-specific coordinates when in RTL. + /// + /// + /// The element. + /// + /// + /// The element. + /// + /// + position = position || {}; + setAdjustedScrollPosition(element, position.scrollLeft, position.scrollTop); + } + + // navigator.msManipulationViewsEnabled tells us whether snap points work or not regardless of whether the style properties exist, however, + // on Phone WWAs, this check returns false even though snap points are supported. To work around this bug, we check for the presence of + // 'MSAppHost' in the user agent string which indicates that we are in a WWA environment; all WWA environments support snap points. + var supportsSnapPoints = _Global.navigator.msManipulationViewsEnabled || _Global.navigator.userAgent.indexOf("MSAppHost") >= 0; + var supportsTouchDetection = !!(_Global.MSPointerEvent || _Global.TouchEvent); + + var uniqueElementIDCounter = 0; + + function uniqueID(e) { + if (!(e.uniqueID || e._uniqueID)) { + e._uniqueID = "element__" + (++uniqueElementIDCounter); + } + + return e.uniqueID || e._uniqueID; + } + + function ensureId(element) { + if (!element.id) { + element.id = uniqueID(element); + } + } + + function _getCursorPos(eventObject) { + var docElement = _Global.document.documentElement; + var docScrollPos = getScrollPosition(docElement); + + return { + left: eventObject.clientX + (_Global.document.body.dir === "rtl" ? -docScrollPos.scrollLeft : docScrollPos.scrollLeft), + top: eventObject.clientY + docElement.scrollTop + }; + } + + function _getElementsByClasses(parent, classes) { + var retVal = []; + + for (var i = 0, len = classes.length; i < len; i++) { + var element = parent.querySelector("." + classes[i]); + if (element) { + retVal.push(element); + } + } + return retVal; + } + + var _selectionPartsSelector = ".win-selectionborder, .win-selectionbackground, .win-selectioncheckmark, .win-selectioncheckmarkbackground"; + var _dataKey = "_msDataKey"; + _Base.Namespace._moduleDefine(exports, "WinJS.Utilities", { + _dataKey: _dataKey, + + _supportsSnapPoints: { + get: function () { + return supportsSnapPoints; + } + }, + + _supportsTouchDetection: { + get: function () { + return supportsTouchDetection; + } + }, + + _uniqueID: uniqueID, + + _ensureId: ensureId, + + _clamp: _clamp, + + _getCursorPos: _getCursorPos, + + _getElementsByClasses: _getElementsByClasses, + + _createGestureRecognizer: function () { + if (_Global.MSGesture) { + return new _Global.MSGesture(); + } + + var doNothing = function () { + }; + return { + addEventListener: doNothing, + removeEventListener: doNothing, + addPointer: doNothing, + stop: doNothing + }; + }, + + _MSGestureEvent: _MSGestureEvent, + _MSManipulationEvent: _MSManipulationEvent, + + _elementsFromPoint: function (x, y) { + if (_Global.document.msElementsFromPoint) { + return _Global.document.msElementsFromPoint(x, y); + } else { + var element = _Global.document.elementFromPoint(x, y); + return element ? [element] : null; + } + }, + + _matchesSelector: function _matchesSelector(element, selectorString) { + var matchesSelector = element.matches + || element.msMatchesSelector + || element.mozMatchesSelector + || element.webkitMatchesSelector; + return matchesSelector.call(element, selectorString); + }, + + _selectionPartsSelector: _selectionPartsSelector, + + _isSelectionRendered: function _isSelectionRendered(itemBox) { + // The tree is changed at pointerDown but _selectedClass is added only when the user drags an item below the selection threshold so checking for _selectedClass is not reliable. + return itemBox.querySelectorAll(_selectionPartsSelector).length > 0; + }, + + _addEventListener: function _addEventListener(element, type, listener, useCapture) { + var eventNameLower = type && type.toLowerCase(); + var entry = customEvents[eventNameLower]; + var equivalentEvent = _BaseUtils._browserEventEquivalents[type]; + if (entry) { + entry.register(element, type, listener, useCapture); + } else if (equivalentEvent) { + element.addEventListener(equivalentEvent, listener, useCapture); + } else { + element.addEventListener(type, listener, useCapture); + } + }, + + _removeEventListener: function _removeEventListener(element, type, listener, useCapture) { + var eventNameLower = type && type.toLowerCase(); + var entry = customEvents[eventNameLower]; + var equivalentEvent = _BaseUtils._browserEventEquivalents[type]; + if (entry) { + entry.unregister(element, type, listener, useCapture); + } else if (equivalentEvent) { + element.removeEventListener(equivalentEvent, listener, useCapture); + } else { + element.removeEventListener(type, listener, useCapture); + } + }, + + _initEventImpl: function (initType, event, eventType) { + eventType = eventType.toLowerCase(); + var mapping = eventTranslations[eventType]; + if (mapping) { + switch (initType.toLowerCase()) { + case "pointer": + if (!_Global.PointerEvent) { + arguments[2] = mapping.mspointer; + } + break; + + default: + arguments[2] = mapping[initType.toLowerCase()]; + break; + } + } + event["init" + initType + "Event"].apply(event, Array.prototype.slice.call(arguments, 2)); + }, + + _initMouseEvent: function (event) { + this._initEventImpl.apply(this, ["Mouse", event].concat(Array.prototype.slice.call(arguments, 1))); + }, + + _initPointerEvent: function (event) { + this._initEventImpl.apply(this, ["Pointer", event].concat(Array.prototype.slice.call(arguments, 1))); + }, + + _PointerEventProxy: PointerEventProxy, + + _bubbleEvent: bubbleEvent, + + _setPointerCapture: function (element, pointerId) { + if (element.setPointerCapture) { + element.setPointerCapture(pointerId); + } + }, + + _releasePointerCapture: function (element, pointerId) { + if (element.releasePointerCapture) { + element.releasePointerCapture(pointerId); + } + }, + + _MSPointerEvent: _MSPointerEvent, + + _getComputedStyle: _getComputedStyle, + + _zoomToDuration: _zoomToDuration, + + _zoomTo: function _zoomTo(element, args) { + if (this._supportsSnapPoints && element.msZoomTo) { + element.msZoomTo(args); + } else { + // Schedule to ensure that we're not running from within an event handler. For example, if running + // within a focus handler triggered by WinJS.Utilities._setActive, scroll position will not yet be + // restored. + Scheduler.schedule(function () { + var initialPos = getAdjustedScrollPosition(element); + var effectiveScrollLeft = (typeof element._zoomToDestX === "number" ? element._zoomToDestX : initialPos.scrollLeft); + var effectiveScrollTop = (typeof element._zoomToDestY === "number" ? element._zoomToDestY : initialPos.scrollTop); + var cs = _getComputedStyle(element); + var scrollLimitX = element.scrollWidth - parseInt(cs.width, 10) - parseInt(cs.paddingLeft, 10) - parseInt(cs.paddingRight, 10); + var scrollLimitY = element.scrollHeight - parseInt(cs.height, 10) - parseInt(cs.paddingTop, 10) - parseInt(cs.paddingBottom, 10); + + if (typeof args.contentX !== "number") { + args.contentX = effectiveScrollLeft; + } + if (typeof args.contentY !== "number") { + args.contentY = effectiveScrollTop; + } + + var zoomToDestX = _clamp(args.contentX, 0, scrollLimitX); + var zoomToDestY = _clamp(args.contentY, 0, scrollLimitY); + if (zoomToDestX === effectiveScrollLeft && zoomToDestY === effectiveScrollTop) { + // Scroll position is already in the proper state. This zoomTo is a no-op. + return; + } + + element._zoomToId = element._zoomToId || 0; + element._zoomToId++; + element._zoomToDestX = zoomToDestX; + element._zoomToDestY = zoomToDestY; + + var thisZoomToId = element._zoomToId; + var start = _BaseUtils._now(); + var xFactor = (element._zoomToDestX - initialPos.scrollLeft) / _zoomToDuration; + var yFactor = (element._zoomToDestY - initialPos.scrollTop) / _zoomToDuration; + + var update = function () { + var t = _BaseUtils._now() - start; + if (element._zoomToId !== thisZoomToId) { + return; + } else if (t > _zoomToDuration) { + setAdjustedScrollPosition(element, element._zoomToDestX, element._zoomToDestY); + element._zoomToDestX = null; + element._zoomToDestY = null; + } else { + setAdjustedScrollPosition(element, initialPos.scrollLeft + t * xFactor, initialPos.scrollTop + t * yFactor); + _BaseUtils._requestAnimationFrame(update); + } + }; + + _BaseUtils._requestAnimationFrame(update); + }, Scheduler.Priority.high, null, "WinJS.Utilities._zoomTo"); + } + }, + + _setActive: function _setActive(element, scroller) { + var success = true; + try { + if (_Global.HTMLElement && _Global.HTMLElement.prototype.setActive) { + element.setActive(); + } else { + // We are aware that, unlike setActive(), focus() will scroll to the element that gets focus. However, this is + // our current cross-browser solution until there is an equivalent for setActive() in other browsers. + // + // This _setActive polyfill does have limited support for preventing scrolling: via the scroller parameter, it + // can prevent one scroller from scrolling. This functionality is necessary in some scenarios. For example, when using + // _zoomTo and _setActive together. + + var scrollLeft, + scrollTop; + + if (scroller) { + scrollLeft = scroller.scrollLeft; + scrollTop = scroller.scrollTop; + } + element.focus(); + if (scroller) { + scroller.scrollLeft = scrollLeft; + scroller.scrollTop = scrollTop; + } + } + } catch (e) { + // setActive() raises an exception when trying to focus an invisible item. Checking visibility is non-trivial, so it's best + // just to catch the exception and ignore it. focus() on the other hand, does not raise exceptions. + success = false; + } + return success; + }, + + _MutationObserver: _MutationObserver, + + _resizeNotifier: { + get: function () { + if (!_resizeNotifier) { + _resizeNotifier = new ResizeNotifier(); + } + return _resizeNotifier; + } + }, + + _GenericListener: GenericListener, + _globalListener: new GenericListener("Global", _Global, { registerThruWinJSCustomEvents: true }), + _documentElementListener: new GenericListener("DocumentElement", _Global.document.documentElement, { registerThruWinJSCustomEvents: true }), + _inputPaneListener: _WinRT.Windows.UI.ViewManagement.InputPane ? + new GenericListener("InputPane", _WinRT.Windows.UI.ViewManagement.InputPane.getForCurrentView()) : + { addEventListener: function () { }, removeEventListener: function () { } }, + + // Appends a hidden child to the given element that will listen for being added + // to the DOM. When the hidden element is added to the DOM, it will dispatch a + // "WinJSNodeInserted" event on the provided element. + _addInsertedNotifier: function (element) { + var hiddenElement = _Global.document.createElement("div"); + hiddenElement.style[_BaseUtils._browserStyleEquivalents["animation-name"].scriptName] = "WinJS-node-inserted"; + hiddenElement.style[_BaseUtils._browserStyleEquivalents["animation-duration"].scriptName] = "0.01s"; + hiddenElement.style["position"] = "absolute"; + element.appendChild(hiddenElement); + + exports._addEventListener(hiddenElement, "animationStart", function (e) { + if (e.animationName === "WinJS-node-inserted") { + var e = _Global.document.createEvent("Event"); + e.initEvent("WinJSNodeInserted", false, true); + element.dispatchEvent(e); + } + }, false); + + return hiddenElement; + }, + + // Returns a promise which completes when *element* is in the DOM. + _inDom: function Utilities_inDom(element) { + return new Promise(function (c) { + if (_Global.document.body.contains(element)) { + c(); + } else { + var nodeInsertedHandler = function () { + element.removeEventListener("WinJSNodeInserted", nodeInsertedHandler, false); + c(); + }; + exports._addInsertedNotifier(element); + element.addEventListener("WinJSNodeInserted", nodeInsertedHandler, false); + } + }); + }, + + // Browser agnostic method to set element flex style + // Param is an object in the form {grow: flex-grow, shrink: flex-shrink, basis: flex-basis} + // All fields optional + _setFlexStyle: function (element, flexParams) { + var styleObject = element.style; + if (typeof flexParams.grow !== "undefined") { + styleObject.msFlexPositive = flexParams.grow; + styleObject.webkitFlexGrow = flexParams.grow; + styleObject.flexGrow = flexParams.grow; + } + if (typeof flexParams.shrink !== "undefined") { + styleObject.msFlexNegative = flexParams.shrink; + styleObject.webkitFlexShrink = flexParams.shrink; + styleObject.flexShrink = flexParams.shrink; + } + if (typeof flexParams.basis !== "undefined") { + styleObject.msFlexPreferredSize = flexParams.basis; + styleObject.webkitFlexBasis = flexParams.basis; + styleObject.flexBasis = flexParams.basis; + } + }, + + /// + /// Defines a set of keyboard values. + /// + Key: { + /// + /// BACKSPACE key. + /// + backspace: 8, + + /// + /// TAB key. + /// + tab: 9, + + /// + /// ENTER key. + /// + enter: 13, + + /// + /// Shift key. + /// + shift: 16, + + /// + /// CTRL key. + /// + ctrl: 17, + + /// + /// ALT key + /// + alt: 18, + + /// + /// Pause key. + /// + pause: 19, + + /// + /// CAPS LOCK key. + /// + capsLock: 20, + + /// + /// ESCAPE key. + /// + escape: 27, + + /// + /// SPACE key. + /// + space: 32, + + /// + /// PAGE UP key. + /// + pageUp: 33, + + /// + /// PAGE DOWN key. + /// + pageDown: 34, + + /// + /// END key. + /// + end: 35, + + /// + /// HOME key. + /// + home: 36, + + /// + /// Left arrow key. + /// + leftArrow: 37, + + /// + /// Up arrow key. + /// + upArrow: 38, + + /// + /// Right arrow key. + /// + rightArrow: 39, + + /// + /// Down arrow key. + /// + downArrow: 40, + + /// + /// INSERT key. + /// + insert: 45, + + /// + /// DELETE key. + /// + deleteKey: 46, + + /// + /// Number 0 key. + /// + num0: 48, + + /// + /// Number 1 key. + /// + num1: 49, + + /// + /// Number 2 key. + /// + num2: 50, + + /// + /// Number 3 key. + /// + num3: 51, + + /// + /// Number 4 key. + /// + num4: 52, + + /// + /// Number 5 key. + /// + num5: 53, + + /// + /// Number 6 key. + /// + num6: 54, + + /// + /// Number 7 key. + /// + num7: 55, + + /// + /// Number 8 key. + /// + num8: 56, + + /// + /// Number 9 key. + /// + num9: 57, + + /// + /// A key. + /// + a: 65, + + /// + /// B key. + /// + b: 66, + + /// + /// C key. + /// + c: 67, + + /// + /// D key. + /// + d: 68, + + /// + /// E key. + /// + e: 69, + + /// + /// F key. + /// + f: 70, + + /// + /// G key. + /// + g: 71, + + /// + /// H key. + /// + h: 72, + + /// + /// I key. + /// + i: 73, + + /// + /// J key. + /// + j: 74, + + /// + /// K key. + /// + k: 75, + + /// + /// L key. + /// + l: 76, + + /// + /// M key. + /// + m: 77, + + /// + /// N key. + /// + n: 78, + + /// + /// O key. + /// + o: 79, + + /// + /// P key. + /// + p: 80, + + /// + /// Q key. + /// + q: 81, + + /// + /// R key. + /// + r: 82, + + /// + /// S key. + /// + s: 83, + + /// + /// T key. + /// + t: 84, + + /// + /// U key. + /// + u: 85, + + /// + /// V key. + /// + v: 86, + + /// + /// W key. + /// + w: 87, + + /// + /// X key. + /// + x: 88, + + /// + /// Y key. + /// + y: 89, + + /// + /// Z key. + /// + z: 90, + + /// + /// Left Windows key. + /// + leftWindows: 91, + + /// + /// Right Windows key. + /// + rightWindows: 92, + + /// + /// Menu key. + /// + menu: 93, + + /// + /// Number pad 0 key. + /// + numPad0: 96, + + /// + /// Number pad 1 key. + /// + numPad1: 97, + + /// + /// Number pad 2 key. + /// + numPad2: 98, + + /// + /// Number pad 3 key. + /// + numPad3: 99, + + /// + /// Number pad 4 key. + /// + numPad4: 100, + + /// + /// Number pad 5 key. + /// + numPad5: 101, + + /// + /// Number pad 6 key. + /// + numPad6: 102, + + /// + /// Number pad 7 key. + /// + numPad7: 103, + + /// + /// Number pad 8 key. + /// + numPad8: 104, + + /// + /// Number pad 9 key. + /// + numPad9: 105, + + /// + /// Multiplication key. + /// + multiply: 106, + + /// + /// Addition key. + /// + add: 107, + + /// + /// Subtraction key. + /// + subtract: 109, + + /// + /// Decimal point key. + /// + decimalPoint: 110, + + /// + /// Division key. + /// + divide: 111, + + /// + /// F1 key. + /// + F1: 112, + + /// + /// F2 key. + /// + F2: 113, + + /// + /// F3 key. + /// + F3: 114, + + /// + /// F4 key. + /// + F4: 115, + + /// + /// F5 key. + /// + F5: 116, + + /// + /// F6 key. + /// + F6: 117, + + /// + /// F7 key. + /// + F7: 118, + + /// + /// F8 key. + /// + F8: 119, + + /// + /// F9 key. + /// + F9: 120, + + /// + /// F10 key. + /// + F10: 121, + + /// + /// F11 key. + /// + F11: 122, + + /// + /// F12 key. + /// + F12: 123, + + /// + /// XBox One Remote NavigationView key. + /// + NavigationView: 136, + + /// + /// XBox One Remote NavigationMenu key. + /// + NavigationMenu: 137, + + /// + /// XBox One Remote NavigationUp key. + /// + NavigationUp: 138, + + /// + /// XBox One Remote NavigationDown key. + /// + NavigationDown: 139, + + /// + /// XBox One Remote NavigationLeft key. + /// + NavigationLeft: 140, + + /// + /// XBox One Remote NavigationRight key. + /// + NavigationRight: 141, + + /// + /// XBox One Remote NavigationAccept key. + /// + NavigationAccept: 142, + + /// + /// XBox One Remote NavigationCancel key. + /// + NavigationCancel: 143, + + /// + /// NUMBER LOCK key. + /// + numLock: 144, + + /// + /// SCROLL LOCK key. + /// + scrollLock: 145, + + /// + /// Browser back key. + /// + browserBack: 166, + + /// + /// Browser forward key. + /// + browserForward: 167, + + /// + /// SEMICOLON key. + /// + semicolon: 186, + + /// + /// EQUAL key. + /// + equal: 187, + + /// + /// COMMA key. + /// + comma: 188, + + /// + /// DASH key. + /// + dash: 189, + + /// + /// PERIOD key. + /// + period: 190, + + /// + /// FORWARD SLASH key. + /// + forwardSlash: 191, + + /// + /// Accent grave key. + /// + graveAccent: 192, + + /// + /// XBox One GamepadA key. + /// + GamepadA: 195, + + /// + /// XBox One GamepadB key. + /// + GamepadB: 196, + + /// + /// XBox One GamepadX key. + /// + GamepadX: 197, + + /// + /// XBox One GamepadY key. + /// + GamepadY: 198, + + /// + /// XBox One GamepadRightShoulder key. + /// + GamepadRightShoulder: 199, + + /// + /// XBox One GamepadLeftShoulder key. + /// + GamepadLeftShoulder: 200, + + /// + /// XBox One GamepadLeftTrigger key. + /// + GamepadLeftTrigger: 201, + + /// + /// XBox One GamepadRightTrigger key. + /// + GamepadRightTrigger: 202, + + /// + /// XBox One GamepadDPadUp key. + /// + GamepadDPadUp: 203, + + /// + /// XBox One GamepadDPadDown key. + /// + GamepadDPadDown: 204, + + /// + /// XBox One GamepadDPadLeft key. + /// + GamepadDPadLeft: 205, + + /// + /// XBox One GamepadDPadRight key. + /// + GamepadDPadRight: 206, + + /// + /// XBox One GamepadMenu key. + /// + GamepadMenu: 207, + + /// + /// XBox One GamepadView key. + /// + GamepadView: 208, + + /// + /// XBox One GamepadLeftThumbstick key. + /// + GamepadLeftThumbstick: 209, + + /// + /// XBox One GamepadRightThumbstick key. + /// + GamepadRightThumbstick: 210, + + /// + /// XBox One GamepadLeftThumbstickUp key. + /// + GamepadLeftThumbstickUp: 211, + + /// + /// XBox One GamepadLeftThumbstickDown key. + /// + GamepadLeftThumbstickDown: 212, + + /// + /// XBox One GamepadLeftThumbstickRight key. + /// + GamepadLeftThumbstickRight: 213, + + /// + /// XBox One GamepadLeftThumbstickLeft key. + /// + GamepadLeftThumbstickLeft: 214, + + /// + /// XBox One GamepadRightThumbstickUp key. + /// + GamepadRightThumbstickUp: 215, + + /// + /// XBox One GamepadRightThumbstickDown key. + /// + GamepadRightThumbstickDown: 216, + + /// + /// XBox One GamepadRightThumbstickRight key. + /// + GamepadRightThumbstickRight: 217, + + /// + /// XBox One GamepadRightThumbstickLeft key. + /// + GamepadRightThumbstickLeft: 218, + + /// + /// OPEN BRACKET key. + /// + openBracket: 219, + + /// + /// BACKSLASH key. + /// + backSlash: 220, + + /// + /// CLOSE BRACKET key. + /// + closeBracket: 221, + + /// + /// SINGLE QUOTE key. + /// + singleQuote: 222, + + /// + /// Any IME input. + /// + IME: 229 + }, + + data: function (element) { + /// + /// + /// Gets the data value associated with the specified element. + /// + /// + /// The element. + /// + /// + /// The value associated with the element. + /// + /// + if (!element[_dataKey]) { + element[_dataKey] = {}; + } + return element[_dataKey]; + }, + + hasClass: function (e, name) { + /// + /// + /// Determines whether the specified element has the specified class. + /// + /// + /// The element. + /// + /// + /// The name of the class. + /// + /// + /// true if the specified element contains the specified class; otherwise, false. + /// + /// + + if (e.classList) { + return e.classList.contains(name); + } else { + var className = getClassName(e); + var names = className.trim().split(" "); + var l = names.length; + for (var i = 0; i < l; i++) { + if (names[i] === name) { + return true; + } + } + return false; + } + }, + + addClass: addClass, + + removeClass: removeClass, + + toggleClass: toggleClass, + + _setAttribute: setAttribute, + + getRelativeLeft: function (element, parent) { + /// + /// + /// Gets the left coordinate of the specified element relative to the specified parent. + /// + /// + /// The element. + /// + /// + /// The parent element. + /// + /// + /// The relative left coordinate. + /// + /// + if (!element) { + return 0; + } + + var elementPosition = exports._getPositionRelativeTo(element, null); + var parentPosition = exports._getPositionRelativeTo(parent, null); + return elementPosition.left - parentPosition.left; + }, + + getRelativeTop: function (element, parent) { + /// + /// + /// Gets the top coordinate of the element relative to the specified parent. + /// + /// + /// The element. + /// + /// + /// The parent element. + /// + /// + /// The relative top coordinate. + /// + /// + if (!element) { + return 0; + } + + var elementPosition = exports._getPositionRelativeTo(element, null); + var parentPosition = exports._getPositionRelativeTo(parent, null); + return elementPosition.top - parentPosition.top; + }, + + getScrollPosition: getScrollPosition, + + setScrollPosition: setScrollPosition, + + empty: function (element) { + /// + /// + /// Removes all the child nodes from the specified element. + /// + /// + /// The element. + /// + /// + /// The element. + /// + /// + if (element.childNodes && element.childNodes.length > 0) { + for (var i = element.childNodes.length - 1; i >= 0; i--) { + element.removeChild(element.childNodes.item(i)); + } + } + return element; + }, + + _isDOMElement: function (element) { + return element && + typeof element === "object" && + typeof element.tagName === "string"; + }, + + getContentWidth: function (element) { + /// + /// + /// Gets the width of the content of the specified element. The content width does not include borders or padding. + /// + /// + /// The element. + /// + /// + /// The content width of the element. + /// + /// + var border = getDimension(element, "borderLeftWidth") + getDimension(element, "borderRightWidth"), + padding = getDimension(element, "paddingLeft") + getDimension(element, "paddingRight"); + return element.offsetWidth - border - padding; + }, + _getPreciseContentWidth: function (element) { + var border = _getPreciseDimension(element, "borderLeftWidth") + _getPreciseDimension(element, "borderRightWidth"), + padding = _getPreciseDimension(element, "paddingLeft") + _getPreciseDimension(element, "paddingRight"); + return element.offsetWidth - border - padding; + }, + + getTotalWidth: function (element) { + /// + /// + /// Gets the width of the element, including margins. + /// + /// + /// The element. + /// + /// + /// The width of the element including margins. + /// + /// + var margin = getDimension(element, "marginLeft") + getDimension(element, "marginRight"); + return element.offsetWidth + margin; + }, + _getPreciseTotalWidth: function (element) { + var margin = _getPreciseDimension(element, "marginLeft") + _getPreciseDimension(element, "marginRight"); + return element.offsetWidth + margin; + }, + + getContentHeight: function (element) { + /// + /// + /// Gets the height of the content of the specified element. The content height does not include borders or padding. + /// + /// + /// The element. + /// + /// + /// The content height of the element. + /// + /// + var border = getDimension(element, "borderTopWidth") + getDimension(element, "borderBottomWidth"), + padding = getDimension(element, "paddingTop") + getDimension(element, "paddingBottom"); + return element.offsetHeight - border - padding; + }, + _getPreciseContentHeight: function (element) { + var border = _getPreciseDimension(element, "borderTopWidth") + _getPreciseDimension(element, "borderBottomWidth"), + padding = _getPreciseDimension(element, "paddingTop") + _getPreciseDimension(element, "paddingBottom"); + return element.offsetHeight - border - padding; + }, + + getTotalHeight: function (element) { + /// + /// + /// Gets the height of the element, including its margins. + /// + /// + /// The element. + /// + /// + /// The height of the element including margins. + /// + /// + var margin = getDimension(element, "marginTop") + getDimension(element, "marginBottom"); + return element.offsetHeight + margin; + }, + _getPreciseTotalHeight: function (element) { + var margin = _getPreciseDimension(element, "marginTop") + _getPreciseDimension(element, "marginBottom"); + return element.offsetHeight + margin; + }, + + getPosition: function (element) { + /// + /// + /// Gets the position of the specified element. + /// + /// + /// The element. + /// + /// + /// An object that contains the left, top, width and height properties of the element. + /// + /// + return exports._getPositionRelativeTo(element, null); + }, + + getTabIndex: function (element) { + /// + /// + /// Gets the tabIndex of the specified element. + /// + /// + /// The element. + /// + /// + /// The tabIndex of the element. Returns -1 if the element cannot be tabbed to + /// + /// + // For reference: http://www.w3.org/html/wg/drafts/html/master/single-page.html#specially-focusable + var tabbableElementsRE = /BUTTON|COMMAND|MENUITEM|OBJECT|SELECT|TEXTAREA/; + if (element.disabled) { + return -1; + } + var tabIndex = element.getAttribute("tabindex"); + if (tabIndex === null || tabIndex === undefined) { + var name = element.tagName; + if (tabbableElementsRE.test(name) || + (element.href && (name === "A" || name === "AREA" || name === "LINK")) || + (name === "INPUT" && element.type !== "hidden") || + (name === "TH" && element.sorted)) { + return 0; + } + return -1; + } + return parseInt(tabIndex, 10); + }, + + convertToPixels: convertToPixels, + _convertToPrecisePixels: _convertToPrecisePixels, + _getPreciseMargins: _getPreciseMargins, + + + eventWithinElement: function (element, event) { + /// + /// + /// Determines whether the specified event occurred within the specified element. + /// + /// + /// The element. + /// + /// + /// The event. + /// + /// + /// true if the event occurred within the element; otherwise, false. + /// + /// + var related = event.relatedTarget; + if (related && related !== element) { + return element.contains(related); + } + + return false; + }, + + //UI Utilities + _deprecated: function (message) { + _Global.console && _Global.console.warn(message); + }, + + // Take a renderer which may be a function (signature: (data) => element) or a WinJS.Binding.Template + // and return a function with a unified synchronous contract which is: + // + // (data, container) => element + // + // Where: + // + // 1) if you pass container the content will be rendered into the container and the + // container will be returned. + // + // 2) if you don't pass a container the content will be rendered and returned. + // + _syncRenderer: function (renderer, tagName) { + tagName = tagName || "div"; + if (typeof renderer === "function") { + return function (data, container) { + if (container) { + container.appendChild(renderer(data)); + return container; + } else { + return renderer(data); + } + }; + } + + var template; + if (typeof renderer.render === "function") { + template = renderer; + } else if (renderer.winControl && typeof renderer.winControl.render === "function") { + template = renderer.winControl; + } + + return function (data, container) { + var host = container || _Global.document.createElement(tagName); + template.render(data, host); + if (container) { + return container; + } else { + // The expectation is that the creation of the DOM elements happens synchronously + // and as such we steal the first child and make it the root element. + // + var element = host.firstElementChild; + + // Because we have changed the "root" we may need to move the dispose method + // created by the template to the child and do a little switcheroo on dispose. + // + if (element && host.dispose) { + var prev = element.dispose; + element.dispose = function () { + element.dispose = prev; + host.appendChild(element); + host.dispose(); + }; + } + return element; + } + }; + }, + + _getPositionRelativeTo: function Utilities_getPositionRelativeTo(element, ancestor) { + var fromElement = element, + offsetParent = element.offsetParent, + top = element.offsetTop, + left = element.offsetLeft; + + while ((element = element.parentNode) && + element !== ancestor && + element !== _Global.document.body && + element !== _Global.document.documentElement) { + top -= element.scrollTop; + var dir = _getComputedStyle(element, null).direction; + left -= dir !== "rtl" ? element.scrollLeft : -getAdjustedScrollPosition(element).scrollLeft; + + if (element === offsetParent) { + top += element.offsetTop; + left += element.offsetLeft; + offsetParent = element.offsetParent; + } + } + + return { + left: left, + top: top, + width: fromElement.offsetWidth, + height: fromElement.offsetHeight + }; + }, + + // *element* is not included in the tabIndex search + _getHighAndLowTabIndices: function Utilities_getHighAndLowTabIndices(element) { + var descendants = element.getElementsByTagName("*"); + var lowestTabIndex = 0; + var highestTabIndex = 0; + // tabIndex=0 is the highest (considered higher than positive tab indices) so + // we can stop searching for a higher tab index once we find tabIndex=0. + var foundTabIndex0 = false; + for (var i = 0, len = descendants.length; i < len; i++) { + var tabIndexStr = descendants[i].getAttribute("tabIndex"); + if (tabIndexStr !== null && tabIndexStr !== undefined) { + var tabIndex = parseInt(tabIndexStr, 10); + // Update lowest + if (tabIndex > 0 && (tabIndex < lowestTabIndex || lowestTabIndex === 0)) { + lowestTabIndex = tabIndex; + } + // Update highest + if (!foundTabIndex0) { + if (tabIndex === 0) { + foundTabIndex0 = true; + highestTabIndex = 0; + } else if (tabIndex > highestTabIndex) { + highestTabIndex = tabIndex; + } + } + } + } + + return { + highest: highestTabIndex, + lowest: lowestTabIndex + }; + }, + + _getLowestTabIndexInList: function Utilities_getLowestTabIndexInList(elements) { + // Returns the lowest positive tabIndex in a list of elements. + // Returns 0 if there are no positive tabIndices. + var lowestTabIndex = 0; + var elmTabIndex; + for (var i = 0; i < elements.length; i++) { + elmTabIndex = parseInt(elements[i].getAttribute("tabIndex"), 10); + if ((0 < elmTabIndex) + && ((elmTabIndex < lowestTabIndex) || !lowestTabIndex)) { + lowestTabIndex = elmTabIndex; + } + } + + return lowestTabIndex; + }, + + _getHighestTabIndexInList: function Utilities_getHighestTabIndexInList(elements) { + // Returns 0 if any element is explicitly set to 0. (0 is the highest tabIndex) + // Returns the highest tabIndex in the list of elements. + // Returns 0 if there are no positive tabIndices. + var highestTabIndex = 0; + var elmTabIndex; + for (var i = 0; i < elements.length; i++) { + elmTabIndex = parseInt(elements[i].getAttribute("tabIndex"), 10); + if (elmTabIndex === 0) { + return elmTabIndex; + } else if (highestTabIndex < elmTabIndex) { + highestTabIndex = elmTabIndex; + } + } + + return highestTabIndex; + }, + + _hasCursorKeysBehaviors: function Utilities_hasCursorKeysBehaviors(element) { + if (element.tagName === "SELECT" || + element.tagName === "TEXTAREA") { + return true; + } + if (element.tagName === "INPUT") { + return element.type === "" || + element.type === "date" || + element.type === "datetime" || + element.type === "datetime-local" || + element.type === "email" || + element.type === "month" || + element.type === "number" || + element.type === "password" || + element.type === "range" || + element.type === "search" || + element.type === "tel" || + element.type === "text" || + element.type === "time" || + element.type === "url" || + element.type === "week"; + } + return false; + }, + + _reparentChildren: function (originalParent, destinationParent) { + var child = originalParent.firstChild; + while (child) { + var sibling = child.nextSibling; + destinationParent.appendChild(child); + child = sibling; + } + }, + + // Ensures that the same element has focus before and after *callback* is + // called. Useful if moving focus is an unintentional side effect of *callback*. + // For example, this could happen if *callback* removes and reinserts elements + // to the DOM. + _maintainFocus: function ElementUtilities_maintainFocus(callback) { + var focusedElement = _Global.document.activeElement; + callback(); + exports._trySetActiveOnAnyElement(focusedElement); + }, + + // Tries to give focus to an element (even if its tabIndex is -1) via setActive. + _trySetActiveOnAnyElement: function Utilities_trySetActiveOnAnyElement(element, scroller) { + return exports._tryFocusOnAnyElement(element, true, scroller); + }, + + // Tries to give focus to an element (even if its tabIndex is -1). + _tryFocusOnAnyElement: function Utilities_tryFocusOnAnyElement(element, useSetActive, scroller) { + var previousActiveElement = _Global.document.activeElement; + + if (element === previousActiveElement) { + return true; + } + + if (useSetActive) { + exports._setActive(element, scroller); + } else { + element.focus(); + } + + return previousActiveElement !== _Global.document.activeElement; + }, + + // Tries to give focus to an element which is a tabstop (i.e. tabIndex >= 0) + // via setActive. + _trySetActive: function Utilities_trySetActive(elem, scroller) { + return this._tryFocus(elem, true, scroller); + }, + + // Tries to give focus to an element which is a tabstop (i.e. tabIndex >= 0). + _tryFocus: function Utilities_tryFocus(elem, useSetActive, scroller) { + var previousActiveElement = _Global.document.activeElement; + + if (elem === previousActiveElement) { + return true; + } + + var simpleLogicForValidTabStop = (exports.getTabIndex(elem) >= 0); + if (!simpleLogicForValidTabStop) { + return false; + } + + if (useSetActive) { + exports._setActive(elem, scroller); + } else { + elem.focus(); + } + + if (previousActiveElement !== _Global.document.activeElement) { + return true; + } + return false; + }, + + _setActiveFirstFocusableElement: function Utilities_setActiveFirstFocusableElement(rootEl, scroller) { + return this._focusFirstFocusableElement(rootEl, true, scroller); + }, + + _focusFirstFocusableElement: function Utilities_focusFirstFocusableElement(rootEl, useSetActive, scroller) { + var _elms = rootEl.getElementsByTagName("*"); + + // Get the tabIndex set to the firstDiv (which is the lowest) + var _lowestTabIndex = this._getLowestTabIndexInList(_elms); + var _nextLowestTabIndex = 0; + + // If there are positive tabIndices, set focus to the element with the lowest tabIndex. + // Keep trying with the next lowest tabIndex until all tabIndices have been exhausted. + // Otherwise set focus to the first focusable element in DOM order. + var i; + while (_lowestTabIndex) { + for (i = 0; i < _elms.length; i++) { + if (_elms[i].tabIndex === _lowestTabIndex) { + if (this._tryFocus(_elms[i], useSetActive, scroller)) { + return true; + } + } else if ((_lowestTabIndex < _elms[i].tabIndex) + && ((_elms[i].tabIndex < _nextLowestTabIndex) || (_nextLowestTabIndex === 0))) { + // Here if _lowestTabIndex < _elms[i].tabIndex < _nextLowestTabIndex + _nextLowestTabIndex = _elms[i].tabIndex; + } + } + + // We weren't able to set focus to anything at that tabIndex + // If we found a higher valid tabIndex, try that now + _lowestTabIndex = _nextLowestTabIndex; + _nextLowestTabIndex = 0; + } + + // Wasn't able to set focus to anything with a positive tabIndex, try everything now. + // This is where things with tabIndex of 0 will be tried. + for (i = 0; i < _elms.length; i++) { + if (this._tryFocus(_elms[i], useSetActive, scroller)) { + return true; + } + } + + return false; + }, + + _setActiveLastFocusableElement: function Utilities_setActiveLastFocusableElement(rootEl, scroller) { + return this._focusLastFocusableElement(rootEl, true, scroller); + }, + + _focusLastFocusableElement: function Utilities_focusLastFocusableElement(rootEl, useSetActive, scroller) { + var _elms = rootEl.getElementsByTagName("*"); + // Get the tabIndex set to the finalDiv (which is the highest) + var _highestTabIndex = this._getHighestTabIndexInList(_elms); + var _nextHighestTabIndex = 0; + + // Try all tabIndex 0 first. After this conditional the _highestTabIndex + // should be equal to the highest positive tabIndex. + var i; + if (_highestTabIndex === 0) { + for (i = _elms.length - 1; i >= 0; i--) { + if (_elms[i].tabIndex === _highestTabIndex) { + if (this._tryFocus(_elms[i], useSetActive, scroller)) { + return true; + } + } else if (_nextHighestTabIndex < _elms[i].tabIndex) { + _nextHighestTabIndex = _elms[i].tabIndex; + } + } + + _highestTabIndex = _nextHighestTabIndex; + _nextHighestTabIndex = 0; + } + + // If there are positive tabIndices, set focus to the element with the highest tabIndex. + // Keep trying with the next highest tabIndex until all tabIndices have been exhausted. + // Otherwise set focus to the last focusable element in DOM order. + while (_highestTabIndex) { + for (i = _elms.length - 1; i >= 0; i--) { + if (_elms[i].tabIndex === _highestTabIndex) { + if (this._tryFocus(_elms[i], useSetActive, scroller)) { + return true; + } + } else if ((_nextHighestTabIndex < _elms[i].tabIndex) && (_elms[i].tabIndex < _highestTabIndex)) { + // Here if _nextHighestTabIndex < _elms[i].tabIndex < _highestTabIndex + _nextHighestTabIndex = _elms[i].tabIndex; + } + } + + // We weren't able to set focus to anything at that tabIndex + // If we found a lower valid tabIndex, try that now + _highestTabIndex = _nextHighestTabIndex; + _nextHighestTabIndex = 0; + } + + // Wasn't able to set focus to anything with a tabIndex, try everything now + for (i = _elms.length - 2; i > 0; i--) { + if (this._tryFocus(_elms[i], useSetActive, scroller)) { + return true; + } + } + + return false; + } + }); +}); diff --git a/refactor/baselines/site-vendor/monaco-dom/winjs-license.txt b/refactor/baselines/site-vendor/monaco-dom/winjs-license.txt new file mode 100644 index 000000000..baf9dc11a --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-dom/winjs-license.txt @@ -0,0 +1,13 @@ +WinJS + +Copyright (c) Microsoft Corporation + +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/refactor/changes/2026-09-15-SITE-07-monaco-dom.md b/refactor/changes/2026-09-15-SITE-07-monaco-dom.md new file mode 100644 index 000000000..4098e77c6 --- /dev/null +++ b/refactor/changes/2026-09-15-SITE-07-monaco-dom.md @@ -0,0 +1,51 @@ +# SITE-07 Monaco DOM 改编来源与通知交付 + +来源 HEAD:`3eb550052531094753207bdadf4b0e32687792de`。SITE-07 继续 doing, +VENDOR-06 继续 open;本次没有更改编辑器脚本、CSS、worker 或播放器运行字节。 + +## 已核实范围 + +固定 VS Code `829382514cb1065f5ebb90f436e1c6103e153953` 的 dom.ts 五处明确注明 +WinJS 改编。六个完整声明块——SizeUtils、getTopLeftOffset、getTotalWidth、 +getContentWidth、getContentHeight、getTotalHeight——与 Monaco 0.30.1 原始 +source map 的对应内容精确相同;当前 editor.main.js 与固定 npm 归档逐字节一致。 +这不是完整 DOM 模块的编译证明,也不把 reference 注释等同于特定上游版本证据。 + +原注释没有 WinJS 版本。本批固定 WinJS 4.4.5 提交 +`4329b1133b243d9ded3b5a1f98d096ee8e80e889` 的 `_ElementUtilities.js` 和完整 +Microsoft MIT 许可作比较,保留 `originalWinjsVersion: null`。参考源码与 VS Code +改编存在像素转换、CSS 属性读取、尺寸助手、边框/RTL/ShadowRoot 位置处理等差异, +没有把两套实现强行判为完全相同,也没有声称添加前必然缺少 Microsoft 的许可授权。 +完整参考许可和说明作为补充交付,原 Monaco 许可及 ThirdPartyNotices 均保留。 + +固定远端文件同时校验 SHA-256 和 Git blob SHA;两个 npm archive 校验 SHA-512/ +SHA-256。源码保存在 `baselines/site-vendor/monaco-dom/`,保留原始字节,不经 +Git 自动换行转换。说明明确标注参考版本和未知原始版本,后续 AI 不应把它改写为 +“Monaco 内含原版 WinJS 4.4.5”。 + +## 实现与维护 + +- `scripts/site-vendor/monaco/dom-origins.ts` 管理声明边界及来源/通知绑定;以现有 + TypeScript 5.9.3 parser 识别完整顶层节点,不执行下载的 WinJS 代码。 +- `reproduce-dom-origins.ts` 校验冻结来源、源码片段与原 map、交付脚本归档身份; + 新增 `yarn verify:monaco-dom-origins [--fetch]`,没有新依赖或锁文件变化。 +- 正常 `build:site-notices` 增加 core-dom 完整许可/说明及索引,合计 88 份 notice + 加索引 89 outputs;校验器拒绝遗漏编辑器归属、条款或来源声明。 +- 测试覆盖缺少/重复声明、同名字符串冒充声明、遗漏条款和错误资产归属。真实 + 浏览器直接调用现有 Monaco 模块,在 padding/border/margin/嵌套滚动前后检查 + 尺寸和原生页面位置;不是测试自造 DOM 工具的替代实现。 + +维护入口与复跑命令见 [Monaco README](../../scripts/site-vendor/monaco/README.md)。 + +## 验证与限制 + +Node 24.21.0、Yarn 1.22.22;30/30 单测,严格 docs-tools 类型与定向只读 lint +通过。联网/离线来源核验、正常通知生成及只读检查分别执行并记录。 +Chromium 153.0.8010.12、Firefox 155.0、WebKit 26.6 的 DOM 检查和移动页面实际 +播放/全部 notice HTTP/新增相对链接共 6/6,零跳过/重试;原始网络诊断保留在 +[机器证据](../baselines/monaco-dom-origins-validation.json),不宣称所有请求无取消。 + +原始 WinJS 改编版本仍未知;Unicode 数据、其他内嵌来源、完整 core TS 编译及 +SITE-07 其他范围继续开放。没有在本轮补证据时悄悄放宽这些验收条件;202/266 +完成数不变。回退本批时一并撤销通知绑定/新增文件并重建索引,不触碰原编辑器 +资产。未推送、部署或发布。 diff --git a/refactor/plan.md b/refactor/plan.md index f7eeb8fc0..a5400f91e 100644 --- a/refactor/plan.md +++ b/refactor/plan.md @@ -655,7 +655,7 @@ - SITE-AI-DOCS-01: [记录](changes/2026-09-14-SITE-AI-DOCS-01-documentation-pipeline.md) [记录](baselines/documentation-pipeline-validation.json) - SITE-BUILD-01: [记录](changes/2026-09-14-SITE-BUILD-01-staged-builds.md) [记录](baselines/site-build-validation.json) - SITE-03: [记录](changes/2026-09-14-SITE-03-desktop-editor.md) [记录](baselines/site-editor-validation.json) -- SITE-07: [记录](site-inventory.md) [记录](baselines/site-provenance.json) [记录](changes/2026-09-14-SITE-07-vendor-notices.md) [记录](baselines/site-notices-checkpoint.json) [记录](baselines/site-codicons-provenance.json) [记录](baselines/site-codicons-validation.json) [记录](changes/2026-09-15-SITE-07-codicons.md) [记录](baselines/vconsole-notices-provenance.json) [记录](baselines/vconsole-notices-validation.json) [记录](changes/2026-09-15-SITE-07-vconsole-notices.md) [记录](console-modernization.md) [记录](baselines/site-console-inventory.json) [记录](baselines/site-console-validation.json) [记录](changes/2026-09-15-SITE-07-console-baseline.md) [记录](baselines/console-feed-provenance.json) [记录](changes/2026-09-15-SITE-07-console-feed-source.md) [记录](baselines/console-commonjs-provenance.json) [记录](changes/2026-09-15-SITE-07-console-commonjs.md) [记录](baselines/console-esm-provenance.json) [记录](changes/2026-09-15-SITE-07-console-esm.md) [记录](baselines/console-embedded-notices.json) [记录](baselines/console-notices-validation.json) [记录](changes/2026-09-15-SITE-07-console-notices.md) [记录](baselines/console-embedded-sources.json) [记录](baselines/console-embedded-validation.json) [记录](changes/2026-09-15-SITE-07-console-embedded-sources.md) [记录](baselines/console-derived-attribution.json) [记录](baselines/console-derived-validation.json) [记录](changes/2026-09-15-SITE-07-console-derived-attribution.md) [记录](baselines/console-stackoverflow-provenance.json) [记录](baselines/console-stackoverflow-validation.json) [记录](changes/2026-09-15-SITE-07-console-stackoverflow.md) [记录](baselines/console-shallowequal-validation.json) [记录](changes/2026-09-15-SITE-07-console-shallowequal.md) [记录](console-notice-review.md) [记录](baselines/console-notice-review-validation.json) [记录](changes/2026-09-15-SITE-07-console-notice-review.md) [记录](baselines/monaco-typescript-provenance.json) [记录](baselines/monaco-typescript-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-typescript.md) [记录](baselines/monaco-languages-provenance.json) [记录](baselines/monaco-languages-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-languages.md) [记录](baselines/monaco-language-notices.json) [记录](baselines/monaco-language-notices-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-language-notices.md) [记录](baselines/monaco-modes-provenance.json) [记录](baselines/monaco-modes-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-modes.md) [记录](baselines/monaco-basic-provenance.json) [记录](baselines/monaco-basic-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-basic.md) [记录](baselines/monaco-core-origins-provenance.json) [记录](baselines/monaco-core-origins-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-core-origins.md) [记录](baselines/monaco-core-build-provenance.json) [记录](baselines/monaco-core-build-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-core-build.md) [记录](baselines/monaco-contributions-provenance.json) [记录](baselines/monaco-contributions-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-contributions.md) [记录](baselines/monaco-css-build-provenance.json) [记录](baselines/monaco-css-build-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-css.md) [记录](baselines/monaco-node-path-provenance.json) [记录](baselines/monaco-node-path-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-node-path.md) +- SITE-07: [记录](site-inventory.md) [记录](baselines/site-provenance.json) [记录](changes/2026-09-14-SITE-07-vendor-notices.md) [记录](baselines/site-notices-checkpoint.json) [记录](baselines/site-codicons-provenance.json) [记录](baselines/site-codicons-validation.json) [记录](changes/2026-09-15-SITE-07-codicons.md) [记录](baselines/vconsole-notices-provenance.json) [记录](baselines/vconsole-notices-validation.json) [记录](changes/2026-09-15-SITE-07-vconsole-notices.md) [记录](console-modernization.md) [记录](baselines/site-console-inventory.json) [记录](baselines/site-console-validation.json) [记录](changes/2026-09-15-SITE-07-console-baseline.md) [记录](baselines/console-feed-provenance.json) [记录](changes/2026-09-15-SITE-07-console-feed-source.md) [记录](baselines/console-commonjs-provenance.json) [记录](changes/2026-09-15-SITE-07-console-commonjs.md) [记录](baselines/console-esm-provenance.json) [记录](changes/2026-09-15-SITE-07-console-esm.md) [记录](baselines/console-embedded-notices.json) [记录](baselines/console-notices-validation.json) [记录](changes/2026-09-15-SITE-07-console-notices.md) [记录](baselines/console-embedded-sources.json) [记录](baselines/console-embedded-validation.json) [记录](changes/2026-09-15-SITE-07-console-embedded-sources.md) [记录](baselines/console-derived-attribution.json) [记录](baselines/console-derived-validation.json) [记录](changes/2026-09-15-SITE-07-console-derived-attribution.md) [记录](baselines/console-stackoverflow-provenance.json) [记录](baselines/console-stackoverflow-validation.json) [记录](changes/2026-09-15-SITE-07-console-stackoverflow.md) [记录](baselines/console-shallowequal-validation.json) [记录](changes/2026-09-15-SITE-07-console-shallowequal.md) [记录](console-notice-review.md) [记录](baselines/console-notice-review-validation.json) [记录](changes/2026-09-15-SITE-07-console-notice-review.md) [记录](baselines/monaco-typescript-provenance.json) [记录](baselines/monaco-typescript-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-typescript.md) [记录](baselines/monaco-languages-provenance.json) [记录](baselines/monaco-languages-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-languages.md) [记录](baselines/monaco-language-notices.json) [记录](baselines/monaco-language-notices-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-language-notices.md) [记录](baselines/monaco-modes-provenance.json) [记录](baselines/monaco-modes-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-modes.md) [记录](baselines/monaco-basic-provenance.json) [记录](baselines/monaco-basic-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-basic.md) [记录](baselines/monaco-core-origins-provenance.json) [记录](baselines/monaco-core-origins-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-core-origins.md) [记录](baselines/monaco-core-build-provenance.json) [记录](baselines/monaco-core-build-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-core-build.md) [记录](baselines/monaco-contributions-provenance.json) [记录](baselines/monaco-contributions-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-contributions.md) [记录](baselines/monaco-css-build-provenance.json) [记录](baselines/monaco-css-build-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-css.md) [记录](baselines/monaco-node-path-provenance.json) [记录](baselines/monaco-node-path-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-node-path.md) [记录](changes/2026-09-15-SITE-07-monaco-dom.md) [记录](baselines/monaco-dom-origins-validation.json) - EX-01: [记录](changes/2026-09-14-EX-01-react-consumer.md) [记录](baselines/react-consumer-validation.json) [记录](scripts/react-consumer.mjs) - EX-02: [记录](changes/2026-09-14-EX-02-vue-consumer.md) [记录](baselines/vue-consumer-validation.json) [记录](scripts/vue-consumer.mjs) - MOD-01: [记录](changes/2026-09-15-MOD-01-bun-evaluation.md) [记录](baselines/bun-install-validation.json) [记录](bun-evaluation.md) diff --git a/refactor/progress.md b/refactor/progress.md index 4557deb57..301a9e654 100644 --- a/refactor/progress.md +++ b/refactor/progress.md @@ -1,5 +1,11 @@ # 进度与证据 +## SITE-07 Monaco DOM 改编来源与通知绑定 + +六段 DOM 声明与固定 VS Code 源码及原始 source map 精确对应,当前 editor.main.js 与原 npm 归档相同。新增 WinJS 4.4.5 固定参考源码/完整 MIT 条款和明确的未知原始改编版本说明;普通构建交付 88 份 notice 加索引。30/30 单测、类型/lint、联网/离线复验和三浏览器尺寸/滚动位置/移动实播/通知 HTTP 6/6 通过。见[记录](changes/2026-09-15-SITE-07-monaco-dom.md)和[证据](baselines/monaco-dom-origins-validation.json)。 + +新增验证脚本仅用已有 TypeScript parser,无依赖/锁或运行资产变化。原始 WinJS 改编版本、Unicode/其他内嵌来源、完整 core 编译及 SITE-07 其他交付仍开放,VENDOR-06 不关闭。202/266 done、21 doing、43 todo 不变;接续其余来源和实际插件验收,未推送/部署/发布。 + ## PKG-AUDIO-05 同文件前缀与原生缓冲检查点 仅改变同一 MP4/AAC 的 HTTP 放行前缀,Windows WebKit 能起播,但四项较大前缀诊断仍没有可信 waiting。默认三引擎 12 项诊断通过,实际 progressed/waiting 为 Chromium/Firefox 8/8、WebKit 0/4;诊断退出成功不算缓冲验收。新增参数只影响 native spec,放行前请求字节/媒体状态独立保存,恢复失败也保留观察。原插件集成断言、超时和运行字节均未改。见[检查点](changes/2026-09-15-PKG-AUDIO-05-prefix.md)及[证据](baselines/audio-prefix-validation.json)。 diff --git a/refactor/risks.json b/refactor/risks.json index 77ac69160..d92a72725 100644 --- a/refactor/risks.json +++ b/refactor/risks.json @@ -661,11 +661,14 @@ "refactor/changes/2026-09-15-SITE-07-monaco-css.md", "refactor/baselines/monaco-node-path-provenance.json", "refactor/baselines/monaco-node-path-validation.json", - "refactor/changes/2026-09-15-SITE-07-monaco-node-path.md" + "refactor/changes/2026-09-15-SITE-07-monaco-node-path.md", + "refactor/changes/2026-09-15-SITE-07-monaco-dom.md", + "refactor/baselines/monaco-dom-origins-provenance.json", + "refactor/baselines/monaco-dom-origins-validation.json" ], "compatibleResolution": "Keep separate from owned TS migration. Verify source/version/diff and license notices before replacement; preserve API/CSS/worker URLs and run owning package tests.", "closureCriteria": "固定上游版本/内容差异、完整组件许可与分发 notices,兼容测试通过;仅当前上游许可证名称不足以关闭。", - "workspaceState": "Monaco 0.30.1 remains byte-pinned, including its known CSS newline-only difference. Codicons 0.0.26, TypeScript 4.4.4 and language-service licenses are delivered. Three service workers, four modes and 76 basic-language bundles reproduce exactly; all 13 core JS minified outputs reproduce with locked esbuild 0.12.6 on Windows x64. Loader/header and css/nls source origins match fixed Git; two maps inventory 584 prepared-source entries and 549 different names. DOMPurify 2.3.1 and marked 3.0.2 have exact source adaptations and complete notice supplements; 85 site notices were verified by HTTP/mobile browser checks. Latest contribution check verifies six archives and 102 Git members, emits 88 TS registration modules and uses RequireJS 2.3.6/Terser 5.9.0 to reproduce the entire dev/min editor assembly, including core string-table entry, dependency injection, order, alias and map trailer. Latest units 23/23, strict type/lint and offline/network source checks pass; modes/tokenizer regressions pass 6/6 across three engines with 2523 token cases per engine. Earlier ten-locale editing/find 30/30 and diff-worker 3/3 evidence remains recorded separately. CSS now reproduces from 68 styles, three embedded images and the copied font, with 81 verified Git members. The archived transport/plugin recipes match every prepared ESM stylesheet; explicit normalization of 70 generated CRLF separators reproduces the entire development CSS. cssnano 4.1.11/PostCSS 7.0.35 reproduce complete minified CSS using isolated frozen Yarn installs (153 selectors/143 versions) and historical browser defaults. The site retains its five header CRLF differences. The exact upstream stage that normalized the 70 development separators is still unidentified. Latest units 25/25, strict type/lint and offline/network checks pass; new three-engine style/theme/font/resize regressions pass 3/3. Original core TS compilation and remaining embedded-origin review stay open; this is not release approval or an exhaustive sanitizer audit. The Node path origin is now fixed to v14.16.0/bd60e93357a118204ea238d94e7a9e4209d93062 and the verified VS Code port. Its complete existing notice text matches both sources; a source supplement corrects the older index link without rewriting it. Six removed exports reproduce both source-map inputs; pinned TS 4.5.0-dev.20211021 emits exact full editor/worker modules. Thirty deterministic original Node path results pass in each browser engine, together with all 86 delivered notices and actual playback: 6/6 browser, 28/28 unit, type/lint, offline/network checks. Chromium retains one observed media ERR_ABORTED despite successful playback. Other embedded origins/full core compilation remain open." + "workspaceState": "Monaco 0.30.1 remains byte-pinned, including its known CSS newline-only difference. Codicons 0.0.26, TypeScript 4.4.4 and language-service licenses are delivered. Three service workers, four modes and 76 basic-language bundles reproduce exactly; all 13 core JS minified outputs reproduce with locked esbuild 0.12.6 on Windows x64. Loader/header and css/nls source origins match fixed Git; two maps inventory 584 prepared-source entries and 549 different names. DOMPurify 2.3.1 and marked 3.0.2 have exact source adaptations and complete notice supplements; 85 site notices were verified by HTTP/mobile browser checks. Latest contribution check verifies six archives and 102 Git members, emits 88 TS registration modules and uses RequireJS 2.3.6/Terser 5.9.0 to reproduce the entire dev/min editor assembly, including core string-table entry, dependency injection, order, alias and map trailer. Latest units 23/23, strict type/lint and offline/network source checks pass; modes/tokenizer regressions pass 6/6 across three engines with 2523 token cases per engine. Earlier ten-locale editing/find 30/30 and diff-worker 3/3 evidence remains recorded separately. CSS now reproduces from 68 styles, three embedded images and the copied font, with 81 verified Git members. The archived transport/plugin recipes match every prepared ESM stylesheet; explicit normalization of 70 generated CRLF separators reproduces the entire development CSS. cssnano 4.1.11/PostCSS 7.0.35 reproduce complete minified CSS using isolated frozen Yarn installs (153 selectors/143 versions) and historical browser defaults. The site retains its five header CRLF differences. The exact upstream stage that normalized the 70 development separators is still unidentified. Latest units 25/25, strict type/lint and offline/network checks pass; new three-engine style/theme/font/resize regressions pass 3/3. Original core TS compilation and remaining embedded-origin review stay open; this is not release approval or an exhaustive sanitizer audit. The Node path origin is now fixed to v14.16.0/bd60e93357a118204ea238d94e7a9e4209d93062 and the verified VS Code port. Its complete existing notice text matches both sources; a source supplement corrects the older index link without rewriting it. Six removed exports reproduce both source-map inputs; pinned TS 4.5.0-dev.20211021 emits exact full editor/worker modules. Thirty deterministic original Node path results pass in each browser engine, together with all 86 delivered notices and actual playback: 6/6 browser, 28/28 unit, type/lint, offline/network checks. Chromium retains one observed media ERR_ABORTED despite successful playback. Other embedded origins/full core compilation remain open. DOM helpers now bind six exact VS Code/source-map declarations and fixed WinJS4.4.5 comparison source/complete MIT terms to the unchanged editor; original adaptation version remains unknown, not inferred from that reference. Other origins and full original core compilation remain open." }, { "id": "VENDOR-07", diff --git a/refactor/tasks.json b/refactor/tasks.json index c0cb58686..f8e220040 100644 --- a/refactor/tasks.json +++ b/refactor/tasks.json @@ -4556,7 +4556,9 @@ "changes/2026-09-15-SITE-07-monaco-css.md", "baselines/monaco-node-path-provenance.json", "baselines/monaco-node-path-validation.json", - "changes/2026-09-15-SITE-07-monaco-node-path.md" + "changes/2026-09-15-SITE-07-monaco-node-path.md", + "changes/2026-09-15-SITE-07-monaco-dom.md", + "baselines/monaco-dom-origins-validation.json" ] }, { diff --git a/refactor/third-party.json b/refactor/third-party.json index df9a8ba54..df5b69be7 100644 --- a/refactor/third-party.json +++ b/refactor/third-party.json @@ -512,10 +512,11 @@ "SITE-05" ], "sourceStatus": "Monaco 0.30.1 verified against official npm archive: 98 byte-exact files, one CSS newline-only difference. The bundled font additionally matches @vscode/codicons 0.0.26 exactly; see site-codicons-provenance.json.", - "licenseStatus": "Full Monaco root notices and Codicons historical notices are delivered. The actual TypeScript 4.4.4 worker is exactly reproduced and has a complete original LICENSE/CopyrightNotice/ThirdPartyNoticeText supplement plus attribution; the original stale 2.7.2 label is preserved with explanation. Other bundled-component completeness remains under VENDOR-06. No permission for unrelated fonts/media is inferred. CSS/HTML/JSON worker source proof now binds seven service packages to nine original license/third-party notice files, two embedded formatter headers and attribution. JSON glob BSD conditions and actual formatter author years are retained; all 81 site notices pass HTTP byte checks. Mode/core/basic-language and remaining embedded-source completeness stay open. All four language mode bundles are now exactly reproduced and the two shared npm dependencies are bound to those mode assets as well as workers. Core/basic-language and remaining upstream-origin review stay open.", + "licenseStatus": "Full Monaco root notices and Codicons historical notices are delivered. The actual TypeScript 4.4.4 worker is exactly reproduced and has a complete original LICENSE/CopyrightNotice/ThirdPartyNoticeText supplement plus attribution; the original stale 2.7.2 label is preserved with explanation. Other bundled-component completeness remains under VENDOR-06. No permission for unrelated fonts/media is inferred. CSS/HTML/JSON worker source proof now binds seven service packages to nine original license/third-party notice files, two embedded formatter headers and attribution. JSON glob BSD conditions and actual formatter author years are retained; all 81 site notices pass HTTP byte checks. Mode/core/basic-language and remaining embedded-source completeness stay open. All four language mode bundles are now exactly reproduced and the two shared npm dependencies are bound to those mode assets as well as workers. Core/basic-language and remaining upstream-origin review stay open. DOM adaptation supplement now delivers fixed WinJS4.4.5 reference terms and explicit unknown-original-version attribution; six fixed VS Code declaration blocks match the original source map.88 notice files plus index are served; remaining provenance is not waived.", "upstreamSources": [ "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.30.1.tgz", - "https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.26.tgz" + "https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.26.tgz", + "https://github.com/winjs/winjs/tree/4329b1133b243d9ded3b5a1f98d096ee8e80e889" ], "upstreamReviewedAt": "2026-09-15", "updatePolicy": "Keep separate from owned TS migration. Verify source/version/diff and license notices before replacement; preserve API/CSS/worker URLs and run owning package tests.", diff --git a/scripts/build-site-notices.mjs b/scripts/build-site-notices.mjs index 886fb03f4..9a78a3471 100644 --- a/scripts/build-site-notices.mjs +++ b/scripts/build-site-notices.mjs @@ -3,6 +3,7 @@ import fs from 'node:fs' import process from 'node:process' import { verifyConsoleNoticeSources } from './site-vendor/console/notices.ts' import { verifyMonacoCoreNotices } from './site-vendor/monaco/core-origins.ts' +import { verifyMonacoDomNotices } from './site-vendor/monaco/dom-origins.ts' import { verifyMonacoPathNotices } from './site-vendor/monaco/node-path.ts' import { verifyMonacoLanguageNotices } from './site-vendor/monaco/notices.ts' import { writeOrCheckNotices } from './site-vendor/notices.ts' @@ -14,6 +15,7 @@ assert.deepEqual(manifest.groups.map(group => group.name).sort(), ['console', 'm assert.deepEqual(manifest.groups.filter(group => group.name !== 'console').flatMap(group => (group.components || []).map(component => component.name)).sort(), [ '@babel/runtime', '@vscode/codicons', + 'WinJS-derived DOM helpers (Monaco core)', 'copy-text-to-clipboard', 'core-js', 'css-loader', @@ -91,6 +93,7 @@ for (const name of ['LICENSE', 'MIT-LICENSE', 'ATTRIBUTION.md']) assert(vconsoleNotices?.includes(`docs/licenses/vconsole/${name}`), `Missing vConsole notice: ${name}`) verifyConsoleNoticeSources(process.cwd(), manifest) verifyMonacoCoreNotices(process.cwd(), manifest) +verifyMonacoDomNotices(process.cwd(), manifest) verifyMonacoPathNotices(process.cwd(), manifest) verifyMonacoLanguageNotices(process.cwd(), manifest) const count = writeOrCheckNotices(process.cwd(), manifest, process.argv.includes('--check')) diff --git a/scripts/site-vendor/manifest.json b/scripts/site-vendor/manifest.json index b364eceb8..40e859fcc 100644 --- a/scripts/site-vendor/manifest.json +++ b/scripts/site-vendor/manifest.json @@ -1025,6 +1025,16 @@ "source": "refactor/baselines/site-vendor/monaco-node-path/ATTRIBUTION.md.txt", "target": "docs/licenses/monaco-editor/core-path/ATTRIBUTION.md", "sha256": "40583c701c0bcbd8e10935652a0a8b02e2073b0ef040fb7be7b939c437d8b8dc" + }, + { + "source": "refactor/baselines/site-vendor/monaco-dom/winjs-license.txt", + "target": "docs/licenses/monaco-editor/core-dom/LICENSE.txt", + "sha256": "13217bb585c27ee298f49c7aec2ef74578bc0d644880906a89d2c3ccec5d647e" + }, + { + "source": "refactor/baselines/site-vendor/monaco-dom/ATTRIBUTION.md.txt", + "target": "docs/licenses/monaco-editor/core-dom/ATTRIBUTION.md", + "sha256": "0858d19261742809cecd7174a0a06b2b0013a4b9560b78aede1edd3dd350da21" } ], "review": "The complete upstream Monaco LICENSE/ThirdPartyNotices are retained. The unmodified bundled Codicons font exactly matches @vscode/codicons 0.0.26; its historical README, CC BY 4.0 content license, MIT code license and added attribution are distributed below. Other site assets remain subject to their separate provenance reviews.", @@ -1217,6 +1227,18 @@ "docs/licenses/monaco-editor/ThirdPartyNotices.txt", "docs/licenses/monaco-editor/core-path/ATTRIBUTION.md" ] + }, + { + "name": "WinJS-derived DOM helpers (Monaco core)", + "version": "unversioned adaptation; reference WinJS 4.4.5", + "tarball": "https://github.com/winjs/winjs/tree/4329b1133b243d9ded3b5a1f98d096ee8e80e889", + "assets": [ + "docs/assets/js/vs/editor/editor.main.js" + ], + "notices": [ + "docs/licenses/monaco-editor/core-dom/LICENSE.txt", + "docs/licenses/monaco-editor/core-dom/ATTRIBUTION.md" + ] } ] }, diff --git a/scripts/site-vendor/monaco/README.md b/scripts/site-vendor/monaco/README.md index c7d97e086..59cb6a114 100644 --- a/scripts/site-vendor/monaco/README.md +++ b/scripts/site-vendor/monaco/README.md @@ -370,3 +370,39 @@ yarn test:browser test/browser/editor-path.spec.js test/browser/site-vendor.spec Full original core TypeScript compilation, WinJS/Unicode/other embedded origins and the overall SITE-07 acceptance remain separate. A path-module proof is not an exhaustive claim about every Node API or the rest of Monaco. + +## WinJS-derived DOM declarations + +`dom-origins.ts` identifies six complete top-level declaration blocks in fixed +VS Code `dom.ts`. `reproduce-dom-origins.ts` verifies those exact blocks in the +original editor source map and checks that the shipped editor still equals the +fixed npm archive. AST declaration boundaries reject same-named strings, missing +blocks and duplicate declarations. This is not compilation of the full DOM module. + +The source explicitly attributes helpers to WinJS but does not identify the copied +version. The record keeps `originalWinjsVersion: null`. A fixed WinJS 4.4.5 source +and its complete Microsoft MIT terms provide a reproducible comparison, not an +assertion that Monaco incorporates that exact unmodified release. The generated +core-dom attribution explains CSS/pixel, position and typed-helper adaptations. +Do not replace this distinction with a guessed version during later maintenance. + +The ordinary notice build binds the reference license and attribution to the +editor asset; it rejects omitted terms or a changed source/asset relationship. +The site now carries 88 notice files plus its index. Frozen source and delivered +terms preserve original bytes through Git attributes. No dependencies or editor +runtime bytes changed; the verifier uses the existing TypeScript parser. + +```sh +yarn verify:monaco-dom-origins --fetch +yarn verify:monaco-dom-origins +yarn build:site-notices +yarn check:site-notices +yarn test:browser editor-dom.spec.js site-vendor.spec.js --workers=1 +``` + +The browser test calls the actual shipped editor's dimension/position helpers +with borders, padding, margins and nested scrolling, comparing page offsets with +native geometry. The site test checks all notice HTTP bytes, relative links and +real mobile-page playback. Unicode/other embedded sources, unknown original +WinJS version, complete original core compilation and SITE-07 acceptance remain +open. Source comments and this bounded proof are not full provenance clearance. diff --git a/scripts/site-vendor/monaco/dom-origins.ts b/scripts/site-vendor/monaco/dom-origins.ts new file mode 100644 index 000000000..73649acd7 --- /dev/null +++ b/scripts/site-vendor/monaco/dom-origins.ts @@ -0,0 +1,63 @@ +import type { VendorManifest } from '../notices.ts' +import type { Archive, Member, Remote } from './archives.ts' +import assert from 'node:assert/strict' +import { Buffer } from 'node:buffer' +import fs from 'node:fs' +import path from 'node:path' +import ts from 'typescript' +import { hash } from './archives.ts' + +export const domOriginNames = ['SizeUtils', 'getTopLeftOffset', 'getTotalWidth', 'getContentWidth', 'getContentHeight', 'getTotalHeight'] + +export interface DomOrigins { + archives: Archive[] + remotes: Remote[] + vscodeSource: string + winjsSource: string + map: Member & { source: string } + fragments: { name: string, sha256: string }[] + shipped: Member & { target: string } + component: { name: string, version: string, tarball: string, assets: string[], notices: string[] } + notices: { source: string, target: string, sha256: string }[] + originalWinjsVersion: null +} + +// Match declaration boundaries, never a same-named string or a substring of a function. +export function domOriginFragments(source: string): Map { + const file = ts.createSourceFile('dom.ts', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS) + const fragments = new Map() + for (const node of file.statements) { + if ((!ts.isClassDeclaration(node) && !ts.isFunctionDeclaration(node)) || !node.name || !domOriginNames.includes(node.name.text)) + continue + assert(!fragments.has(node.name.text), 'Repeated DOM origin declaration') + fragments.set(node.name.text, node.getText(file)) + } + assert.deepEqual([...fragments.keys()], domOriginNames, 'Missing or reordered DOM origin declarations') + return fragments +} + +export function readDomOrigins(root: string): DomOrigins { + return JSON.parse(fs.readFileSync(path.join(root, 'refactor/baselines/monaco-dom-origins-provenance.json'), 'utf8')) +} + +export function verifyMonacoDomNotices(root: string, manifest: VendorManifest): void { + const record = readDomOrigins(root) + assert.equal(record.originalWinjsVersion, null, 'Do not invent the original WinJS adaptation version') + assert.equal(record.component.name, 'WinJS-derived DOM helpers (Monaco core)') + assert.equal(record.component.version, 'unversioned adaptation; reference WinJS 4.4.5') + assert.equal(record.component.tarball, 'https://github.com/winjs/winjs/tree/4329b1133b243d9ded3b5a1f98d096ee8e80e889', 'Wrong fixed WinJS reference') + assert.deepEqual(record.component.assets, ['docs/assets/js/vs/editor/editor.main.js'], 'Wrong DOM origin assets') + assert.deepEqual(record.notices.map(notice => notice.target), ['docs/licenses/monaco-editor/core-dom/LICENSE.txt', 'docs/licenses/monaco-editor/core-dom/ATTRIBUTION.md'], 'Missing complete DOM notice set') + assert.deepEqual(record.component.notices, record.notices.map(notice => notice.target), 'Missing DOM attribution or terms') + const group = manifest.groups.find(group => group.name === 'monaco-editor') + assert(group, 'Missing Monaco DOM group') + assert.deepEqual(group.components?.filter(item => item.name === record.component.name), [record.component], 'Wrong Monaco DOM notice binding') + for (const notice of record.notices) { + assert.deepEqual(group.notices.filter(item => item.target === notice.target), [notice], 'Missing Monaco DOM notice') + assert.equal(hash(fs.readFileSync(path.join(root, notice.source))), notice.sha256, 'Changed Monaco DOM terms') + } + const source = fs.readFileSync(path.join(root, record.vscodeSource), 'utf8') + assert.equal((source.match(/Adapted from WinJS/g) || []).length, 5, 'Changed explicit DOM attribution') + const fragments = domOriginFragments(source) + assert.deepEqual(record.fragments, [...fragments].map(([name, content]) => ({ name, sha256: hash(Buffer.from(content)) })), 'Changed DOM origin source fragments') +} diff --git a/scripts/site-vendor/monaco/reproduce-dom-origins.ts b/scripts/site-vendor/monaco/reproduce-dom-origins.ts new file mode 100644 index 000000000..9419ddd7b --- /dev/null +++ b/scripts/site-vendor/monaco/reproduce-dom-origins.ts @@ -0,0 +1,25 @@ +import assert from 'node:assert/strict' +import fs from 'node:fs' +import path from 'node:path' +import process from 'node:process' +import { fileURLToPath } from 'node:url' +import { ArchiveCache } from './archives.ts' +import { domOriginFragments, readDomOrigins, verifyMonacoDomNotices } from './dom-origins.ts' + +const root = fileURLToPath(new URL('../../../', import.meta.url)) +assert(process.argv.slice(2).every(arg => arg === '--fetch'), 'Use reproduce-dom-origins.ts [--fetch]') +assert.equal(process.version, `v${fs.readFileSync(path.join(root, '.node-version'), 'utf8').trim()}`, 'Use canonical Node') +const record = readDomOrigins(root) +const cache = new ArchiveCache(root, path.join(root, 'refactor/.cache/monaco-review')) +await cache.verify(record.archives, record.remotes, process.argv.includes('--fetch')) +verifyMonacoDomNotices(root, JSON.parse(fs.readFileSync(path.join(root, 'scripts/site-vendor/manifest.json'), 'utf8'))) +const map: { sources: string[], sourcesContent: string[] } = JSON.parse(cache.member(record.map).toString('utf8')) +assert.equal(map.sources.filter(source => source === record.map.source).length, 1, 'Missing or repeated DOM source map entry') +const mapped = domOriginFragments(map.sourcesContent[map.sources.indexOf(record.map.source)]!) +const original = domOriginFragments(fs.readFileSync(path.join(root, record.vscodeSource), 'utf8')) +assert.deepEqual(mapped, original, 'Prepared DOM adaptations differ from fixed VS Code source') +assert.deepEqual(fs.readFileSync(path.join(root, record.shipped.target)), cache.member(record.shipped), 'Shipped DOM asset changed') +const winjs = fs.readFileSync(path.join(root, record.winjsSource), 'utf8') +for (const name of ['convertToPixels', 'getDimension', 'getTotalWidth', 'getContentWidth', 'getContentHeight', 'getTotalHeight', 'getPosition']) + assert(winjs.includes(name), 'Missing referenced WinJS helper') +console.log(JSON.stringify({ archives: record.archives.length, gitSources: record.remotes.length, unchangedMappedAdaptations: mapped.size, shippedAssetMatchesArchive: true, originalWinjsVersion: null, referenceVersion: '4.4.5', fullDomCompilation: false })) diff --git a/test/browser/editor-dom.spec.js b/test/browser/editor-dom.spec.js new file mode 100644 index 000000000..d8fb4c0d5 --- /dev/null +++ b/test/browser/editor-dom.spec.js @@ -0,0 +1,45 @@ +import { expect, test } from './fixtures.js' + +test('docs Monaco DOM helpers preserve dimensions and offsets through nested scrolling', async ({ page }, testInfo) => { + await page.goto('/test/player.html?core=candidate&chapter=published') + await page.addScriptTag({ url: '/assets/js/vs/loader.js' }) + const observations = await page.evaluate(async () => { + window.require.config({ paths: { vs: '/assets/js/vs' } }) + const load = ids => new Promise((resolve, reject) => window.require(ids, (...modules) => resolve(modules), reject)) + await load(['vs/editor/editor.main']) + const [dom] = await load(['vs/base/browser/dom']) + const host = document.createElement('div') + host.style.cssText = 'position:relative;width:300px;height:160px;border:5px solid;overflow:scroll;' + const spacer = document.createElement('div') + spacer.style.cssText = 'width:600px;height:500px;' + const child = document.createElement('div') + child.style.cssText = 'box-sizing:content-box;position:absolute;left:70px;top:90px;width:120px;height:50px;padding:3px;border:2px solid;margin:7px;' + host.append(spacer, child) + document.body.append(host) + try { + return [[0, 0], [25, 35], [0, 0]].map(([left, top]) => { + host.scrollLeft = left + host.scrollTop = top + const rect = child.getBoundingClientRect() + return { + scroll: [host.scrollLeft, host.scrollTop], + content: [dom.getContentWidth(child), dom.getContentHeight(child)], + total: [dom.getTotalWidth(child), dom.getTotalHeight(child)], + offset: dom.getTopLeftOffset(child), + native: { left: rect.left + window.scrollX, top: rect.top + window.scrollY }, + } + }) + } + finally { + host.remove() + } + }) + for (const value of observations) { + expect(value.content).toEqual([120, 50]) + expect(value.total).toEqual([144, 74]) + expect(value.offset.left).toBeCloseTo(value.native.left, 1) + expect(value.offset.top).toBeCloseTo(value.native.top, 1) + } + expect(observations.map(value => value.scroll)).toEqual([[0, 0], [25, 35], [0, 0]]) + await testInfo.attach('monaco-dom-origins', { contentType: 'application/json', body: JSON.stringify(observations) }) +}) diff --git a/test/browser/site-vendor.spec.js b/test/browser/site-vendor.spec.js index 4bc3f16ef..d323ff26c 100644 --- a/test/browser/site-vendor.spec.js +++ b/test/browser/site-vendor.spec.js @@ -26,6 +26,7 @@ test('mobile vConsole shows logs and upstream site notice texts are served uncha { path: '/licenses/monaco-editor/language-services/ATTRIBUTION.md', count: 12 }, { path: '/licenses/monaco-editor/core-origins/ATTRIBUTION.md', count: 3 }, { path: '/licenses/monaco-editor/core-path/ATTRIBUTION.md', count: 1 }, + { path: '/licenses/monaco-editor/core-dom/ATTRIBUTION.md', count: 1 }, ]) { const attribution = await request.get(path) expect(attribution.status()).toBe(200) diff --git a/test/site-notices.test.js b/test/site-notices.test.js index b65b1e7c6..0af946d35 100644 --- a/test/site-notices.test.js +++ b/test/site-notices.test.js @@ -9,12 +9,34 @@ import process from 'node:process' import test from 'node:test' import { verifyConsoleNoticeSources } from '../scripts/site-vendor/console/notices.ts' import { verifyMonacoCoreNotices } from '../scripts/site-vendor/monaco/core-origins.ts' +import { domOriginFragments, verifyMonacoDomNotices } from '../scripts/site-vendor/monaco/dom-origins.ts' import { verifyMonacoPathNotices } from '../scripts/site-vendor/monaco/node-path.ts' import { verifyMonacoLanguageNoticeArchives, verifyMonacoLanguageNotices } from '../scripts/site-vendor/monaco/notices.ts' import { generateNotices, writeOrCheckNotices } from '../scripts/site-vendor/notices.ts' const hash = bytes => createHash('sha256').update(bytes).digest('hex') +test('WinJS-derived DOM helpers keep reference terms without claiming an exact original version', () => { + const original = JSON.parse(fs.readFileSync('scripts/site-vendor/manifest.json', 'utf8')) + assert.doesNotThrow(() => verifyMonacoDomNotices(process.cwd(), original)) + const missingAsset = structuredClone(original) + missingAsset.groups.find(group => group.name === 'monaco-editor').components.find(item => item.name.startsWith('WinJS-derived')).assets = [] + assert.throws(() => verifyMonacoDomNotices(process.cwd(), missingAsset), /DOM notice binding/) + const missingTerms = structuredClone(original) + const group = missingTerms.groups.find(group => group.name === 'monaco-editor') + group.notices = group.notices.filter(item => !item.target.endsWith('core-dom/LICENSE.txt')) + assert.throws(() => verifyMonacoDomNotices(process.cwd(), missingTerms), /DOM notice/) +}) + +test('DOM origin declarations reject duplicate or missing blocks and ignore same-named strings', () => { + const source = fs.readFileSync('refactor/baselines/site-vendor/monaco-dom/vscode-dom.txt', 'utf8') + const fragments = domOriginFragments(source) + assert.equal(fragments.size, 6) + assert.deepEqual(domOriginFragments(`${source}\nconst label = 'getTotalWidth';`), fragments) + assert.throws(() => domOriginFragments(`${source}\n${fragments.get('getTotalWidth')}`), /Repeated DOM/) + assert.throws(() => domOriginFragments(source.replace(fragments.get('SizeUtils'), 'const SizeUtils = "same name";')), /Missing or reordered/) +}) + test('Node path attribution covers both editor and worker and keeps the original terms', () => { const original = JSON.parse(fs.readFileSync('scripts/site-vendor/manifest.json', 'utf8')) assert.doesNotThrow(() => verifyMonacoPathNotices(process.cwd(), original))