eyeling 1.24.16 → 1.24.18
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/HANDBOOK.md +2 -0
- package/package.json +1 -1
- package/test/playground.test.js +51 -5
package/HANDBOOK.md
CHANGED
|
@@ -3760,6 +3760,8 @@ When a user does want a portable link, the **Copy share link** button creates on
|
|
|
3760
3760
|
- edited programs are shared with a compact compressed `?state=...` payload,
|
|
3761
3761
|
- default option values are omitted from that payload to keep links small.
|
|
3762
3762
|
|
|
3763
|
+
If a generated compact share link is still very long, the playground reveals an **Open shortener** option. The threshold is intentionally conservative, and the shortener handoff is explicit rather than automatic: the browser opens a TinyURL creation page with the generated share URL only after the user chooses that option. This avoids silently sending encoded editor content to a third-party service.
|
|
3764
|
+
|
|
3763
3765
|
This keeps everyday use pleasant while preserving the important tutorial and issue-reporting workflow: a link can still capture the imported resource, the local editable overlay, background-knowledge mode, proof-comments mode, and HTTPS-dereferencing mode.
|
|
3764
3766
|
|
|
3765
3767
|
For compatibility, older `?edit=`, `?program=`, `?url=`, compact `?state=`, and hash-based links are still accepted when opened. The old `/demo` entry point is also kept as a redirect to the canonical `/playground` page.
|
package/package.json
CHANGED
package/test/playground.test.js
CHANGED
|
@@ -722,6 +722,7 @@ async function main() {
|
|
|
722
722
|
renderedTabSelected: renderedTab ? renderedTab.getAttribute('aria-selected') === 'true' : false,
|
|
723
723
|
sourceTabSelected: sourceTab ? sourceTab.getAttribute('aria-selected') === 'true' : false,
|
|
724
724
|
shareStatus: document.getElementById('share-status') ? String(document.getElementById('share-status').textContent || '') : '',
|
|
725
|
+
shortenerHidden: document.getElementById('open-shortener-btn') ? !!document.getElementById('open-shortener-btn').hidden : true,
|
|
725
726
|
backgroundStatus: document.getElementById('background-status') ? String(document.getElementById('background-status').textContent || '') : '',
|
|
726
727
|
href: String(window.location.href || ''),
|
|
727
728
|
highlighted,
|
|
@@ -776,6 +777,19 @@ async function main() {
|
|
|
776
777
|
return await evalInPage(`window.__eyelingPlaygroundMakeShareUrl()`);
|
|
777
778
|
}
|
|
778
779
|
|
|
780
|
+
async function makeShareUrlDiagnosticsInPage() {
|
|
781
|
+
return await evalInPage(`(async () => {
|
|
782
|
+
const url = await window.__eyelingPlaygroundMakeShareUrl();
|
|
783
|
+
return {
|
|
784
|
+
url,
|
|
785
|
+
length: url.length,
|
|
786
|
+
threshold: window.__eyelingPlaygroundShareUrlShortenerThreshold,
|
|
787
|
+
needsShortener: window.__eyelingPlaygroundShouldOfferShortener(url),
|
|
788
|
+
shortenerUrl: window.__eyelingPlaygroundMakeShareUrlShortenerUrl(url),
|
|
789
|
+
};
|
|
790
|
+
})()`);
|
|
791
|
+
}
|
|
792
|
+
|
|
779
793
|
async function loadUrlIntoEditor(url) {
|
|
780
794
|
const payload = JSON.stringify(String(url));
|
|
781
795
|
await evalInPage(`(() => {
|
|
@@ -922,9 +936,25 @@ ${JSON.stringify(last, null, 2)}`);
|
|
|
922
936
|
assert.match(compactShareUrl, /[?&]state=/, 'Expected an on-demand compact state parameter');
|
|
923
937
|
assert.doesNotMatch(compactShareUrl, /[?&](?:edit|program)=/, 'Expected share link to avoid raw edit/program params');
|
|
924
938
|
assert.ok(compactShareUrl.length < playgroundUrl.length + encodeURIComponent(outputStringProgram).length, 'Expected compact share URL to be shorter than raw editor URL');
|
|
939
|
+
assert.equal(renderedAgain.shortenerHidden, true, 'Expected ordinary compact share links to keep the shortener option hidden');
|
|
925
940
|
endTest();
|
|
926
941
|
|
|
927
|
-
// 6)
|
|
942
|
+
// 6) Very large edited programs should offer a URL shortener handoff instead of only a huge link.
|
|
943
|
+
beginTest('playground offers a URL shortener option for oversized share links');
|
|
944
|
+
const longShareProgram = Array.from({ length: 1400 }, (_, i) => {
|
|
945
|
+
const n = String(i).padStart(4, '0');
|
|
946
|
+
const token = ((i * 2654435761) >>> 0).toString(36).padStart(7, '0');
|
|
947
|
+
return `:s${n}_${token} :p${token}_${n} "literal-${n}-${token}-${i * 9973}" .`;
|
|
948
|
+
}).join('\n');
|
|
949
|
+
await setProgram(longShareProgram);
|
|
950
|
+
const longShare = await makeShareUrlDiagnosticsInPage();
|
|
951
|
+
assert.ok(longShare.length > longShare.threshold, `Expected test share URL to exceed threshold (${longShare.length} <= ${longShare.threshold})`);
|
|
952
|
+
assert.equal(longShare.needsShortener, true, 'Expected oversized share URL to request a shortener option');
|
|
953
|
+
assert.match(longShare.shortenerUrl, /^https:\/\/tinyurl\.com\/create\.php\?url=/, 'Expected TinyURL create URL handoff');
|
|
954
|
+
assert.ok(longShare.shortenerUrl.includes(encodeURIComponent(longShare.url).slice(0, 40)), 'Expected shortener URL to carry the generated share URL');
|
|
955
|
+
endTest();
|
|
956
|
+
|
|
957
|
+
// 7) log:query can produce Turtle; that should stay in plain source output without Markdown tabs.
|
|
928
958
|
beginTest('playground hides markdown tabs for Turtle log:query output');
|
|
929
959
|
await setProgram(logQueryTurtleProgram);
|
|
930
960
|
await clickRun();
|
|
@@ -944,7 +974,7 @@ ${JSON.stringify(last, null, 2)}`);
|
|
|
944
974
|
assert.equal(logQueryTurtle.sourceHidden, false, 'Expected Turtle log:query output to show source directly');
|
|
945
975
|
endTest();
|
|
946
976
|
|
|
947
|
-
//
|
|
977
|
+
// 8) URL-loaded examples should auto-load matching examples/input/<stem>.trig and run in RDF/TriG mode.
|
|
948
978
|
beginTest('playground auto-loads companion TriG sidecars and uses RDF/TriG mode');
|
|
949
979
|
await loadUrlIntoEditor('https://raw.githubusercontent.com/eyereasoner/eyeling/refs/heads/main/examples/smoke-arithmetic.n3');
|
|
950
980
|
const smokeLoaded = await waitForState(
|
|
@@ -973,9 +1003,25 @@ ${JSON.stringify(last, null, 2)}`);
|
|
|
973
1003
|
new RegExp('href="' + started.baseUrl.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '/examples/input/smoke-arithmetic\\.trig"'),
|
|
974
1004
|
'Expected relative Markdown TriG links to resolve against the static output page, not /playground',
|
|
975
1005
|
);
|
|
1006
|
+
assert.equal(smoke.outputTabsHidden, false, 'Expected smoke-arithmetic Markdown output tabs to be visible');
|
|
1007
|
+
assert.equal(smoke.renderedHidden, false, 'Expected smoke-arithmetic Markdown output to render by default');
|
|
1008
|
+
assert.equal(smoke.sourceHidden, true, 'Expected smoke-arithmetic Markdown source to be hidden by default');
|
|
1009
|
+
|
|
1010
|
+
await clickOutputSourceTab();
|
|
1011
|
+
const smokeSourceView = await getPlaygroundState();
|
|
1012
|
+
assert.equal(smokeSourceView.sourceTabSelected, true, 'Expected smoke-arithmetic Markdown source tab to be selectable');
|
|
1013
|
+
assert.equal(smokeSourceView.renderedHidden, true, 'Expected smoke-arithmetic rendered panel to hide in source view');
|
|
1014
|
+
assert.equal(smokeSourceView.sourceHidden, false, 'Expected smoke-arithmetic source editor to show in source view');
|
|
1015
|
+
assert.match(smokeSourceView.output, /^# smoke-arithmetic/m, 'Expected smoke-arithmetic source tab to show Markdown source');
|
|
1016
|
+
|
|
1017
|
+
await clickOutputRenderedTab();
|
|
1018
|
+
const smokeRenderedAgain = await getPlaygroundState();
|
|
1019
|
+
assert.equal(smokeRenderedAgain.renderedTabSelected, true, 'Expected smoke-arithmetic Rendered tab to be selectable again');
|
|
1020
|
+
assert.equal(smokeRenderedAgain.renderedHidden, false, 'Expected smoke-arithmetic rendered panel to show again');
|
|
1021
|
+
assert.equal(smokeRenderedAgain.sourceHidden, true, 'Expected smoke-arithmetic source editor to hide again');
|
|
976
1022
|
endTest();
|
|
977
1023
|
|
|
978
|
-
//
|
|
1024
|
+
// 9) URL-loaded repository examples should auto-load matching examples/builtin/<stem>.js.
|
|
979
1025
|
beginTest('playground auto-loads a companion example builtin for URL-loaded Sudoku');
|
|
980
1026
|
await loadUrlIntoEditor('https://raw.githubusercontent.com/eyereasoner/eyeling/refs/heads/main/examples/sudoku.n3');
|
|
981
1027
|
await waitForState(
|
|
@@ -999,12 +1045,12 @@ ${JSON.stringify(last, null, 2)}`);
|
|
|
999
1045
|
assert.match(sudoku.output, /unique valid Sudoku solution/i, 'Expected Sudoku builtin-backed result');
|
|
1000
1046
|
endTest();
|
|
1001
1047
|
|
|
1002
|
-
//
|
|
1048
|
+
// 10) Ensure no uncaught runtime exceptions.
|
|
1003
1049
|
beginTest('playground has no uncaught runtime exceptions');
|
|
1004
1050
|
assert.equal(exceptions.length, 0, `Uncaught exceptions in playground.html: ${JSON.stringify(exceptions[0] || {})}`);
|
|
1005
1051
|
endTest();
|
|
1006
1052
|
|
|
1007
|
-
//
|
|
1053
|
+
// 11) Console errors are noisy and often indicate a broken UI.
|
|
1008
1054
|
// (We suppress known noise like /favicon.ico on the server.)
|
|
1009
1055
|
beginTest('playground has no console errors');
|
|
1010
1056
|
assert.equal(consoleErrors.length, 0, `Console errors in playground.html: ${JSON.stringify(consoleErrors[0] || {})}`);
|