@phin-tech/dottie 0.11.0 → 0.11.1
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/PARITY.md +1 -1
- package/README.md +7 -2
- package/dist/compile.js +14 -7
- package/dist/dottie-compile.mjs +21 -9
- package/dist/dottie-logic.min.js +1 -1
- package/dist/dottie-player.js +70 -10
- package/dist/dottie-player.min.js +34 -34
- package/dist/dottie-sim.min.js +1 -1
- package/dist/dottie.js +70 -10
- package/dist/types/clicks.d.ts +10 -3
- package/dist/types/compile.d.ts +5 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/player.d.ts +10 -1
- package/package.json +1 -1
package/PARITY.md
CHANGED
|
@@ -59,6 +59,6 @@ fixture, so the gap is visible rather than silent.
|
|
|
59
59
|
| Clicks that set and toggle variables | Supported | [edge/state](../fixtures/edge/state.dottie) | Change what shows without touching the playhead |
|
|
60
60
|
| Looping scenes (`loop` on a marker) | Supported | [edge/state](../fixtures/edge/state.dottie) | No stop on entering, round from the scene's end to its start |
|
|
61
61
|
| Links out of the drawing (`url`) | Supported | [edge/links](../fixtures/edge/links.dottie) | A web or mail `url` opens when clicked if there is no `click`, and SVG export wraps it in `<a>`; a link to another drawing does nothing on the web |
|
|
62
|
-
| Links between shapes and pages | Partial | [edge/clicks](../fixtures/edge/clicks.dottie) | A link to a shape on another page shows that page; one on the same page does nothing. The HTML export
|
|
62
|
+
| Links between shapes and pages | Partial | [edge/clicks](../fixtures/edge/clicks.dottie) | A link to a shape on another page shows that page; one on the same page does nothing. The HTML export of one page has neither; with every page (`--all-pages`, `history`) it shows the page at its own address, and split a page per file (`--split`, `links`) it goes to that page's file |
|
|
63
63
|
| Editing | Missing | | |
|
|
64
64
|
| Ticking task boxes in notes | Missing | | Drawn, not clickable |
|
package/README.md
CHANGED
|
@@ -28,6 +28,8 @@ prefer reduced motion. A still page is just the drawing.
|
|
|
28
28
|
| `clean` | Draw precisely instead of sketchy |
|
|
29
29
|
| `no-controls`, `no-autoplay`, `no-loop` | |
|
|
30
30
|
| `label` | The accessible name; the page name by default |
|
|
31
|
+
| `history` | Each page a link shows gets its own address (`#` and the page's name), so Back and Forward go between pages and a link can open any of them. One such player to a page |
|
|
32
|
+
| `links` | JSON from the id of an element a link points at to the web page that shows it (`{"…": "details.html"}`), for a drawing exported one page per file: a link to another page goes there. Only relative `.html` paths are followed |
|
|
31
33
|
|
|
32
34
|
Elements the drawing makes clickable work with the mouse and the keyboard (Tab, then Enter or Space). A click plays
|
|
33
35
|
a named scene on to the next one, opens a link in a new tab (only `http`, `https` and `mailto`), or shows the page a
|
|
@@ -43,7 +45,8 @@ region a click took down. A looping scene plays round until a click or next leav
|
|
|
43
45
|
|
|
44
46
|
The element has `play()`, `pause()`, `nextScene()`, `prevScene()`, `activate(elementId)`, `currentTime`
|
|
45
47
|
(settable), `duration`, `paused`, `variables` and `setState({name: value})`, and fires `load`, `frame`, `action`,
|
|
46
|
-
`state` (with `{variables}`, after a change)
|
|
48
|
+
`state` (with `{variables}`, after a change), `page` (with `{index, name, first}`, when the page shown changes) and
|
|
49
|
+
`error` events. Its page color comes from the drawing's theme; set
|
|
47
50
|
`--dottie-radius` to round it, and style its parts with `::part(stage)` and `::part(controls)`.
|
|
48
51
|
|
|
49
52
|
Without modules, `dist/dottie-player.min.js` is a classic script that registers the element and sets
|
|
@@ -93,7 +96,9 @@ handwriting fonts the drawing uses (15 to 30 KB each), so one file shows it anyw
|
|
|
93
96
|
```
|
|
94
97
|
|
|
95
98
|
`dottie-compile` takes `--page`, `--at`, `--clean`, `--no-controls`, `--no-autoplay`, `--no-loop` and `--label`;
|
|
96
|
-
only the chosen page (and its pictures) goes in.
|
|
99
|
+
only the chosen page (and its pictures) goes in. With `--all-pages` every page goes in, for a drawing people drill
|
|
100
|
+
into: a link to a shape on another page shows that page, each page gets its own address (`tour.html#Details`), and
|
|
101
|
+
Back goes back (`--page` is then the page to start on). The Dottie Mac app's command-line tool writes the same file:
|
|
97
102
|
`dottie render tour.dottie -f js`. From code: `import { compile } from "@phin-tech/dottie/compile"`.
|
|
98
103
|
|
|
99
104
|
## Use the library
|
package/dist/compile.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! dottie.js 0.11.
|
|
1
|
+
/*! dottie.js 0.11.1 | Apache-2.0 | https://github.com/phin-tech/dottie */
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -763,6 +763,10 @@ function playerAttributes(options) {
|
|
|
763
763
|
if (options.noLoop) out["no-loop"] = "";
|
|
764
764
|
if (options.label !== void 0) out.label = options.label;
|
|
765
765
|
if (options.logicEngine) out["allow-logic"] = "";
|
|
766
|
+
if (options.allPages) {
|
|
767
|
+
out.history = "";
|
|
768
|
+
if (options.page !== void 0) out.page = String(options.page);
|
|
769
|
+
}
|
|
766
770
|
return out;
|
|
767
771
|
}
|
|
768
772
|
function compile(source, runtime, options = {}) {
|
|
@@ -777,28 +781,31 @@ function compile(source, runtime, options = {}) {
|
|
|
777
781
|
const file = parseDottie(raw);
|
|
778
782
|
const json = raw;
|
|
779
783
|
const i = pageIndex(file, options.page === void 0 ? null : String(options.page));
|
|
780
|
-
const
|
|
784
|
+
const chosen = options.allPages ? json.pages.map((_, k) => k) : [i];
|
|
785
|
+
const pages = chosen.map((k) => json.pages[k]);
|
|
781
786
|
const refs = /* @__PURE__ */ new Set();
|
|
782
|
-
JSON.stringify(
|
|
787
|
+
JSON.stringify(pages, (k, v) => {
|
|
783
788
|
if (k === "ref" && typeof v === "string") refs.add(v);
|
|
784
789
|
return v;
|
|
785
790
|
});
|
|
786
791
|
const images = Object.fromEntries(Object.entries(json.images ?? {}).filter(([k]) => refs.has(k)));
|
|
787
|
-
const data = { version: json.version, pages
|
|
792
|
+
const data = { version: json.version, pages };
|
|
788
793
|
if (Object.keys(images).length) data.images = images;
|
|
789
794
|
const fonts = {};
|
|
790
|
-
|
|
795
|
+
const families2 = new Set(chosen.flatMap((k) => options.fontData ? usedFonts(file.pages[k]) : []));
|
|
796
|
+
for (const family of families2) {
|
|
791
797
|
for (const face of fontFaces(family)) {
|
|
792
798
|
const b64 = options.fontData(family, face);
|
|
793
799
|
if (b64) (fonts[family] ?? (fonts[family] = {}))[face] = b64;
|
|
794
800
|
}
|
|
795
801
|
}
|
|
802
|
+
const logic = chosen.some((k) => file.pages[k].logic);
|
|
796
803
|
const fill = {
|
|
797
804
|
DOTTIE_DATA: () => scriptJSON(data),
|
|
798
|
-
DOTTIE_OPTIONS: () => scriptJSON(playerAttributes(
|
|
805
|
+
DOTTIE_OPTIONS: () => scriptJSON(playerAttributes(logic ? options : { ...options, logicEngine: void 0 })),
|
|
799
806
|
DOTTIE_FONTS: () => scriptJSON(fonts)
|
|
800
807
|
};
|
|
801
|
-
const engine = options.logicEngine &&
|
|
808
|
+
const engine = options.logicEngine && logic ? options.logicEngine.trimEnd() + "\n" : "";
|
|
802
809
|
return engine + runtime.trimEnd() + "\n" + LOADER.replace(/\bDOTTIE_(?:DATA|OPTIONS|FONTS)\b/g, (m) => fill[m]());
|
|
803
810
|
}
|
|
804
811
|
export {
|
package/dist/dottie-compile.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/*! dottie.js 0.11.
|
|
2
|
+
/*! dottie.js 0.11.1 | Apache-2.0 | https://github.com/phin-tech/dottie */
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5
5
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -771,6 +771,10 @@ function playerAttributes(options2) {
|
|
|
771
771
|
if (options2.noLoop) out["no-loop"] = "";
|
|
772
772
|
if (options2.label !== void 0) out.label = options2.label;
|
|
773
773
|
if (options2.logicEngine) out["allow-logic"] = "";
|
|
774
|
+
if (options2.allPages) {
|
|
775
|
+
out.history = "";
|
|
776
|
+
if (options2.page !== void 0) out.page = String(options2.page);
|
|
777
|
+
}
|
|
774
778
|
return out;
|
|
775
779
|
}
|
|
776
780
|
function compile(source2, runtime, options2 = {}) {
|
|
@@ -785,33 +789,36 @@ function compile(source2, runtime, options2 = {}) {
|
|
|
785
789
|
const file = parseDottie(raw);
|
|
786
790
|
const json = raw;
|
|
787
791
|
const i = pageIndex(file, options2.page === void 0 ? null : String(options2.page));
|
|
788
|
-
const
|
|
792
|
+
const chosen = options2.allPages ? json.pages.map((_, k) => k) : [i];
|
|
793
|
+
const pages = chosen.map((k) => json.pages[k]);
|
|
789
794
|
const refs = /* @__PURE__ */ new Set();
|
|
790
|
-
JSON.stringify(
|
|
795
|
+
JSON.stringify(pages, (k, v) => {
|
|
791
796
|
if (k === "ref" && typeof v === "string") refs.add(v);
|
|
792
797
|
return v;
|
|
793
798
|
});
|
|
794
799
|
const images = Object.fromEntries(Object.entries(json.images ?? {}).filter(([k]) => refs.has(k)));
|
|
795
|
-
const data = { version: json.version, pages
|
|
800
|
+
const data = { version: json.version, pages };
|
|
796
801
|
if (Object.keys(images).length) data.images = images;
|
|
797
802
|
const fonts = {};
|
|
798
|
-
|
|
803
|
+
const families2 = new Set(chosen.flatMap((k) => options2.fontData ? usedFonts(file.pages[k]) : []));
|
|
804
|
+
for (const family of families2) {
|
|
799
805
|
for (const face of fontFaces(family)) {
|
|
800
806
|
const b64 = options2.fontData(family, face);
|
|
801
807
|
if (b64) (fonts[family] ?? (fonts[family] = {}))[face] = b64;
|
|
802
808
|
}
|
|
803
809
|
}
|
|
810
|
+
const logic = chosen.some((k) => file.pages[k].logic);
|
|
804
811
|
const fill = {
|
|
805
812
|
DOTTIE_DATA: () => scriptJSON(data),
|
|
806
|
-
DOTTIE_OPTIONS: () => scriptJSON(playerAttributes(
|
|
813
|
+
DOTTIE_OPTIONS: () => scriptJSON(playerAttributes(logic ? options2 : { ...options2, logicEngine: void 0 })),
|
|
807
814
|
DOTTIE_FONTS: () => scriptJSON(fonts)
|
|
808
815
|
};
|
|
809
|
-
const engine = options2.logicEngine &&
|
|
816
|
+
const engine = options2.logicEngine && logic ? options2.logicEngine.trimEnd() + "\n" : "";
|
|
810
817
|
return engine + runtime.trimEnd() + "\n" + LOADER.replace(/\bDOTTIE_(?:DATA|OPTIONS|FONTS)\b/g, (m) => fill[m]());
|
|
811
818
|
}
|
|
812
819
|
|
|
813
820
|
// src/index.ts
|
|
814
|
-
var VERSION = "0.11.
|
|
821
|
+
var VERSION = "0.11.1";
|
|
815
822
|
|
|
816
823
|
// src/cli.ts
|
|
817
824
|
var usage = `dottie-compile ${VERSION}: a Dottie drawing as one script that plays it on any page.
|
|
@@ -825,10 +832,12 @@ USAGE
|
|
|
825
832
|
OPTIONS
|
|
826
833
|
-o, --output <path> Where to write it ("-" for stdout); default drawing.js next to the input
|
|
827
834
|
-p, --page <page> Page name or 1-based number; only that page is included (default the first)
|
|
835
|
+
--all-pages Include every page, with links between them working and Back going back (with
|
|
836
|
+
--page, the page to start on)
|
|
828
837
|
--at <seconds> Show that moment as a still
|
|
829
838
|
--clean Draw precisely instead of sketchy
|
|
830
839
|
--no-controls, --no-autoplay, --no-loop
|
|
831
|
-
--allow-logic
|
|
840
|
+
--allow-logic let the page's click logic run (ADR 0007); it carries the engine (about 850 KB)
|
|
832
841
|
--label <text> The player's accessible name
|
|
833
842
|
`;
|
|
834
843
|
function fail(message, code = 2) {
|
|
@@ -868,6 +877,9 @@ for (let i = 0; i < args.length; i++) {
|
|
|
868
877
|
options.at = t;
|
|
869
878
|
break;
|
|
870
879
|
}
|
|
880
|
+
case "--all-pages":
|
|
881
|
+
options.allPages = true;
|
|
882
|
+
break;
|
|
871
883
|
case "--clean":
|
|
872
884
|
options.clean = true;
|
|
873
885
|
break;
|
package/dist/dottie-logic.min.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! dottie.js 0.11.
|
|
1
|
+
/*! dottie.js 0.11.1 | Apache-2.0 | https://github.com/phin-tech/dottie */
|
|
2
2
|
"use strict";(()=>{var Sx=Object.defineProperty;var w=(x,F)=>()=>(x&&(F=x(x=0)),F);var E0=(x,F)=>{for(var A in F)Sx(x,A,{get:F[A],enumerable:!0})};var T,f0,Z,H,L,K=w(()=>{T={JS_EVAL_TYPE_GLOBAL:0,JS_EVAL_TYPE_MODULE:1,JS_EVAL_TYPE_DIRECT:2,JS_EVAL_TYPE_INDIRECT:3,JS_EVAL_TYPE_MASK:3,JS_EVAL_FLAG_STRICT:8,JS_EVAL_FLAG_STRIP:16,JS_EVAL_FLAG_COMPILE_ONLY:32,JS_EVAL_FLAG_BACKTRACE_BARRIER:64},f0={BaseObjects:1,Date:2,Eval:4,StringNormalize:8,RegExp:16,RegExpCompiler:32,JSON:64,Proxy:128,MapSet:256,TypedArrays:512,Promise:1024,BigInt:2048,BigFloat:4096,BigDecimal:8192,OperatorOverloading:16384,BignumExt:32768},Z={Pending:0,Fulfilled:1,Rejected:2},H={JS_GPN_STRING_MASK:1,JS_GPN_SYMBOL_MASK:2,JS_GPN_PRIVATE_MASK:4,JS_GPN_ENUM_ONLY:16,JS_GPN_SET_ENUM:32,QTS_GPN_NUMBER_MASK:64,QTS_STANDARD_COMPLIANT_NUMBER:128},L={IsStrictlyEqual:0,IsSameValue:1,IsSameValueZero:2}});function J(...x){D0&&console.log("quickjs-emscripten:",...x)}function*xx(x){return yield x}function Ix(x){return xx(i0(x))}function R0(x,F){return(...A)=>{let v=F.call(x,n0,...A);return i0(v)}}function wx(x,F){let A=F.call(x,n0);return i0(A)}function i0(x){function F(A){return A.done?A.value:A.value instanceof Promise?A.value.then(v=>F(x.next(v)),v=>F(x.throw(v))):F(x.next(A.value))}return F(x.next())}function j0(x,F){let A;try{x.dispose()}catch(v){A=v}if(F&&A)throw Object.assign(F,{message:`${F.message}
|
|
3
3
|
Then, failed to dispose scope: ${A.message}`,disposeError:A}),F;if(F||A)throw F||A}function Rx(x){let F=x?Array.from(x):[];function A(){return F.forEach(E=>E.alive?E.dispose():void 0)}function v(){return F.some(E=>E.alive)}return Object.defineProperty(F,C0,{configurable:!0,enumerable:!1,value:A}),Object.defineProperty(F,"dispose",{configurable:!0,enumerable:!1,value:A}),Object.defineProperty(F,"alive",{configurable:!0,enumerable:!1,get:v}),F}function W(x){return!!(x&&(typeof x=="object"||typeof x=="function")&&"alive"in x&&typeof x.alive=="boolean"&&"dispose"in x&&typeof x.dispose=="function")}function Jx(x){if(!x)return 0;let F=0;for(let[A,v]of Object.entries(x)){if(!(A in f0))throw new X0(A);v&&(F|=f0[A])}return F}function Ox(x){if(typeof x=="number")return x;if(x===void 0)return 0;let{type:F,strict:A,strip:v,compileOnly:E,backtraceBarrier:j}=x,e=0;return F==="global"&&(e|=T.JS_EVAL_TYPE_GLOBAL),F==="module"&&(e|=T.JS_EVAL_TYPE_MODULE),A&&(e|=T.JS_EVAL_FLAG_STRICT),v&&(e|=T.JS_EVAL_FLAG_STRIP),E&&(e|=T.JS_EVAL_FLAG_COMPILE_ONLY),j&&(e|=T.JS_EVAL_FLAG_BACKTRACE_BARRIER),e}function Vx(x){if(typeof x=="number")return x;if(x===void 0)return 0;let{strings:F,symbols:A,quickjsPrivate:v,onlyEnumerable:E,numbers:j,numbersAsStrings:e}=x,t=0;return F&&(t|=H.JS_GPN_STRING_MASK),A&&(t|=H.JS_GPN_SYMBOL_MASK),v&&(t|=H.JS_GPN_PRIVATE_MASK),E&&(t|=H.JS_GPN_ENUM_ONLY),j&&(t|=H.QTS_GPN_NUMBER_MASK),e&&(t|=H.QTS_STANDARD_COMPLIANT_NUMBER),t}function Zx(...x){let F=[];for(let A of x)A!==void 0&&(F=F.concat(A));return F}function e0(x){return x>>8}function s0(x,F){F.interruptHandler&&x.setInterruptHandler(F.interruptHandler),F.maxStackSizeBytes!==void 0&&x.setMaxStackSize(F.maxStackSizeBytes),F.memoryLimitBytes!==void 0&&x.setMemoryLimit(F.memoryLimitBytes)}function l0(x,F){F.moduleLoader&&x.setModuleLoader(F.moduleLoader),F.shouldInterrupt&&x.setInterruptHandler(F.shouldInterrupt),F.memoryLimitBytes!==void 0&&x.setMemoryLimit(F.memoryLimitBytes),F.maxStackSizeBytes!==void 0&&x.setMaxStackSize(F.maxStackSizeBytes)}var gx,Tx,D0,Hx,t0,V0,b0,Z0,K0,U0,yx,Nx,X0,W0,Y0,z0,$,n0,m,C0,M0,k,y,P0,q,o0,Mx,Px,R,Lx,vx,i8,o8,Kx,L0,J0,X,Ux,O0,Xx,Wx,Yx,zx,a0,Bx,rx=w(()=>{K();K();gx=Object.defineProperty,Tx=(x,F)=>{for(var A in F)gx(x,A,{get:F[A],enumerable:!0})},D0=!1;Hx={};Tx(Hx,{QuickJSAsyncifyError:()=>K0,QuickJSAsyncifySuspended:()=>U0,QuickJSEmptyGetOwnPropertyNames:()=>Y0,QuickJSEmscriptenModuleError:()=>Nx,QuickJSHostRefInvalid:()=>$,QuickJSHostRefRangeExceeded:()=>z0,QuickJSMemoryLeakDetected:()=>yx,QuickJSNotImplemented:()=>Z0,QuickJSPromisePending:()=>W0,QuickJSUnknownIntrinsic:()=>X0,QuickJSUnwrapError:()=>t0,QuickJSUseAfterFree:()=>b0,QuickJSWrongOwner:()=>V0});t0=class extends Error{constructor(x,F){let A=typeof x=="object"&&x&&"message"in x?String(x.message):String(x);super(A),this.cause=x,this.context=F,this.name="QuickJSUnwrapError"}},V0=class extends Error{constructor(){super(...arguments),this.name="QuickJSWrongOwner"}},b0=class extends Error{constructor(){super(...arguments),this.name="QuickJSUseAfterFree"}},Z0=class extends Error{constructor(){super(...arguments),this.name="QuickJSNotImplemented"}},K0=class extends Error{constructor(){super(...arguments),this.name="QuickJSAsyncifyError"}},U0=class extends Error{constructor(){super(...arguments),this.name="QuickJSAsyncifySuspended"}},yx=class extends Error{constructor(){super(...arguments),this.name="QuickJSMemoryLeakDetected"}},Nx=class extends Error{constructor(){super(...arguments),this.name="QuickJSEmscriptenModuleError"}},X0=class extends TypeError{constructor(){super(...arguments),this.name="QuickJSUnknownIntrinsic"}},W0=class extends Error{constructor(){super(...arguments),this.name="QuickJSPromisePending"}},Y0=class extends Error{constructor(){super(...arguments),this.name="QuickJSEmptyGetOwnPropertyNames"}},z0=class extends Error{constructor(){super(...arguments),this.name="QuickJSHostRefRangeExceeded"}},$=class extends Error{constructor(){super(...arguments),this.name="QuickJSHostRefInvalid"}};n0=xx;n0.of=Ix;m=class{[Symbol.dispose](){return this.dispose()}},C0=Symbol.dispose??Symbol.for("Symbol.dispose"),M0=m.prototype;M0[C0]||(M0[C0]=function(){return this.dispose()});k=class Ax extends m{constructor(F,A,v,E){super(),this._value=F,this.copier=A,this.disposer=v,this._owner=E,this._alive=!0,this._constructorStack=D0?new Error("Lifetime constructed").stack:void 0}get alive(){return this._alive}get value(){return this.assertAlive(),this._value}get owner(){return this._owner}get dupable(){return!!this.copier}dup(){if(this.assertAlive(),!this.copier)throw new Error("Non-dupable lifetime");return new Ax(this.copier(this._value),this.copier,this.disposer,this._owner)}consume(F){this.assertAlive();let A=F(this);return this.dispose(),A}map(F){return this.assertAlive(),F(this)}tap(F){return F(this),this}dispose(){this.assertAlive(),this.disposer&&this.disposer(this._value),this._alive=!1}assertAlive(){if(!this.alive)throw this._constructorStack?new b0(`Lifetime not alive
|
|
4
4
|
${this._constructorStack}
|
package/dist/dottie-player.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! dottie.js 0.11.
|
|
1
|
+
/*! dottie.js 0.11.1 | Apache-2.0 | https://github.com/phin-tech/dottie */
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __defNormalProp = (obj, key, value2) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value: value2 }) : obj[key] = value2;
|
|
4
4
|
var __export = (target, all) => {
|
|
@@ -4030,7 +4030,7 @@ function sceneNamed(name, markers) {
|
|
|
4030
4030
|
const exact = markers.findIndex((m) => m.name === name);
|
|
4031
4031
|
return exact >= 0 ? exact : markers.findIndex((m) => m.name.toLowerCase() === name.toLowerCase());
|
|
4032
4032
|
}
|
|
4033
|
-
function clickTargets(page, file) {
|
|
4033
|
+
function clickTargets(page, file, hrefs) {
|
|
4034
4034
|
const markers = page.timeline?.markers ?? [];
|
|
4035
4035
|
const out = /* @__PURE__ */ new Map();
|
|
4036
4036
|
let pageOf = null;
|
|
@@ -4066,11 +4066,19 @@ function clickTargets(page, file) {
|
|
|
4066
4066
|
});
|
|
4067
4067
|
}
|
|
4068
4068
|
const target = pageOf.get(e.link);
|
|
4069
|
-
if (target !== void 0 && file.pages[target] !== page)
|
|
4069
|
+
if (target !== void 0 && file.pages[target] !== page) {
|
|
4070
|
+
out.set(e.id, { page: target });
|
|
4071
|
+
continue;
|
|
4072
|
+
}
|
|
4070
4073
|
}
|
|
4074
|
+
const href = e.link && hrefs && Object.prototype.hasOwnProperty.call(hrefs, e.link) ? pageHref(hrefs[e.link]) : null;
|
|
4075
|
+
if (href) out.set(e.id, { href });
|
|
4071
4076
|
}
|
|
4072
4077
|
return out;
|
|
4073
4078
|
}
|
|
4079
|
+
function pageHref(href) {
|
|
4080
|
+
return typeof href === "string" && /^[A-Za-z0-9._~%/-]+\.html(#[^\s:]*)?$/.test(href) && !href.startsWith("//") ? href : null;
|
|
4081
|
+
}
|
|
4074
4082
|
function hoveredElement(e) {
|
|
4075
4083
|
const h = e.hover;
|
|
4076
4084
|
if (!h) return e;
|
|
@@ -5143,7 +5151,8 @@ output { font-variant-numeric: tabular-nums; min-width: 4.5em; text-align: right
|
|
|
5143
5151
|
.error { padding: 16px; font-family: ui-monospace, Menlo, monospace; white-space: pre-wrap; }
|
|
5144
5152
|
${CLICK_STYLE}`;
|
|
5145
5153
|
var Playback = class {
|
|
5146
|
-
/** `file` is the drawing `page` belongs to, so links to its other pages are clickable
|
|
5154
|
+
/** `file` is the drawing `page` belongs to, so links to its other pages are clickable; `hrefs`, the web pages that
|
|
5155
|
+
* show the elements links point at, for pages that aren't in it (clickTargets). */
|
|
5147
5156
|
constructor(page, into, options = {}) {
|
|
5148
5157
|
__publicField(this, "page");
|
|
5149
5158
|
__publicField(this, "plan");
|
|
@@ -5185,7 +5194,7 @@ var Playback = class {
|
|
|
5185
5194
|
this.page = options.clean ? cleanCopy(page) : page;
|
|
5186
5195
|
addFonts(usedFonts(this.page));
|
|
5187
5196
|
this.plan = plan(this.page);
|
|
5188
|
-
this.clicks = clickTargets(page, options.file);
|
|
5197
|
+
this.clicks = clickTargets(page, options.file, options.hrefs);
|
|
5189
5198
|
const table = symbolTable(this.page);
|
|
5190
5199
|
for (const e of this.page.elements) {
|
|
5191
5200
|
const s = e.kind === "symbol" && e.symbol !== null ? table.get(e.symbol) : void 0;
|
|
@@ -5454,6 +5463,11 @@ var DottiePlayer = class extends ElementBase {
|
|
|
5454
5463
|
__publicField(this, "stillTime", null);
|
|
5455
5464
|
__publicField(this, "visible", true);
|
|
5456
5465
|
__publicField(this, "observer", null);
|
|
5466
|
+
/** The page last shown, so `page` fires only when it changes. */
|
|
5467
|
+
__publicField(this, "shownPage", null);
|
|
5468
|
+
__publicField(this, "onPopState", () => {
|
|
5469
|
+
if (this.file) this.mount();
|
|
5470
|
+
});
|
|
5457
5471
|
/** Runs handler `handler` from the page's logic for a click on `id` (DottieDocument.clicked). Clicks take turns, so
|
|
5458
5472
|
* each handler sees the state the one before left. */
|
|
5459
5473
|
__publicField(this, "logicQueue", Promise.resolve());
|
|
@@ -5502,15 +5516,21 @@ var DottiePlayer = class extends ElementBase {
|
|
|
5502
5516
|
});
|
|
5503
5517
|
this.observer.observe(this);
|
|
5504
5518
|
}
|
|
5519
|
+
if (this.hasAttribute("history")) window.addEventListener("popstate", this.onPopState);
|
|
5505
5520
|
void this.load();
|
|
5506
5521
|
}
|
|
5507
5522
|
disconnectedCallback() {
|
|
5508
5523
|
cancelAnimationFrame(this.raf);
|
|
5509
5524
|
this.raf = 0;
|
|
5510
5525
|
this.observer?.disconnect();
|
|
5526
|
+
window.removeEventListener("popstate", this.onPopState);
|
|
5511
5527
|
}
|
|
5512
5528
|
attributeChangedCallback(name, old, value2) {
|
|
5513
5529
|
if (old === value2 || !this.isConnected) return;
|
|
5530
|
+
if (name === "history") {
|
|
5531
|
+
if (value2 === null) window.removeEventListener("popstate", this.onPopState);
|
|
5532
|
+
else window.addEventListener("popstate", this.onPopState);
|
|
5533
|
+
}
|
|
5514
5534
|
if (name === "src") void this.load();
|
|
5515
5535
|
else if (name === "label") this.stage.setAttribute("aria-label", value2 ?? "");
|
|
5516
5536
|
else if (this.file) this.mount();
|
|
@@ -5559,6 +5579,7 @@ var DottiePlayer = class extends ElementBase {
|
|
|
5559
5579
|
}
|
|
5560
5580
|
showFile(file) {
|
|
5561
5581
|
this.file = file;
|
|
5582
|
+
this.shownPage = null;
|
|
5562
5583
|
for (const w of file.warnings) console.warn(`dottie-player: ${w}`);
|
|
5563
5584
|
this.mount(() => this.dispatchEvent(new CustomEvent("load", { detail: { file } })));
|
|
5564
5585
|
}
|
|
@@ -5566,7 +5587,7 @@ var DottiePlayer = class extends ElementBase {
|
|
|
5566
5587
|
* showing stays until it is ready; a newer mount, file or failed load in the meantime wins. */
|
|
5567
5588
|
mount(mounted) {
|
|
5568
5589
|
const file = this.file;
|
|
5569
|
-
const page = file.pages[pageIndex(file, this.getAttribute("page"))];
|
|
5590
|
+
const page = file.pages[this.addressedPage(file) ?? pageIndex(file, this.getAttribute("page"))];
|
|
5570
5591
|
const clean = this.hasAttribute("clean");
|
|
5571
5592
|
const token = ++this.mountToken;
|
|
5572
5593
|
const shown = clean ? cleanCopy(page) : page;
|
|
@@ -5581,10 +5602,41 @@ var DottiePlayer = class extends ElementBase {
|
|
|
5581
5602
|
mounted?.();
|
|
5582
5603
|
});
|
|
5583
5604
|
}
|
|
5605
|
+
/** With `history`, the page the address names after its `#` (by name, any case), if it names one. */
|
|
5606
|
+
addressedPage(file) {
|
|
5607
|
+
if (!this.hasAttribute("history") || typeof location === "undefined" || location.hash.length < 2) return null;
|
|
5608
|
+
let name;
|
|
5609
|
+
try {
|
|
5610
|
+
name = decodeURIComponent(location.hash.slice(1));
|
|
5611
|
+
} catch {
|
|
5612
|
+
return null;
|
|
5613
|
+
}
|
|
5614
|
+
const i = file.pages.findIndex((p) => p.name.toLowerCase() === name.toLowerCase());
|
|
5615
|
+
return i >= 0 ? i : null;
|
|
5616
|
+
}
|
|
5617
|
+
/** The `links` attribute read: element id to web page, the pages that can't be named left out. */
|
|
5618
|
+
hrefs() {
|
|
5619
|
+
const raw = this.getAttribute("links");
|
|
5620
|
+
if (!raw) return void 0;
|
|
5621
|
+
let v;
|
|
5622
|
+
try {
|
|
5623
|
+
v = JSON.parse(raw);
|
|
5624
|
+
} catch {
|
|
5625
|
+
console.warn("dottie-player: links isn't JSON");
|
|
5626
|
+
return void 0;
|
|
5627
|
+
}
|
|
5628
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) return void 0;
|
|
5629
|
+
return v;
|
|
5630
|
+
}
|
|
5584
5631
|
mountPage(file, page, clean) {
|
|
5585
|
-
const p = new Playback(page, this.stage, { clean, file });
|
|
5632
|
+
const p = new Playback(page, this.stage, { clean, file, hrefs: this.hrefs() });
|
|
5586
5633
|
p.still = this.hasAttribute("at");
|
|
5587
5634
|
this.playback = p;
|
|
5635
|
+
if (this.shownPage !== page) {
|
|
5636
|
+
const first = this.shownPage === null;
|
|
5637
|
+
this.shownPage = page;
|
|
5638
|
+
queueMicrotask(() => this.dispatchEvent(new CustomEvent("page", { detail: { index: file.pages.indexOf(page), name: page.name, first } })));
|
|
5639
|
+
}
|
|
5588
5640
|
this.style.setProperty("--dottie-page", color(p.background));
|
|
5589
5641
|
this.style.setProperty("--dottie-ink", color(p.ink));
|
|
5590
5642
|
this.style.colorScheme = luminance(p.background) < 0.5 ? "dark" : "light";
|
|
@@ -5696,7 +5748,15 @@ var DottiePlayer = class extends ElementBase {
|
|
|
5696
5748
|
if ("url" in click) {
|
|
5697
5749
|
if (/^(https?:|mailto:)/i.test(click.url)) window.open(click.url, "_blank", "noopener");
|
|
5698
5750
|
} else if ("page" in click) {
|
|
5699
|
-
this.
|
|
5751
|
+
const target = this.file?.pages[click.page];
|
|
5752
|
+
if (this.hasAttribute("history") && target) {
|
|
5753
|
+
history.pushState(null, "", "#" + encodeURIComponent(target.name));
|
|
5754
|
+
this.mount();
|
|
5755
|
+
} else {
|
|
5756
|
+
this.setAttribute("page", String(click.page + 1));
|
|
5757
|
+
}
|
|
5758
|
+
} else if ("href" in click) {
|
|
5759
|
+
location.assign(click.href);
|
|
5700
5760
|
} else if (click.scene >= 0 && click.scene < p.scenes.length) {
|
|
5701
5761
|
if (reduced || this.hasAttribute("at") || p.frameCount < 2) {
|
|
5702
5762
|
this.setPlaying(false);
|
|
@@ -5842,7 +5902,7 @@ var DottiePlayer = class extends ElementBase {
|
|
|
5842
5902
|
if (handled) e.preventDefault();
|
|
5843
5903
|
}
|
|
5844
5904
|
};
|
|
5845
|
-
__publicField(DottiePlayer, "observedAttributes", ["src", "page", "at", "clean", "no-controls", "label", "allow-logic"]);
|
|
5905
|
+
__publicField(DottiePlayer, "observedAttributes", ["src", "page", "at", "clean", "no-controls", "label", "allow-logic", "history", "links"]);
|
|
5846
5906
|
function clickable(target) {
|
|
5847
5907
|
const el = target;
|
|
5848
5908
|
return el && typeof el.closest === "function" ? el.closest(".dottie-a") : null;
|
|
@@ -5947,7 +6007,7 @@ function render(source, options = {}) {
|
|
|
5947
6007
|
function isFile(v) {
|
|
5948
6008
|
return typeof v === "object" && v !== null && Array.isArray(v.pages) && Array.isArray(v.warnings);
|
|
5949
6009
|
}
|
|
5950
|
-
var VERSION = "0.11.
|
|
6010
|
+
var VERSION = "0.11.1";
|
|
5951
6011
|
|
|
5952
6012
|
// src/player-entry.ts
|
|
5953
6013
|
servePlans();
|