sourcemonkey 0.0.0-stage → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +87 -2
- package/dist/bytes.js +37 -0
- package/dist/channel-placeholder.js +5 -0
- package/dist/collection-scan.js +17 -0
- package/dist/collections.html +353 -0
- package/dist/compare.html +358 -0
- package/dist/composed-source.js +205 -0
- package/dist/connect-prompt.html +47 -0
- package/dist/debug/icons.html +211 -0
- package/dist/debug/storage.html +163 -0
- package/dist/debug-log.js +75 -0
- package/dist/diagnostic-location.js +64 -0
- package/dist/eval-hook.js +308 -0
- package/dist/extension/background.js +5263 -0
- package/dist/extension/channel.js +133 -0
- package/dist/extension/code-links.js +187 -0
- package/dist/extension/code-tabs.js +460 -0
- package/dist/extension/collection-dialog.js +619 -0
- package/dist/extension/collection-display.js +322 -0
- package/dist/extension/collections.js +2905 -0
- package/dist/extension/compare.js +867 -0
- package/dist/extension/concurrency.js +186 -0
- package/dist/extension/connect-grants.js +109 -0
- package/dist/extension/connect-prompt-page.js +70 -0
- package/dist/extension/connect-prompt.js +266 -0
- package/dist/extension/copy-button.js +63 -0
- package/dist/extension/copy-dialog.js +502 -0
- package/dist/extension/copy-preference.js +66 -0
- package/dist/extension/debug/icons.js +203 -0
- package/dist/extension/debug/storage.js +365 -0
- package/dist/extension/deep-link.js +77 -0
- package/dist/extension/delete-dialog.js +432 -0
- package/dist/extension/delete-icon.js +40 -0
- package/dist/extension/details-tooltips.js +66 -0
- package/dist/extension/directories.js +679 -0
- package/dist/extension/export-backup.js +407 -0
- package/dist/extension/export-dialog.js +142 -0
- package/dist/extension/file-access.js +74 -0
- package/dist/extension/file-changes.js +346 -0
- package/dist/extension/frame-info.js +85 -0
- package/dist/extension/github-provider.js +336 -0
- package/dist/extension/glyph.js +84 -0
- package/dist/extension/gm-bindings.js +601 -0
- package/dist/extension/gm-download.js +419 -0
- package/dist/extension/gm-menu.js +228 -0
- package/dist/extension/gm-notification.js +141 -0
- package/dist/extension/gm-originator-map.js +23 -0
- package/dist/extension/gm-tab-data.js +121 -0
- package/dist/extension/gm-tab.js +160 -0
- package/dist/extension/gm-url-change.js +111 -0
- package/dist/extension/gm-url-scheme.js +27 -0
- package/dist/extension/gm-values.js +176 -0
- package/dist/extension/gm-window-control.js +104 -0
- package/dist/extension/gm-xhr-headers.js +333 -0
- package/dist/extension/gm-xhr.js +584 -0
- package/dist/extension/injector.js +3145 -0
- package/dist/extension/install-capture.js +277 -0
- package/dist/extension/line-diff.js +233 -0
- package/dist/extension/local-copy.js +560 -0
- package/dist/extension/local-delete.js +276 -0
- package/dist/extension/location-kinds.js +108 -0
- package/dist/extension/log-format.js +158 -0
- package/dist/extension/managed-changes.js +361 -0
- package/dist/extension/managed-items.js +57 -0
- package/dist/extension/match-index.js +375 -0
- package/dist/extension/missing-scripts.js +66 -0
- package/dist/extension/more-menu.js +109 -0
- package/dist/extension/move-dialog.js +197 -0
- package/dist/extension/offscreen.js +37 -0
- package/dist/extension/options.js +504 -0
- package/dist/extension/page-heading.js +170 -0
- package/dist/extension/page-links.js +199 -0
- package/dist/extension/parse-check-client.js +70 -0
- package/dist/extension/parse-check.js +161 -0
- package/dist/extension/parse-sandbox-host.js +172 -0
- package/dist/extension/parse-sandbox.js +175 -0
- package/dist/extension/popup-commands-open.js +41 -0
- package/dist/extension/popup-view.js +387 -0
- package/dist/extension/popup.js +703 -0
- package/dist/extension/prism-userscript.js +53 -0
- package/dist/extension/refresh-error.js +136 -0
- package/dist/extension/refresh-targets.js +160 -0
- package/dist/extension/related-versions.js +1144 -0
- package/dist/extension/resize-observer-loop.js +19 -0
- package/dist/extension/row-cache.js +387 -0
- package/dist/extension/script-blobs.js +413 -0
- package/dist/extension/script-details.js +658 -0
- package/dist/extension/script-enablement.js +285 -0
- package/dist/extension/script-identity.js +310 -0
- package/dist/extension/script-keys.js +54 -0
- package/dist/extension/script-log-id.js +155 -0
- package/dist/extension/script-log.js +290 -0
- package/dist/extension/script-rejection.js +104 -0
- package/dist/extension/script-sites.js +158 -0
- package/dist/extension/script-store.js +3507 -0
- package/dist/extension/script-updater.js +991 -0
- package/dist/extension/script-url-hash.js +61 -0
- package/dist/extension/select-all.js +37 -0
- package/dist/extension/select-open-guard.js +90 -0
- package/dist/extension/site-icon.js +1261 -0
- package/dist/extension/sm-dev-link.js +302 -0
- package/dist/extension/solo-click.js +58 -0
- package/dist/extension/sticky-numbers.js +188 -0
- package/dist/extension/storage-breakdown.js +253 -0
- package/dist/extension/storage-scan.js +86 -0
- package/dist/extension/storage-usage.js +194 -0
- package/dist/extension/structural-keys.js +29 -0
- package/dist/extension/sw-teardown.js +36 -0
- package/dist/extension/tab-status.js +403 -0
- package/dist/extension/toolbar-summary.js +105 -0
- package/dist/extension/user-scripts-access.js +43 -0
- package/dist/extension/userscript.js +3672 -0
- package/dist/extension/value-store.js +204 -0
- package/dist/extension/version-probe-fetch.js +68 -0
- package/dist/extension/worker-client.js +109 -0
- package/dist/extension/worker-ops.js +171 -0
- package/dist/extension/zip-writer.js +24 -0
- package/dist/external-files.js +878 -0
- package/dist/file-loader.js +436 -0
- package/dist/file-locations.js +439 -0
- package/dist/generated-wrappers.js +5 -0
- package/dist/github-auth.js +148 -0
- package/dist/github-urls.js +46 -0
- package/dist/gm-api-catalog.js +217 -0
- package/dist/gm-connect.js +273 -0
- package/dist/gm-xhr-types.js +5 -0
- package/dist/http-read.js +142 -0
- package/dist/icons/icon-128.png +0 -0
- package/dist/icons/icon-16.png +0 -0
- package/dist/icons/icon-48.png +0 -0
- package/dist/local-file-overrides.js +558 -0
- package/dist/manifest.json +38 -0
- package/dist/markup-response.js +126 -0
- package/dist/match-targets.js +305 -0
- package/dist/menu-captions.js +22 -0
- package/dist/offscreen.html +39 -0
- package/dist/options.html +197 -0
- package/dist/parse-check-protocol.js +51 -0
- package/dist/parse-location.js +171 -0
- package/dist/parse-sandbox.html +56 -0
- package/dist/phase-timing.js +155 -0
- package/dist/popup.html +197 -0
- package/dist/public-suffixes.js +6957 -0
- package/dist/run-context.js +31 -0
- package/dist/runtime-messages.js +34 -0
- package/dist/sandboxed-page.js +35 -0
- package/dist/script-build.js +787 -0
- package/dist/script-display.js +383 -0
- package/dist/script-icon.js +43 -0
- package/dist/script-links.js +204 -0
- package/dist/script-source-url.js +214 -0
- package/dist/script-world.js +65 -0
- package/dist/sm-dev-protocol.js +84 -0
- package/dist/source-map.js +177 -0
- package/dist/stack-link.js +138 -0
- package/dist/styles.css +825 -0
- package/dist/unsafe-window-use.js +229 -0
- package/dist/url-match.js +734 -0
- package/dist/userscript-header.js +248 -0
- package/dist/userscript.html +1165 -0
- package/dist/vendor/fflate.LICENSE +21 -0
- package/dist/vendor/fflate.js +2692 -0
- package/dist/vendor/prism/prism-line-numbers.css +1 -0
- package/dist/vendor/prism/prism-line-numbers.js +1 -0
- package/dist/vendor/prism/prism.css +1 -0
- package/dist/vendor/prism/prism.js +1946 -0
- package/dist/version-compare.js +141 -0
- package/dist/version-probe.js +120 -0
- package/lib/build-info.json +1 -0
- package/lib/bytes.d.ts +3 -0
- package/lib/bytes.js +37 -0
- package/lib/channel-placeholder.d.ts +1 -0
- package/lib/channel-placeholder.js +5 -0
- package/lib/collection-scan.d.ts +8 -0
- package/lib/collection-scan.js +17 -0
- package/lib/composed-source.d.ts +28 -0
- package/lib/composed-source.js +205 -0
- package/lib/debug-log.d.ts +9 -0
- package/lib/debug-log.js +75 -0
- package/lib/diagnostic-location.d.ts +8 -0
- package/lib/diagnostic-location.js +64 -0
- package/lib/eval-hook.d.ts +34 -0
- package/lib/eval-hook.js +308 -0
- package/lib/external-files.d.ts +111 -0
- package/lib/external-files.js +878 -0
- package/lib/file-loader.d.ts +48 -0
- package/lib/file-loader.js +436 -0
- package/lib/file-locations.d.ts +44 -0
- package/lib/file-locations.js +439 -0
- package/lib/generated-wrappers.d.ts +11 -0
- package/lib/generated-wrappers.js +5 -0
- package/lib/github-auth.d.ts +12 -0
- package/lib/github-auth.js +148 -0
- package/lib/github-urls.d.ts +1 -0
- package/lib/github-urls.js +46 -0
- package/lib/gm-api-catalog.d.ts +24 -0
- package/lib/gm-api-catalog.js +217 -0
- package/lib/gm-connect.d.ts +34 -0
- package/lib/gm-connect.js +273 -0
- package/lib/gm-xhr-types.d.ts +68 -0
- package/lib/gm-xhr-types.js +5 -0
- package/lib/harness/browser-extensions.d.ts +73 -0
- package/lib/harness/browser-extensions.js +285 -0
- package/lib/harness/browser-lang.d.ts +20 -0
- package/lib/harness/browser-lang.js +86 -0
- package/lib/harness/browser-launch.d.ts +14 -0
- package/lib/harness/browser-launch.js +184 -0
- package/lib/harness/checks.d.ts +110 -0
- package/lib/harness/checks.js +321 -0
- package/lib/harness/cli.d.ts +2 -0
- package/lib/harness/cli.js +2259 -0
- package/lib/harness/command-args.d.ts +91 -0
- package/lib/harness/command-args.js +369 -0
- package/lib/harness/command-lines.d.ts +80 -0
- package/lib/harness/command-lines.js +180 -0
- package/lib/harness/command-list.d.ts +206 -0
- package/lib/harness/command-list.js +1475 -0
- package/lib/harness/console-commands.d.ts +463 -0
- package/lib/harness/console-commands.js +3216 -0
- package/lib/harness/download-watch.d.ts +21 -0
- package/lib/harness/download-watch.js +156 -0
- package/lib/harness/extension-backend.d.ts +41 -0
- package/lib/harness/extension-backend.js +100 -0
- package/lib/harness/extension-host.d.ts +112 -0
- package/lib/harness/extension-host.js +552 -0
- package/lib/harness/extension-launch.d.ts +67 -0
- package/lib/harness/extension-launch.js +285 -0
- package/lib/harness/extension-link.d.ts +315 -0
- package/lib/harness/extension-link.js +607 -0
- package/lib/harness/external-manager.d.ts +146 -0
- package/lib/harness/external-manager.js +414 -0
- package/lib/harness/fixture.d.ts +165 -0
- package/lib/harness/fixture.js +461 -0
- package/lib/harness/frame-sessions.d.ts +71 -0
- package/lib/harness/frame-sessions.js +248 -0
- package/lib/harness/frames.d.ts +68 -0
- package/lib/harness/frames.js +216 -0
- package/lib/harness/help-format.d.ts +17 -0
- package/lib/harness/help-format.js +127 -0
- package/lib/harness/host.d.ts +352 -0
- package/lib/harness/host.js +423 -0
- package/lib/harness/index.d.ts +8 -0
- package/lib/harness/index.js +10 -0
- package/lib/harness/input-file.d.ts +18 -0
- package/lib/harness/input-file.js +61 -0
- package/lib/harness/json-output.d.ts +565 -0
- package/lib/harness/json-output.js +71 -0
- package/lib/harness/manager-actions.d.ts +21 -0
- package/lib/harness/manager-actions.js +129 -0
- package/lib/harness/manager-commands.d.ts +142 -0
- package/lib/harness/manager-commands.js +1196 -0
- package/lib/harness/manager-fetch.d.ts +33 -0
- package/lib/harness/manager-fetch.js +239 -0
- package/lib/harness/managers.d.ts +24 -0
- package/lib/harness/managers.js +27 -0
- package/lib/harness/output-style.d.ts +125 -0
- package/lib/harness/output-style.js +322 -0
- package/lib/harness/page-commands.d.ts +134 -0
- package/lib/harness/page-commands.js +1141 -0
- package/lib/harness/page-output.d.ts +67 -0
- package/lib/harness/page-output.js +139 -0
- package/lib/harness/page-watch.d.ts +171 -0
- package/lib/harness/page-watch.js +607 -0
- package/lib/harness/parse-check-node.d.ts +3 -0
- package/lib/harness/parse-check-node.js +132 -0
- package/lib/harness/path-args.d.ts +22 -0
- package/lib/harness/path-args.js +148 -0
- package/lib/harness/playwright-chromium.d.ts +16 -0
- package/lib/harness/playwright-chromium.js +86 -0
- package/lib/harness/prepare.d.ts +168 -0
- package/lib/harness/prepare.js +364 -0
- package/lib/harness/prompt-editor.d.ts +17 -0
- package/lib/harness/prompt-editor.js +354 -0
- package/lib/harness/prompt-history.d.ts +13 -0
- package/lib/harness/prompt-history.js +89 -0
- package/lib/harness/rebuild-advice.d.ts +6 -0
- package/lib/harness/rebuild-advice.js +39 -0
- package/lib/harness/run-log.d.ts +47 -0
- package/lib/harness/run-log.js +140 -0
- package/lib/harness/run-logs.d.ts +132 -0
- package/lib/harness/run-logs.js +241 -0
- package/lib/harness/run.d.ts +194 -0
- package/lib/harness/run.js +1973 -0
- package/lib/harness/runs.d.ts +229 -0
- package/lib/harness/runs.js +726 -0
- package/lib/harness/save-html.d.ts +39 -0
- package/lib/harness/save-html.js +89 -0
- package/lib/harness/saved-pages.d.ts +120 -0
- package/lib/harness/saved-pages.js +275 -0
- package/lib/harness/script-mark.d.ts +17 -0
- package/lib/harness/script-mark.js +56 -0
- package/lib/harness/snapshot.d.ts +143 -0
- package/lib/harness/snapshot.js +474 -0
- package/lib/harness/stuck-tabs.d.ts +19 -0
- package/lib/harness/stuck-tabs.js +131 -0
- package/lib/harness/tab-refs.d.ts +20 -0
- package/lib/harness/tab-refs.js +80 -0
- package/lib/harness/tampermonkey.d.ts +71 -0
- package/lib/harness/tampermonkey.js +356 -0
- package/lib/harness/tm-ids.d.ts +18 -0
- package/lib/harness/tm-ids.js +88 -0
- package/lib/harness/violentmonkey.d.ts +34 -0
- package/lib/harness/violentmonkey.js +162 -0
- package/lib/harness/wait.d.ts +77 -0
- package/lib/harness/wait.js +458 -0
- package/lib/http-read.d.ts +30 -0
- package/lib/http-read.js +142 -0
- package/lib/local-file-overrides.d.ts +35 -0
- package/lib/local-file-overrides.js +558 -0
- package/lib/manifest.json +38 -0
- package/lib/markup-response.d.ts +11 -0
- package/lib/markup-response.js +126 -0
- package/lib/match-targets.d.ts +18 -0
- package/lib/match-targets.js +305 -0
- package/lib/menu-captions.d.ts +1 -0
- package/lib/menu-captions.js +22 -0
- package/lib/parse-check-protocol.d.ts +27 -0
- package/lib/parse-check-protocol.js +51 -0
- package/lib/parse-location.d.ts +12 -0
- package/lib/parse-location.js +171 -0
- package/lib/phase-timing.d.ts +12 -0
- package/lib/phase-timing.js +155 -0
- package/lib/public-suffixes.d.ts +1 -0
- package/lib/public-suffixes.js +6957 -0
- package/lib/run-context.d.ts +2 -0
- package/lib/run-context.js +31 -0
- package/lib/runtime-messages.d.ts +10 -0
- package/lib/runtime-messages.js +34 -0
- package/lib/sandboxed-page.d.ts +5 -0
- package/lib/sandboxed-page.js +35 -0
- package/lib/script-build.d.ts +111 -0
- package/lib/script-build.js +787 -0
- package/lib/script-display.d.ts +51 -0
- package/lib/script-display.js +383 -0
- package/lib/script-icon.d.ts +16 -0
- package/lib/script-icon.js +43 -0
- package/lib/script-links.d.ts +24 -0
- package/lib/script-links.js +204 -0
- package/lib/script-source-url.d.ts +8 -0
- package/lib/script-source-url.js +214 -0
- package/lib/script-world.d.ts +6 -0
- package/lib/script-world.js +65 -0
- package/lib/sm-dev-protocol.d.ts +251 -0
- package/lib/sm-dev-protocol.js +84 -0
- package/lib/source-map.d.ts +32 -0
- package/lib/source-map.js +177 -0
- package/lib/stack-link.d.ts +15 -0
- package/lib/stack-link.js +138 -0
- package/lib/unsafe-window-use.d.ts +1 -0
- package/lib/unsafe-window-use.js +229 -0
- package/lib/url-match.d.ts +40 -0
- package/lib/url-match.js +734 -0
- package/lib/userscript-header.d.ts +33 -0
- package/lib/userscript-header.js +248 -0
- package/lib/version-compare.d.ts +6 -0
- package/lib/version-compare.js +141 -0
- package/lib/version-probe.d.ts +17 -0
- package/lib/version-probe.js +120 -0
- package/package.json +55 -3
- package/skills/SourceMonkey-dev/SKILL.md +868 -0
- package/skills/SourceMonkey-dev/references/cdp.md +293 -0
- package/skills/SourceMonkey-dev/references/commands.md +297 -0
- package/skills/SourceMonkey-dev/references/other-managers.md +63 -0
- package/skills/SourceMonkey-dev/references/specs.md +46 -0
- package/skills/SourceMonkey-friction/SKILL.md +103 -0
- package/skills/SourceMonkey-friction/references/template.md +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jeff Shute
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,88 @@
|
|
|
1
|
-
#
|
|
1
|
+
# SourceMonkey developer tools for userscripts
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Develop, test and debug userscripts in a real browser, running in the
|
|
4
|
+
real [SourceMonkey](https://github.com/jshute96/SourceMonkey) extension,
|
|
5
|
+
using real `GM_*` APIs and other features.
|
|
6
|
+
|
|
7
|
+
Use these tools with coding agents (like Claude Code) to enable fully agentic
|
|
8
|
+
userscript development.
|
|
9
|
+
|
|
10
|
+
This package includes:
|
|
11
|
+
|
|
12
|
+
- **`sm-dev` command-line tool**
|
|
13
|
+
- Run a userscript against a live page and watch what it does.
|
|
14
|
+
- Or run against a saved page snapshot (for example, on pages that require login).
|
|
15
|
+
- Drive and inspect the page, and read userscript state and stored values.
|
|
16
|
+
- Run and manage scripts under Tampermonkey or Violentmonkey too.
|
|
17
|
+
- **A Playwright test fixture**
|
|
18
|
+
- Write tests that load userscripts on a page, and check for expected results.
|
|
19
|
+
- Test against live pages or snapshots.
|
|
20
|
+
- Catch changes on the live page that break your scripts.
|
|
21
|
+
- **Agent skills**
|
|
22
|
+
- Use with coding agents, so they can develop, test and debug
|
|
23
|
+
userscripts using `sm-dev`, against live pages or snapshots.
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
Needs Node 22 or newer.
|
|
28
|
+
|
|
29
|
+
In a repo of userscripts, install it with Playwright, and the Chromium
|
|
30
|
+
build Playwright drives:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
pnpm add -D sourcemonkey @playwright/test
|
|
34
|
+
pnpm exec playwright install chromium
|
|
35
|
+
pnpm sm-dev --help
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Or run `sm-dev` without installing anything:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
npx sm-dev --help
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Commands that launch a browser require Chromium. They'll report the command
|
|
45
|
+
to install the required version, if it's not already installed.
|
|
46
|
+
|
|
47
|
+
## Run a script
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
pnpm sm-dev start path/script.user.js [http://example.com]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
This launches a browser with SourceMonkey loaded, loads the script,
|
|
54
|
+
and opens the given URL (or the script's `@match` target page, by default).
|
|
55
|
+
This streams the page's console, and lets you interact with the
|
|
56
|
+
page and the loaded userscripts.
|
|
57
|
+
|
|
58
|
+
At the prompt:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
> status # Browser info, loaded scripts, and tab status
|
|
62
|
+
> snapshot --visible # What's on screen, with element refs (e12)
|
|
63
|
+
> click e12 # Click one, and wait for the page to settle
|
|
64
|
+
> menu # The script's menu commands
|
|
65
|
+
> values # What the script stored
|
|
66
|
+
> help # See other commands
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Write a test
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
import { test, expect } from 'sourcemonkey/harness';
|
|
73
|
+
|
|
74
|
+
test('adds the button to the toolbar', async ({ page, loadUserscript, gm, reports }) => {
|
|
75
|
+
await loadUserscript('sites/example.com/add-button.user.js');
|
|
76
|
+
await page.goto('https://example.com/items/42');
|
|
77
|
+
await reports.waitForStart();
|
|
78
|
+
await expect(page.locator('#add-button')).toBeVisible();
|
|
79
|
+
expect(await gm.get('lastItem')).toBe('42');
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## More
|
|
84
|
+
|
|
85
|
+
- [The SourceMonkey extension](https://github.com/jshute96/SourceMonkey):
|
|
86
|
+
the default userscript manager these tools use.
|
|
87
|
+
- [Harness guide](https://github.com/jshute96/SourceMonkey/blob/main/docs/harness-guide.md):
|
|
88
|
+
details on setup, browsers, all `sm-dev` commands, and the test fixture.
|
package/dist/bytes.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Small byte / crypto helpers shared across modules so the SHA-256 and
|
|
2
|
+
// binary→base64 logic lives in one place (script content hashes in
|
|
3
|
+
// script-store, @require/@resource byte hashes + transport in
|
|
4
|
+
// external-files, GM_xmlhttpRequest response transport in gm-xhr).
|
|
5
|
+
// SHA-256 → lowercase hex. Accepts a string (UTF-8 encoded first) or
|
|
6
|
+
// bytes. Async because SubtleCrypto has no sync form on the web
|
|
7
|
+
// platform.
|
|
8
|
+
export async function sha256Hex(data) {
|
|
9
|
+
const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;
|
|
10
|
+
const digest = await crypto.subtle.digest('SHA-256', bytes);
|
|
11
|
+
let out = '';
|
|
12
|
+
for (const b of new Uint8Array(digest))
|
|
13
|
+
out += b.toString(16).padStart(2, '0');
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
// base64→binary. The inverse of `bytesToBase64`, used on the receiving
|
|
17
|
+
// end of message hops that can't carry an ArrayBuffer, and to rebuild a
|
|
18
|
+
// stored `@resource` body when a conditional GET answers 304 and the
|
|
19
|
+
// server sends no bytes of its own.
|
|
20
|
+
export function base64ToBytes(base64) {
|
|
21
|
+
const binary = atob(base64);
|
|
22
|
+
const bytes = new Uint8Array(binary.length);
|
|
23
|
+
for (let i = 0; i < binary.length; i++)
|
|
24
|
+
bytes[i] = binary.charCodeAt(i);
|
|
25
|
+
return bytes.buffer;
|
|
26
|
+
}
|
|
27
|
+
// Chunked binary→base64. `String.fromCharCode(...hugeArray)` throws
|
|
28
|
+
// "Maximum call stack size exceeded" past ~125k args in V8, so we walk
|
|
29
|
+
// the buffer in 32 KiB slices and concatenate. Linear and bounded.
|
|
30
|
+
export function bytesToBase64(bytes) {
|
|
31
|
+
let binary = '';
|
|
32
|
+
const CHUNK = 0x8000;
|
|
33
|
+
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
34
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
|
|
35
|
+
}
|
|
36
|
+
return btoa(binary);
|
|
37
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// The stand-in for the channel key in the static wrapper files
|
|
2
|
+
// (src/extension/channel.ts swaps the real key in when it registers
|
|
3
|
+
// them). Its own module so the harness, which loads a wrapper under
|
|
4
|
+
// Node, can call the registry gate with it.
|
|
5
|
+
export const CHANNEL_KEY_PLACEHOLDER = '__SM_KEY__';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Shared scan primitives used by every collection-kind scanner.
|
|
2
|
+
//
|
|
3
|
+
// Lives in its own module because both `directories.ts` (local
|
|
4
|
+
// directory / manifest scanner) and `github-provider.ts` (Contents-API
|
|
5
|
+
// scanner) need them — importing them directly between the two
|
|
6
|
+
// scanner modules would create a runtime ES-module cycle, since
|
|
7
|
+
// `directories.ts` also imports the github dispatcher from
|
|
8
|
+
// `github-provider.ts`.
|
|
9
|
+
// How many subdirectory levels below the root a scanner walks before
|
|
10
|
+
// stopping. Applies to local directory collections AND GitHub directory
|
|
11
|
+
// collections (the cost model is different but the cap keeps both
|
|
12
|
+
// bounded).
|
|
13
|
+
export const MAX_SCAN_DEPTH = 2;
|
|
14
|
+
// The one and only filename SourceMonkey recognises as a userscript
|
|
15
|
+
// manifest. Lives here (not in `directories.ts`) so `github-provider.ts`
|
|
16
|
+
// can import it without forming a runtime cycle with `directories.ts`.
|
|
17
|
+
export const MANIFEST_FILENAME = 'script_manifest.json';
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<title>SourceMonkey | Collections</title>
|
|
6
|
+
<link rel="stylesheet" href="styles.css" />
|
|
7
|
+
<style>
|
|
8
|
+
/* Full-bleed body; the header bar and `.page-body` (styles.css)
|
|
9
|
+
each centre their own contents on the shared `--page-width`
|
|
10
|
+
column. */
|
|
11
|
+
body { font: 14px system-ui, sans-serif; margin: 0; color: #222; --page-width: 720px; }
|
|
12
|
+
/* Grid layout so a long display name that needs to wrap stays
|
|
13
|
+
inside the right-hand column instead of dropping back to the
|
|
14
|
+
row's left edge. Column 1 sizes to the bubble; column 2 takes
|
|
15
|
+
the remaining space and is where the name wraps. */
|
|
16
|
+
h2 {
|
|
17
|
+
font-size: 1em;
|
|
18
|
+
margin: 0;
|
|
19
|
+
word-break: break-all;
|
|
20
|
+
display: grid;
|
|
21
|
+
grid-template-columns: max-content 1fr;
|
|
22
|
+
column-gap: 0.5em;
|
|
23
|
+
align-items: baseline;
|
|
24
|
+
}
|
|
25
|
+
/* `.collection-type-bubble` + colored `.bubble-*` variants +
|
|
26
|
+
`.collection-display-name` typography are in styles.css (the
|
|
27
|
+
cross-page shared stylesheet). */
|
|
28
|
+
/* Height, surface, hover and press are shared across the two
|
|
29
|
+
pages (styles.css); this is just this page's roomier
|
|
30
|
+
horizontal padding on text buttons. */
|
|
31
|
+
button { font: inherit; padding: 0 11px; cursor: pointer; }
|
|
32
|
+
input[type="text"] { font: inherit; padding: 4px 7px; }
|
|
33
|
+
.placeholder { color: #666; }
|
|
34
|
+
.add-form { display: flex; gap: 0.5em; margin-bottom: 1em; align-items: center; }
|
|
35
|
+
.add-form input[type="text"] { flex: 1 1 auto; }
|
|
36
|
+
.collection { border: 1px solid #ddd; border-radius: 6px; padding: 11px 14px; margin-bottom: 11px; }
|
|
37
|
+
.collection-header { display: flex; justify-content: flex-start; align-items: center; gap: 0.6em; margin-bottom: 7px; }
|
|
38
|
+
.collection-header h2 { flex: 1 1 auto; min-width: 0; }
|
|
39
|
+
.collection-toggle { flex: 0 0 auto; }
|
|
40
|
+
.collection-buttons { display: flex; gap: 0.4em; flex: 0 0 auto; margin-left: auto; align-items: center; }
|
|
41
|
+
/* The ⋯ menus (src/extension/more-menu.ts): square, like the
|
|
42
|
+
glyph buttons beside them. */
|
|
43
|
+
button.more-menu { width: var(--icon-btn-size); padding: 0; font-size: 16px; }
|
|
44
|
+
button.more-menu[aria-expanded="true"] { background: var(--btn-bg-hover); }
|
|
45
|
+
/* Up/Down arrow buttons. They wear `.icon-btn` like the rest of
|
|
46
|
+
the header row, so the box and the disabled state come from
|
|
47
|
+
styles.css; the class is what the reorder code and the tests
|
|
48
|
+
address them by. */
|
|
49
|
+
/* Whole-px vertical metrics on this page, and `separate` borders rather
|
|
50
|
+
than `collapse` (a collapsed border is split half into each adjacent
|
|
51
|
+
cell, landing rows on half pixels) — see docs/architecture.md,
|
|
52
|
+
"Extension-page styling". */
|
|
53
|
+
/* A can inside a script row is a row control, not a control in a
|
|
54
|
+
button row: at the shared 26px it makes its row 7px taller than
|
|
55
|
+
the rows around it, and only SOME rows have one (a `missing`
|
|
56
|
+
row, a local copy), so the table comes out ragged. Shrinking
|
|
57
|
+
the pair here puts it back inside the row's own line box —
|
|
58
|
+
this is the escape hatch styles.css describes. */
|
|
59
|
+
.script-table { --icon-btn-size: 18px; --icon-btn-glyph: 14px; }
|
|
60
|
+
.script-table { width: 100%; border-collapse: separate; border-spacing: 0; }
|
|
61
|
+
.script-table th, .script-table td { text-align: left; padding: 4px 8px; border-bottom: 1px solid #eee; vertical-align: top; }
|
|
62
|
+
.script-table th { font-weight: 600; color: #555; font-size: 0.9em; line-height: 16px; }
|
|
63
|
+
.script-table tbody tr:last-child td { border-bottom-color: transparent; }
|
|
64
|
+
.script-table td.size-cell, .script-table td.status-cell, .script-table td.toggle-cell, .script-table td.action-cell, .script-table td.scheme-cell { white-space: nowrap; width: 1%; }
|
|
65
|
+
/* Container-collection action column: the per-row remove button.
|
|
66
|
+
Right-aligned so the trash icon hugs the table edge regardless
|
|
67
|
+
of how narrow / wide the name column wants to be. */
|
|
68
|
+
.script-table td.action-cell { text-align: right; padding-left: 3px; }
|
|
69
|
+
.script-table th:last-child { width: 1%; }
|
|
70
|
+
.script-table td.toggle-cell { padding-right: 3px; }
|
|
71
|
+
/* When a collection is off, its whole section dims; when a script is off, just the row dims.
|
|
72
|
+
The toggle itself stays at full opacity so users can flip it back. */
|
|
73
|
+
.collection.disabled .collection-header h2,
|
|
74
|
+
.script-table tr.disabled td:not(.toggle-cell) { opacity: 0.45; }
|
|
75
|
+
.toggle { display: inline-flex; align-items: center; cursor: pointer; position: relative; }
|
|
76
|
+
.toggle input[type="checkbox"] { cursor: pointer; margin: 0; }
|
|
77
|
+
.toggle-disabled { cursor: not-allowed; opacity: 0.5; }
|
|
78
|
+
.toggle-disabled input[type="checkbox"] { cursor: not-allowed; }
|
|
79
|
+
/* Bulk-toggle button in the script-table header. Sized like the
|
|
80
|
+
per-row checkbox so the column lines up. */
|
|
81
|
+
/* vertical-align keeps the button's place in the header line box
|
|
82
|
+
independent of its text: baseline-aligned, an empty inline-flex
|
|
83
|
+
button sits a fraction lower and resizes the header row, which
|
|
84
|
+
shifts every collection below. */
|
|
85
|
+
.bulk-toggle { vertical-align: middle; width: 14px; height: 14px; padding: 0; font: inherit; font-weight: 700; line-height: 1; border: 1px solid #888; border-radius: 2px; background: #fff; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
|
|
86
|
+
.bulk-toggle:hover:not(:disabled) { background: #f0f0f0; }
|
|
87
|
+
.bulk-toggle:disabled { cursor: not-allowed; opacity: 0.5; }
|
|
88
|
+
.script-table th.toggle-cell { white-space: nowrap; width: 1%; padding-right: 3px; }
|
|
89
|
+
/* Column of site favicons to the left of the name link. One
|
|
90
|
+
16px icon per distinct site the script targets (see
|
|
91
|
+
`MAX_SITE_ICONS`), side by side with a 2px gap. Each icon is
|
|
92
|
+
a clickable <a class="site-icon-inner"> when its @match yields
|
|
93
|
+
a usable origin; a script with no site holds one inert
|
|
94
|
+
<span class="site-icon-inner">. Every inner starts as a globe
|
|
95
|
+
placeholder that is swapped for the real favicon on load.
|
|
96
|
+
The slot is as wide as this table's widest row needs
|
|
97
|
+
(`--icon-cols`, set per table by collections.ts), so the
|
|
98
|
+
names in one collection share a straight left edge. */
|
|
99
|
+
.script-table { --icon-cols: 1; --icon-gap: 2px; }
|
|
100
|
+
.site-icon {
|
|
101
|
+
display: inline-flex;
|
|
102
|
+
gap: var(--icon-gap);
|
|
103
|
+
width: calc(var(--icon-cols) * 16px + (var(--icon-cols) - 1) * var(--icon-gap));
|
|
104
|
+
height: 16px;
|
|
105
|
+
margin-right: 0.4em;
|
|
106
|
+
vertical-align: text-bottom;
|
|
107
|
+
flex: 0 0 auto;
|
|
108
|
+
/* text-indent inherits, and this is a block container: reset it
|
|
109
|
+
so the name cell's negative hanging indent can't shift the
|
|
110
|
+
icon if a future inner is ever inline rather than
|
|
111
|
+
display:block. */
|
|
112
|
+
text-indent: 0;
|
|
113
|
+
}
|
|
114
|
+
/* The icons inside the slot (`.site-icon-inner`, the globe, the
|
|
115
|
+
<img>) are styled once for every page in styles.css. */
|
|
116
|
+
/* Script names come from the file/URL and can be arbitrarily long
|
|
117
|
+
(web-installed scripts often carry a whole marketing title).
|
|
118
|
+
Let them wrap rather than force the table wider than its
|
|
119
|
+
`.collection` card, which pushed Size / Status outside the box.
|
|
120
|
+
`<wbr>` markers after each `/` (appendWithSlashBreaks) give
|
|
121
|
+
preferred break points before a mid-word break is needed.
|
|
122
|
+
The hanging indent keeps continuation lines aligned with the
|
|
123
|
+
first line's text instead of tucking under the favicon. */
|
|
124
|
+
.script-table td.name-cell {
|
|
125
|
+
overflow-wrap: anywhere;
|
|
126
|
+
word-break: normal;
|
|
127
|
+
/* `--icon-w` is the slot's width incl. its right margin; the
|
|
128
|
+
hanging indent must track the icon column so wrapped lines
|
|
129
|
+
still align under the first line's text. */
|
|
130
|
+
--icon-w: calc(var(--icon-cols) * 16px + (var(--icon-cols) - 1) * var(--icon-gap) + 0.4em);
|
|
131
|
+
padding-left: calc(8px + var(--icon-w));
|
|
132
|
+
text-indent: calc(-1 * var(--icon-w));
|
|
133
|
+
}
|
|
134
|
+
.status-ok { color: #166534; }
|
|
135
|
+
.status-invalid, .status-rejected, .status-error { color: #b00; }
|
|
136
|
+
.status-warning, .status-outdated { color: #b67200; }
|
|
137
|
+
.status-refresh-failed { color: #c2410c; }
|
|
138
|
+
/* The Status cell content is a link to that script's Log tab.
|
|
139
|
+
Keep the link looking like status text (not blue underlined). */
|
|
140
|
+
.status-cell a { text-decoration: none; color: inherit; cursor: pointer; }
|
|
141
|
+
.status-cell a:hover { text-decoration: underline; }
|
|
142
|
+
.empty { color: #666; font-style: italic; }
|
|
143
|
+
.error { color: #b00; }
|
|
144
|
+
/* A collection's failure line: a hint can start a line of its own,
|
|
145
|
+
and the address it couldn't read is a link. */
|
|
146
|
+
p.error[data-message-kind] { white-space: pre-line; }
|
|
147
|
+
p.error[data-message-kind] a { color: inherit; }
|
|
148
|
+
/* The banner box itself is in styles.css (shared with the
|
|
149
|
+
viewer). These are the collections-page-only parts: a roomier
|
|
150
|
+
gap before the collection list, and the raw-API-error line in the
|
|
151
|
+
"Allow User Scripts" banner. */
|
|
152
|
+
.banner { margin-bottom: 1em; }
|
|
153
|
+
.banner.banner-error .banner-detail { color: #b71c1c; }
|
|
154
|
+
.banner .banner-detail { color: #92400e; font-size: 0.85em; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; margin-top: 0.5em; }
|
|
155
|
+
/* Inline busy spinner for individual controls (toggles, add form).
|
|
156
|
+
`@keyframes sm-spin` is in styles.css, shared with the dialog
|
|
157
|
+
spinner and the glyph buttons' spin state. */
|
|
158
|
+
.busy-spinner { display: inline-block; width: 12px; height: 12px; margin-left: 6px; border: 2px solid #ccc; border-top-color: #555; border-radius: 50%; animation: sm-spin 0.7s linear infinite; vertical-align: middle; box-sizing: border-box; }
|
|
159
|
+
/* Bulk-toggle button shows its spinner in place of the +/- glyph. */
|
|
160
|
+
.bulk-toggle.busy { position: relative; color: transparent; }
|
|
161
|
+
.bulk-toggle.busy::after { content: ''; position: absolute; left: 50%; top: 50%; margin: -5px 0 0 -5px; width: 10px; height: 10px; border: 2px solid #ccc; border-top-color: #555; border-radius: 50%; animation: sm-spin 0.7s linear infinite; box-sizing: border-box; }
|
|
162
|
+
/* A toggle's spinner is overlaid on its own checkbox rather than
|
|
163
|
+
appended beside it. The script table's toggle cell sizes to its
|
|
164
|
+
content, so an in-flow spinner widened that column and shifted
|
|
165
|
+
every row in the collection a few pixels right (and back) for as
|
|
166
|
+
long as the write was in flight. */
|
|
167
|
+
.toggle .busy-spinner { position: absolute; inset: 0; width: auto; height: auto; margin: 0; }
|
|
168
|
+
.toggle:has(.busy-spinner) input[type="checkbox"] { opacity: 0.3; }
|
|
169
|
+
/* While a collection is being removed, dim the whole section and block further clicks. */
|
|
170
|
+
.collection.removing { opacity: 0.5; pointer-events: none; }
|
|
171
|
+
/* Highlight rows that changed during a refresh. The color
|
|
172
|
+
persists until the next refresh clears it, so the
|
|
173
|
+
user can leave the page and come back without losing the
|
|
174
|
+
what-changed signal.
|
|
175
|
+
|
|
176
|
+
Two independent signals: `row-added` / `row-updated` say what
|
|
177
|
+
happened, `row-failed` says how it came out. `row-failed` is
|
|
178
|
+
listed after both so it wins the wash — a script that arrived
|
|
179
|
+
broken is red, and keeps its "New" chip to say it is also new.
|
|
180
|
+
(`row-removed` sits last and never shares a row with any of
|
|
181
|
+
them.) */
|
|
182
|
+
.script-table tr.row-added td { background: #cdebcf; }
|
|
183
|
+
.script-table tr.row-updated td { background: #d7e7f7; }
|
|
184
|
+
.script-table tr.row-failed td { background: #f5c2c7; }
|
|
185
|
+
.script-table tr.row-removed td { background: #f0f0ef; }
|
|
186
|
+
/* The accent bar rides on the row's first cell as an inset
|
|
187
|
+
shadow, so it costs no column width and can't shift the table. */
|
|
188
|
+
.script-table tr.row-added td:first-child { box-shadow: inset 3px 0 0 #166534; }
|
|
189
|
+
.script-table tr.row-updated td:first-child { box-shadow: inset 3px 0 0 #2b6cb0; }
|
|
190
|
+
.script-table tr.row-failed td:first-child { box-shadow: inset 3px 0 0 #b00; }
|
|
191
|
+
.script-table tr.row-removed td:first-child { box-shadow: inset 3px 0 0 #9ca3af; }
|
|
192
|
+
/* What a refresh did to the row, said in words as well as colour.
|
|
193
|
+
New / Updated are pseudo-elements rather than real nodes: their
|
|
194
|
+
Status cell is rebuilt from stored state on every repaint, which
|
|
195
|
+
would discard a chip element, while the class lives on the `<tr>`
|
|
196
|
+
the repaint preserves. A tombstone's `Removed` chip IS a real
|
|
197
|
+
element (`.change-chip`) — nothing repaints that row, and there
|
|
198
|
+
the chip is the whole status, so it has to be selectable and
|
|
199
|
+
readable by a screen reader. One rule for the three, so they
|
|
200
|
+
can't drift apart. */
|
|
201
|
+
.script-table tr.row-added td.status-cell::after,
|
|
202
|
+
.script-table tr.row-updated td.status-cell::after,
|
|
203
|
+
.script-table .change-chip {
|
|
204
|
+
display: inline-block;
|
|
205
|
+
margin-left: 6px;
|
|
206
|
+
padding: 0 6px;
|
|
207
|
+
border-radius: 8px;
|
|
208
|
+
font-size: 10px;
|
|
209
|
+
font-weight: 700;
|
|
210
|
+
text-transform: uppercase;
|
|
211
|
+
letter-spacing: 0.03em;
|
|
212
|
+
color: #fff;
|
|
213
|
+
vertical-align: 1px;
|
|
214
|
+
}
|
|
215
|
+
.script-table tr.row-added td.status-cell::after { content: 'New'; background: #166534; }
|
|
216
|
+
.script-table tr.row-updated td.status-cell::after { content: 'Updated'; background: #2b6cb0; }
|
|
217
|
+
/* A dropped row has no status of its own, so its chip stands
|
|
218
|
+
alone in the cell rather than beside a status word. */
|
|
219
|
+
.script-table .chip-removed { background: #9ca3af; margin-left: 0; }
|
|
220
|
+
/* Tombstone: the ghost of a script this refresh dropped. Struck
|
|
221
|
+
through and greyed, with nothing on it to click — the checkbox
|
|
222
|
+
is disabled and the favicon is de-linked in `renderTombstoneRow`.
|
|
223
|
+
Lives in the DOM only: the next refresh clears it and a reload
|
|
224
|
+
never rebuilds it. */
|
|
225
|
+
.script-table tr.row-removed td { color: #6b7280; }
|
|
226
|
+
/* The strike is drawn on the name and size themselves, not on the
|
|
227
|
+
cells: a decoration inherited by a cell is painted straight
|
|
228
|
+
across the favicon (an atomic inline the line can't skip), and
|
|
229
|
+
the chip and checkbox have nothing to strike through. */
|
|
230
|
+
.script-table tr.row-removed .tombstone-name,
|
|
231
|
+
.script-table tr.row-removed td.size-cell { text-decoration: line-through; }
|
|
232
|
+
/* Sizes line up on their units. */
|
|
233
|
+
.script-table .size-cell { text-align: right; font-variant-numeric: tabular-nums; }
|
|
234
|
+
/* The favicon stays — it's what the eye finds the row by — but
|
|
235
|
+
muted, so a dead row never draws attention ahead of a live one. */
|
|
236
|
+
.script-table tr.row-removed .site-icon { filter: grayscale(1); opacity: 0.55; }
|
|
237
|
+
.script-table tr.row-removed td.toggle-cell input { opacity: 0.5; }
|
|
238
|
+
/* The live rows' toggle box without the `.toggle` class the bulk
|
|
239
|
+
census counts — see `renderTombstoneRow`. Same box AND the same
|
|
240
|
+
zeroed checkbox margin: the UA's default margin on an
|
|
241
|
+
`<input type="checkbox">` is what `.toggle` above cancels, and
|
|
242
|
+
without cancelling it here too the ghost's box sits a few pixels
|
|
243
|
+
down and right of every other row's. */
|
|
244
|
+
.toggle-ghost { display: inline-flex; align-items: center; }
|
|
245
|
+
.toggle-ghost input[type="checkbox"] { margin: 0; }
|
|
246
|
+
.script-table tr.row-removed .scheme-chip { opacity: 0.55; }
|
|
247
|
+
</style>
|
|
248
|
+
</head>
|
|
249
|
+
<body>
|
|
250
|
+
<!-- Shared glyph sprite: the one copy of every inline SVG glyph in the
|
|
251
|
+
extension. scripts/build.mjs inlines it into each page wherever the
|
|
252
|
+
page writes an `#include glyph-sprite` marker comment. (Spelling
|
|
253
|
+
that marker out here would be nice, but its own closing `--` plus
|
|
254
|
+
`>` would end THIS comment and spill the rest onto the page.)
|
|
255
|
+
|
|
256
|
+
One source of truth: the markup used to be copy-pasted into each
|
|
257
|
+
page's HTML, which is how two pages end up with glyphs that have
|
|
258
|
+
quietly drifted apart.
|
|
259
|
+
|
|
260
|
+
Each symbol is defined once per page and referenced by a `use`
|
|
261
|
+
element, so a hundred rows share one copy of the path data instead
|
|
262
|
+
of inlining it per row.
|
|
263
|
+
|
|
264
|
+
#sm-globe favicon placeholder until a site icon loads, and
|
|
265
|
+
the permanent icon for a script with no resolvable
|
|
266
|
+
origin (src/extension/site-icon.ts; styling on
|
|
267
|
+
`.site-icon-globe`).
|
|
268
|
+
#sm-trash remove SourceMonkey's record of a script.
|
|
269
|
+
#sm-trash-file delete the script FILE from disk — the same can,
|
|
270
|
+
badged with a disk. Both painted by
|
|
271
|
+
src/extension/delete-icon.ts, which explains the pair.
|
|
272
|
+
The can is drawn ~19% smaller than #sm-trash — its
|
|
273
|
+
own inner scale(.9) inside the normalizing
|
|
274
|
+
wrapper's scale(.9) — so the badge has a corner to
|
|
275
|
+
sit in without swallowing the can. Deliberate: the two appear in the same
|
|
276
|
+
column in the "Other versions" panel, and the
|
|
277
|
+
badged one has to stay a can at 15px.
|
|
278
|
+
#sm-copy the viewer's "copy this to the clipboard" button,
|
|
279
|
+
#sm-check and the checkmark it flashes on success
|
|
280
|
+
(src/extension/copy-button.ts).
|
|
281
|
+
#sm-refresh refetch a collection, a script, or one row of the
|
|
282
|
+
"Other versions" table. Its busy state is this
|
|
283
|
+
same arc spinning (`.btn-glyph.spinning`), so the
|
|
284
|
+
button never changes shape mid-refresh.
|
|
285
|
+
#sm-gear open a collection's rename / options dialog.
|
|
286
|
+
#sm-open open a location in a new tab (the collection
|
|
287
|
+
dialog's button beside its location box).
|
|
288
|
+
#sm-swap the compare page's "swap the two sides" button:
|
|
289
|
+
two arrows, one each way, the same width so their
|
|
290
|
+
ends line up.
|
|
291
|
+
|
|
292
|
+
Colour comes from `currentColor`, so a button's own `color` (and
|
|
293
|
+
its hover) drives the glyph.
|
|
294
|
+
|
|
295
|
+
OPTICAL SIZING — read before editing a path or a stroke width.
|
|
296
|
+
Identical 16px boxes do not make icons look the same size; the ink
|
|
297
|
+
inside them has to match too. As drawn, these ranged from 18 to
|
|
298
|
+
23.3 units of 24, and the gear read ~22% larger than the arrow. So
|
|
299
|
+
a glyph that needed resizing is wrapped in
|
|
300
|
+
<g transform="translate(12 12) scale(k) translate(-12 -12)">
|
|
301
|
+
and its `stroke-width` is DIVIDED by the same k. Consequences:
|
|
302
|
+
- The number in the file is not the number that renders. Every
|
|
303
|
+
glyph here strokes at 1.75 units once its wrapper is applied
|
|
304
|
+
(1.9/... , 1.95/.9, 1.667*1.05, 1.825*.959). Change a stroke
|
|
305
|
+
width and you break that unless you change k with it.
|
|
306
|
+
- #sm-refresh translates by -13, not -12: Feather's rotate-cw is
|
|
307
|
+
drawn a unit right of centre, and this puts it back. It is not
|
|
308
|
+
a typo.
|
|
309
|
+
- #sm-copy and #sm-check are deliberately outside this: they
|
|
310
|
+
stroke at 2.0 in the 14px copy button. That button sits beside
|
|
311
|
+
the 1.75 set only in the collection dialog, next to #sm-open,
|
|
312
|
+
where the smaller box evens out the heavier stroke. -->
|
|
313
|
+
<svg width="0" height="0" style="position:absolute" aria-hidden="true">
|
|
314
|
+
<symbol id="sm-globe" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"></circle><path d="M2 12h20"></path><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></symbol>
|
|
315
|
+
<symbol id="sm-trash" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 6h17"></path><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"></path><path d="M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2"></path><path d="M10 10.5v7"></path><path d="M14 10.5v7"></path></symbol>
|
|
316
|
+
<symbol id="sm-trash-file" viewBox="0 0 24 24"><g transform="translate(12 12) scale(.9) translate(-12 -12)"><mask id="sm-trash-file-cut" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24"><rect width="24" height="24" fill="#fff"></rect><circle cx="19.6" cy="19.6" r="5.2" fill="#000"></circle></mask><g mask="url(#sm-trash-file-cut)" transform="translate(-.7 -1.5) scale(.9)" fill="none" stroke="currentColor" stroke-width="2.167" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 6h17"></path><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"></path><path d="M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2"></path><path d="M10 10.5v7"></path><path d="M14 10.5v7"></path></g><g transform="translate(14.53 14.36) scale(.422)" fill="none" stroke="currentColor" stroke-width="4.611" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"></ellipse><path d="M3 5v14c0 1.66 4.03 3 9 3s9-1.34 9-3V5"></path></g></g></symbol>
|
|
317
|
+
<symbol id="sm-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></symbol>
|
|
318
|
+
<symbol id="sm-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></symbol>
|
|
319
|
+
<symbol id="sm-refresh" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.667" stroke-linecap="round" stroke-linejoin="round"><g transform="translate(12 12) scale(1.05) translate(-13 -12)"><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path><polyline points="23 4 23 10 17 10"></polyline></g></symbol>
|
|
320
|
+
<symbol id="sm-swap" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7.5h18"></path><path d="M16.5 3l4.5 4.5-4.5 4.5"></path><path d="M21 16.5H3"></path><path d="M7.5 12L3 16.5 7.5 21"></path></symbol>
|
|
321
|
+
<symbol id="sm-gear" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.825" stroke-linecap="round" stroke-linejoin="round"><g transform="translate(12 12) scale(.959) translate(-12 -12)"><circle cx="12" cy="12" r="3.1"></circle><path d="M19.4 14.6a1.6 1.6 0 0 0 .32 1.77l.06.06a1.95 1.95 0 1 1-2.76 2.76l-.06-.06a1.6 1.6 0 0 0-1.77-.32 1.6 1.6 0 0 0-.97 1.47V21a1.95 1.95 0 1 1-3.9 0v-.1a1.6 1.6 0 0 0-1.05-1.47 1.6 1.6 0 0 0-1.77.32l-.06.06a1.95 1.95 0 1 1-2.76-2.76l.06-.06a1.6 1.6 0 0 0 .32-1.77 1.6 1.6 0 0 0-1.47-.97H3a1.95 1.95 0 1 1 0-3.9h.1a1.6 1.6 0 0 0 1.47-1.05 1.6 1.6 0 0 0-.32-1.77l-.06-.06a1.95 1.95 0 1 1 2.76-2.76l.06.06a1.6 1.6 0 0 0 1.77.32H9a1.6 1.6 0 0 0 .97-1.47V3a1.95 1.95 0 1 1 3.9 0v.1a1.6 1.6 0 0 0 .97 1.47 1.6 1.6 0 0 0 1.77-.32l.06-.06a1.95 1.95 0 1 1 2.76 2.76l-.06.06a1.6 1.6 0 0 0-.32 1.77V9a1.6 1.6 0 0 0 1.47.97H21a1.95 1.95 0 1 1 0 3.9h-.1a1.6 1.6 0 0 0-1.47.97z"></path></g></symbol>
|
|
322
|
+
<symbol id="sm-open" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><path d="M10 14L21 3"></path></symbol>
|
|
323
|
+
</svg>
|
|
324
|
+
<header class="page-header">
|
|
325
|
+
<div class="page-header-inner">
|
|
326
|
+
<img class="page-icon" src="icons/icon-48.png" alt="" />
|
|
327
|
+
<h1><span class="brand">SourceMonkey |</span> Collections</h1>
|
|
328
|
+
<div class="page-header-actions">
|
|
329
|
+
<button id="open-options" type="button" title="Open the options page">Options</button>
|
|
330
|
+
<!-- The label ships in the markup so the button is never blank:
|
|
331
|
+
collections.js is a deferred module, and `setGlyphButton`
|
|
332
|
+
(src/extension/collections.ts) replaces this text with the same word
|
|
333
|
+
beside a glyph once it runs. -->
|
|
334
|
+
<button id="refresh-all" type="button">Refresh All</button>
|
|
335
|
+
</div>
|
|
336
|
+
</div>
|
|
337
|
+
</header>
|
|
338
|
+
|
|
339
|
+
<div class="page-body">
|
|
340
|
+
<div id="banner-slot"></div>
|
|
341
|
+
|
|
342
|
+
<form id="add-form" class="add-form">
|
|
343
|
+
<input id="add-path" type="text" placeholder="A .user.js file, a directory, a script_manifest.json, or a name for a new collection" autocomplete="off" spellcheck="false" />
|
|
344
|
+
<button type="submit">Add</button>
|
|
345
|
+
</form>
|
|
346
|
+
<p id="add-error" class="error" hidden></p>
|
|
347
|
+
|
|
348
|
+
<div id="collections"></div>
|
|
349
|
+
</div>
|
|
350
|
+
|
|
351
|
+
<script src="extension/collections.js" type="module"></script>
|
|
352
|
+
</body>
|
|
353
|
+
</html>
|