@pie-players/pie-assessment-toolkit 0.3.74 → 0.3.75
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/README.md +349 -313
- package/dist/attempt/TestSession.d.ts +1 -20
- package/dist/attempt/TestSession.js +8 -99
- package/dist/components/ItemScope.custom-element.d.ts +1 -0
- package/dist/components/ItemScope.custom-element.js +1 -0
- package/dist/components/ItemToolBar.custom-element.js +1 -1
- package/dist/components/PieAssessmentToolkit.custom-element.js +14 -14
- package/dist/components/SectionToolBar.custom-element.js +1 -1
- package/dist/components/chunks/ItemToolBar-7tt7v2xp.js +4 -0
- package/dist/components/chunks/{ItemToolBar-gmrryv2v.js → ItemToolBar-97hx60z4.js} +1 -1
- package/dist/components/chunks/ItemToolBar-bxwyhr5p.js +2 -0
- package/dist/components/chunks/ItemToolBar-jx38w99s.js +2 -0
- package/dist/components/chunks/ItemToolBar-rd2bb4p6.js +40 -0
- package/dist/components/chunks/ItemToolBar-vdkyn9f3.js +2 -0
- package/dist/components/chunks/sre-engine-jd8cc08x.js +1 -0
- package/dist/components/item-scope-element.d.ts +2 -0
- package/dist/components/item-scope-element.js +2 -0
- package/dist/context/assessment-toolkit-context.d.ts +27 -6
- package/dist/index.d.ts +22 -47
- package/dist/index.js +12 -36
- package/dist/policy/core/PolicySource.d.ts +1 -1
- package/dist/policy/core/ToolPolicyEngine.d.ts +77 -32
- package/dist/policy/core/ToolPolicyEngine.js +136 -46
- package/dist/policy/core/compose-decision.d.ts +28 -7
- package/dist/policy/core/compose-decision.js +75 -54
- package/dist/policy/core/decision-types.d.ts +65 -34
- package/dist/policy/core/feature-decision.d.ts +16 -9
- package/dist/policy/core/feature-decision.js +14 -8
- package/dist/policy/core/pnp-policy-inputs.d.ts +24 -33
- package/dist/policy/core/pnp-policy-inputs.js +28 -56
- package/dist/policy/core/provenance.d.ts +9 -4
- package/dist/policy/core/provenance.js +1 -1
- package/dist/policy/engine.d.ts +7 -23
- package/dist/policy/engine.js +5 -20
- package/dist/policy/sources/PnpPolicySource.d.ts +44 -61
- package/dist/policy/sources/PnpPolicySource.js +117 -118
- package/dist/runtime/SectionControllerBinding.d.ts +279 -0
- package/dist/runtime/SectionControllerBinding.js +450 -0
- package/dist/runtime/SectionRuntimeEngine.d.ts +26 -289
- package/dist/runtime/SectionRuntimeEngine.js +30 -372
- package/dist/runtime/adapter/SectionEngineAdapter.d.ts +19 -80
- package/dist/runtime/adapter/SectionEngineAdapter.js +19 -92
- package/dist/runtime/adapter/dom-event-bridge.d.ts +15 -30
- package/dist/runtime/adapter/dom-event-bridge.js +17 -44
- package/dist/runtime/adapter/subscriber-fanout.d.ts +1 -2
- package/dist/runtime/adapter/subscriber-fanout.js +1 -2
- package/dist/runtime/catalog-context.d.ts +19 -0
- package/dist/runtime/catalog-context.js +28 -0
- package/dist/runtime/composition-emit-scheduler.d.ts +9 -15
- package/dist/runtime/composition-emit-scheduler.js +9 -15
- package/dist/runtime/content-language.d.ts +32 -0
- package/dist/runtime/content-language.js +46 -0
- package/dist/runtime/content-region.d.ts +17 -0
- package/dist/runtime/content-region.js +29 -0
- package/dist/runtime/content-registration.d.ts +13 -0
- package/dist/runtime/content-registration.js +25 -0
- package/dist/runtime/core/SectionEngineCore.d.ts +2 -2
- package/dist/runtime/core/SectionEngineCore.js +2 -2
- package/dist/runtime/core/cohort.d.ts +1 -1
- package/dist/runtime/core/cohort.js +1 -1
- package/dist/runtime/core/engine-input.d.ts +18 -30
- package/dist/runtime/core/engine-input.js +11 -12
- package/dist/runtime/core/engine-output.d.ts +16 -40
- package/dist/runtime/core/engine-output.js +9 -21
- package/dist/runtime/core/engine-readiness.d.ts +5 -37
- package/dist/runtime/core/engine-readiness.js +8 -41
- package/dist/runtime/core/engine-resolver.d.ts +46 -74
- package/dist/runtime/core/engine-resolver.js +18 -43
- package/dist/runtime/core/engine-state.d.ts +28 -36
- package/dist/runtime/core/engine-state.js +18 -21
- package/dist/runtime/core/engine-transition.d.ts +14 -19
- package/dist/runtime/core/engine-transition.js +71 -51
- package/dist/runtime/engine.d.ts +16 -19
- package/dist/runtime/engine.js +12 -19
- package/dist/runtime/page-warnings.d.ts +13 -0
- package/dist/runtime/page-warnings.js +22 -0
- package/dist/runtime/policy-input-forwarding.d.ts +25 -0
- package/dist/runtime/policy-input-forwarding.js +25 -0
- package/dist/runtime/registration-events.d.ts +11 -0
- package/dist/runtime/runtime-event-claim.d.ts +8 -0
- package/dist/runtime/runtime-event-claim.js +15 -0
- package/dist/runtime/shell-event-bridge.d.ts +45 -0
- package/dist/runtime/shell-event-bridge.js +127 -0
- package/dist/runtime/shell-registration.d.ts +73 -0
- package/dist/runtime/shell-registration.js +95 -0
- package/dist/runtime/shell-scope.d.ts +68 -0
- package/dist/runtime/shell-scope.js +188 -0
- package/dist/runtime/tool-host-contract.d.ts +8 -10
- package/dist/runtime/tool-host-contract.js +11 -11
- package/dist/runtime/unclaimed-registration-watch.d.ts +7 -0
- package/dist/runtime/unclaimed-registration-watch.js +23 -0
- package/dist/services/ElementToolStateStore.d.ts +14 -10
- package/dist/services/ElementToolStateStore.js +37 -13
- package/dist/services/HighlightCoordinator.d.ts +21 -21
- package/dist/services/HighlightCoordinator.js +431 -325
- package/dist/services/RangeSerializer.d.ts +10 -1
- package/dist/services/RangeSerializer.js +87 -14
- package/dist/services/TTSService.d.ts +117 -70
- package/dist/services/TTSService.js +668 -578
- package/dist/services/ToolCoordinator.d.ts +43 -60
- package/dist/services/ToolCoordinator.js +164 -206
- package/dist/services/ToolRegistry.d.ts +74 -57
- package/dist/services/ToolRegistry.js +104 -114
- package/dist/services/ToolkitCoordinator.d.ts +183 -189
- package/dist/services/ToolkitCoordinator.js +477 -431
- package/dist/services/audio-handoff.d.ts +6 -7
- package/dist/services/audio-handoff.js +20 -14
- package/dist/services/catalog-owner.d.ts +0 -1
- package/dist/services/framework-error-bus.d.ts +3 -6
- package/dist/services/framework-error-bus.js +3 -6
- package/dist/services/framework-error.d.ts +22 -7
- package/dist/services/framework-error.js +9 -7
- package/dist/services/interfaces.d.ts +158 -129
- package/dist/services/section-session-assignment.d.ts +21 -0
- package/dist/services/section-session-assignment.js +82 -0
- package/dist/services/spoken-audio-cards.d.ts +0 -2
- package/dist/services/spoken-audio-cards.js +0 -2
- package/dist/services/tool-config-defaults.d.ts +3 -3
- package/dist/services/tool-config-defaults.js +3 -3
- package/dist/services/tool-config-validation.d.ts +4 -5
- package/dist/services/tool-config-validation.js +36 -61
- package/dist/services/tool-context.d.ts +0 -8
- package/dist/services/tool-context.js +0 -12
- package/dist/services/tool-icons.d.ts +4 -3
- package/dist/services/tool-icons.js +4 -3
- package/dist/services/tool-instance-id.d.ts +0 -1
- package/dist/services/tool-instance-id.js +0 -6
- package/dist/services/tool-providers/TTSToolProvider.d.ts +18 -19
- package/dist/services/tool-providers/TTSToolProvider.js +37 -34
- package/dist/services/tool-providers/ToolProviderApi.d.ts +10 -4
- package/dist/services/tool-providers/ToolProviderRegistry.d.ts +30 -26
- package/dist/services/tool-providers/ToolProviderRegistry.js +119 -93
- package/dist/services/tool-request.d.ts +27 -12
- package/dist/services/tool-request.js +24 -14
- package/dist/services/toolbar-decided-tools.d.ts +15 -0
- package/dist/services/toolbar-decided-tools.js +28 -0
- package/dist/services/tools-config-normalizer.d.ts +17 -22
- package/dist/services/tools-config-normalizer.js +2 -10
- package/dist/services/tts/browser-provider.d.ts +38 -2
- package/dist/services/tts/browser-provider.js +276 -140
- package/dist/services/tts/flat-tree.d.ts +71 -0
- package/dist/services/tts/flat-tree.js +269 -0
- package/dist/services/tts/generated-speech/assemble-plan.d.ts +3 -1
- package/dist/services/tts/generated-speech/assemble-plan.js +3 -1
- package/dist/services/tts/generated-speech/dom/build-dom-plan.d.ts +2 -0
- package/dist/services/tts/generated-speech/dom/build-dom-plan.js +1 -1
- package/dist/services/tts/generated-speech/math-speech-cache.d.ts +3 -1
- package/dist/services/tts/generated-speech/math-speech-cache.js +5 -1
- package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +12 -4
- package/dist/services/tts/highlight-pipeline/prose-boundary-resolver.js +6 -4
- package/dist/services/tts/highlight-pipeline/readable-region.js +3 -2
- package/dist/services/tts/highlight-pipeline/types.d.ts +5 -0
- package/dist/services/tts/highlight-pipeline/visible-map-range.d.ts +12 -0
- package/dist/services/tts/highlight-pipeline/visible-map-range.js +73 -7
- package/dist/services/tts/math-aware-text-processing.d.ts +5 -1
- package/dist/services/tts/math-aware-text-processing.js +32 -18
- package/dist/services/tts/math-control-names.d.ts +21 -0
- package/dist/services/tts/math-control-names.js +142 -0
- package/dist/services/tts/math-speech.d.ts +11 -0
- package/dist/services/tts/math-speech.js +51 -18
- package/dist/services/tts/provider-options.d.ts +41 -0
- package/dist/services/tts/provider-options.js +1 -0
- package/dist/services/tts/ssml/spoken-text.d.ts +2 -26
- package/dist/services/tts/ssml/spoken-text.js +29 -0
- package/dist/services/tts/start-failure.d.ts +11 -0
- package/dist/services/tts/start-failure.js +19 -0
- package/dist/services/tts/text-processing.d.ts +9 -0
- package/dist/services/tts/text-processing.js +46 -33
- package/dist/services/tts/text-segmentation.d.ts +7 -0
- package/dist/services/tts/text-segmentation.js +47 -0
- package/dist/services/tts-runtime-config.d.ts +25 -17
- package/dist/services/tts-runtime-config.js +16 -95
- package/dist/tools/content-capability-resolution.d.ts +7 -9
- package/dist/tools/content-capability-resolution.js +8 -45
- package/dist/tools/registration.d.ts +58 -0
- package/dist/tools/registration.js +54 -0
- package/dist/tools/registrations/toolbar-registration-helpers.js +2 -2
- package/dist/tools/tool-surface-host.d.ts +6 -10
- package/dist/tools/tool-surface-host.js +44 -42
- package/dist/tools/tool-tag-map.d.ts +5 -15
- package/dist/tools/tool-tag-map.js +6 -20
- package/dist/utils/structural-equality.d.ts +11 -0
- package/dist/utils/structural-equality.js +47 -0
- package/package.json +13 -29
- package/dist/attempt/adapters/activity-to-test-attempt-session.d.ts +0 -49
- package/dist/attempt/adapters/activity-to-test-attempt-session.js +0 -138
- package/dist/components/chunks/ItemToolBar-b9dz5jvd.js +0 -40
- package/dist/components/chunks/ItemToolBar-h4xap0t0.js +0 -4
- package/dist/components/chunks/ItemToolBar-wr2myaah.js +0 -2
- package/dist/components/chunks/sre-engine-wf9s43gg.js +0 -1
- package/dist/context/runtime-context-consumer.d.ts +0 -13
- package/dist/context/runtime-context-consumer.js +0 -18
- package/dist/item-loader.d.ts +0 -44
- package/dist/item-loader.js +0 -61
- package/dist/policy/core/engine-context.d.ts +0 -29
- package/dist/policy/core/engine-context.js +0 -27
- package/dist/policy/core/policy-source-tag.d.ts +0 -31
- package/dist/policy/core/policy-source-tag.js +0 -28
- package/dist/policy/internal.d.ts +0 -25
- package/dist/policy/internal.js +0 -25
- package/dist/runtime/adapter/coordinator-bridge.d.ts +0 -92
- package/dist/runtime/adapter/coordinator-bridge.js +0 -126
- package/dist/runtime/adapter/framework-error-bridge.d.ts +0 -36
- package/dist/runtime/adapter/framework-error-bridge.js +0 -46
- package/dist/runtime/adapter/instrumentation-bridge.d.ts +0 -31
- package/dist/runtime/adapter/instrumentation-bridge.js +0 -38
- package/dist/runtime/core/engine-stage-derivation.d.ts +0 -18
- package/dist/runtime/core/engine-stage-derivation.js +0 -29
- package/dist/runtime/engine-context.d.ts +0 -39
- package/dist/runtime/engine-context.js +0 -31
- package/dist/runtime/internal.d.ts +0 -43
- package/dist/runtime/internal.js +0 -45
- package/dist/runtime/section-runtime-engine-host-context.d.ts +0 -74
- package/dist/runtime/section-runtime-engine-host-context.js +0 -57
- package/dist/runtime/stage-emit-gate.d.ts +0 -92
- package/dist/runtime/stage-emit-gate.js +0 -82
- package/dist/services/I18nService.d.ts +0 -47
- package/dist/services/I18nService.js +0 -84
- package/dist/services/ThemeProvider.d.ts +0 -95
- package/dist/services/ThemeProvider.js +0 -334
- package/dist/services/defaultPersonalNeedsProfile.d.ts +0 -21
- package/dist/services/defaultPersonalNeedsProfile.js +0 -26
- package/dist/services/pnp-standard-features.d.ts +0 -238
- package/dist/services/pnp-standard-features.js +0 -338
- package/dist/tools/client.d.ts +0 -10
- package/dist/tools/client.js +0 -10
- package/dist/tools/internal.d.ts +0 -44
- package/dist/tools/internal.js +0 -39
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ToolCoordinator
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Prevents conflicts between calculator, ruler, protractor, etc.
|
|
4
|
+
* Holds the visibility state of floating tools and stacks their elements.
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
6
|
+
* Visibility is state: the coordinator records it and notifies subscribers, and
|
|
7
|
+
* whoever renders a tool shows or hides it from that state. Stacking is the
|
|
8
|
+
* coordinator's alone: an element bound to a tool (`registerTool` with an
|
|
9
|
+
* element, or `updateToolElement`) takes a z-index in the tool's layer and comes
|
|
10
|
+
* to the front of that layer when shown or pressed.
|
|
12
11
|
*
|
|
13
12
|
* Part of PIE Assessment Toolkit.
|
|
14
13
|
*/
|
|
15
14
|
import { createLogger } from "../utils/logger.js";
|
|
15
|
+
import { parseScopedToolId } from "./tool-instance-id.js";
|
|
16
16
|
const log = createLogger("ToolCoordinator");
|
|
17
17
|
/**
|
|
18
18
|
* Z-index layers for assessment components
|
|
@@ -25,27 +25,23 @@ export var ZIndexLayer;
|
|
|
25
25
|
ZIndexLayer[ZIndexLayer["CONTROL"] = 3000] = "CONTROL";
|
|
26
26
|
ZIndexLayer[ZIndexLayer["HIGHLIGHT"] = 4000] = "HIGHLIGHT";
|
|
27
27
|
})(ZIndexLayer || (ZIndexLayer = {}));
|
|
28
|
+
function matchesFilter(id, filter) {
|
|
29
|
+
if (!filter?.baseId)
|
|
30
|
+
return true;
|
|
31
|
+
return (parseScopedToolId(id)?.baseToolId ?? id) === filter.baseId;
|
|
32
|
+
}
|
|
33
|
+
function toToolState(entry) {
|
|
34
|
+
return {
|
|
35
|
+
id: entry.id,
|
|
36
|
+
name: entry.name,
|
|
37
|
+
isVisible: entry.isVisible,
|
|
38
|
+
element: entry.element,
|
|
39
|
+
layer: entry.layer,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
28
42
|
export class ToolCoordinator {
|
|
29
43
|
tools = new Map();
|
|
30
|
-
layerCounters = new Map();
|
|
31
44
|
listeners = new Set();
|
|
32
|
-
/**
|
|
33
|
-
* Activation (on/off) state keyed by tool id, kept independent of the
|
|
34
|
-
* element registration lifecycle. A tool's DOM element can be unregistered
|
|
35
|
-
* and re-registered as the item re-renders (e.g. a model change re-mounts
|
|
36
|
-
* the toolbar overlay); when that happens the on/off state must survive so
|
|
37
|
-
* that only an explicit toggle — the toolbar button — turns a tool off.
|
|
38
|
-
* Cleared on genuine teardown via {@link releaseTool}.
|
|
39
|
-
*/
|
|
40
|
-
visibilityState = new Map();
|
|
41
|
-
constructor() {
|
|
42
|
-
// Initialize layer counters
|
|
43
|
-
this.layerCounters.set(ZIndexLayer.BASE, 0);
|
|
44
|
-
this.layerCounters.set(ZIndexLayer.TOOL, 0);
|
|
45
|
-
this.layerCounters.set(ZIndexLayer.MODAL, 0);
|
|
46
|
-
this.layerCounters.set(ZIndexLayer.CONTROL, 0);
|
|
47
|
-
this.layerCounters.set(ZIndexLayer.HIGHLIGHT, 0);
|
|
48
|
-
}
|
|
49
45
|
/**
|
|
50
46
|
* Subscribe to tool state changes
|
|
51
47
|
* Returns unsubscribe function
|
|
@@ -56,99 +52,89 @@ export class ToolCoordinator {
|
|
|
56
52
|
this.listeners.delete(listener);
|
|
57
53
|
};
|
|
58
54
|
}
|
|
59
|
-
/**
|
|
60
|
-
* Notify all listeners of state change
|
|
61
|
-
*/
|
|
62
55
|
notifyListeners() {
|
|
63
|
-
this.listeners
|
|
56
|
+
for (const listener of this.listeners) {
|
|
57
|
+
try {
|
|
58
|
+
listener();
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
console.warn("[ToolCoordinator] listener failed:", error);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
|
-
* Register a tool with the coordinator
|
|
66
|
+
* Register a tool with the coordinator. Registering a known id keeps its
|
|
67
|
+
* on/off state and takes the name, the element when one is given, and the
|
|
68
|
+
* layer when none was declared before.
|
|
67
69
|
*
|
|
68
70
|
* @param id Unique tool identifier
|
|
69
71
|
* @param name Display name
|
|
70
|
-
* @param element DOM element
|
|
71
|
-
* @param layer Z-index layer
|
|
72
|
+
* @param element DOM element to stack (optional)
|
|
73
|
+
* @param layer Z-index layer. Without one the tool stacks on TOOL until a
|
|
74
|
+
* registration names one.
|
|
72
75
|
*/
|
|
73
|
-
registerTool(id, name, element, layer
|
|
76
|
+
registerTool(id, name, element, layer) {
|
|
74
77
|
log("registerTool called:", { id, name, hasElement: !!element, layer });
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
let entry = this.tools.get(id);
|
|
79
|
+
if (entry) {
|
|
80
|
+
entry.name = name;
|
|
81
|
+
const wasRegistered = entry.registered;
|
|
82
|
+
entry.registered = true;
|
|
83
|
+
if (layer !== undefined && !entry.layerDeclared) {
|
|
84
|
+
entry.layer = layer;
|
|
85
|
+
entry.layerDeclared = true;
|
|
86
|
+
this.stackOnTop(entry);
|
|
87
|
+
}
|
|
88
|
+
else if (!wasRegistered) {
|
|
89
|
+
this.stackOnTop(entry);
|
|
90
|
+
}
|
|
78
91
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
// tool's activation state so only an explicit toggle can turn it off.
|
|
82
|
-
const isVisible = this.visibilityState.get(id) ?? false;
|
|
83
|
-
// If no element provided, create a placeholder registration
|
|
84
|
-
if (!element) {
|
|
85
|
-
this.tools.set(id, {
|
|
92
|
+
else {
|
|
93
|
+
entry = {
|
|
86
94
|
id,
|
|
87
95
|
name,
|
|
96
|
+
registered: true,
|
|
88
97
|
element: null,
|
|
89
|
-
layer,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
layer: layer ?? ZIndexLayer.TOOL,
|
|
99
|
+
layerDeclared: layer !== undefined,
|
|
100
|
+
isVisible: false,
|
|
101
|
+
baseZIndex: 0,
|
|
102
|
+
};
|
|
103
|
+
this.tools.set(id, entry);
|
|
104
|
+
this.stackOnTop(entry);
|
|
95
105
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// Apply z-index
|
|
99
|
-
element.style.zIndex = String(baseZIndex);
|
|
100
|
-
// Reflect restored visibility onto the freshly registered element.
|
|
101
|
-
element.style.display = isVisible ? "" : "none";
|
|
102
|
-
// Create and store event handler to enable proper cleanup
|
|
103
|
-
const mouseDownHandler = () => this.bringToFront(element);
|
|
104
|
-
element.addEventListener("mousedown", mouseDownHandler);
|
|
105
|
-
// Register tool with handler reference
|
|
106
|
-
this.tools.set(id, {
|
|
107
|
-
id,
|
|
108
|
-
name,
|
|
109
|
-
element,
|
|
110
|
-
layer,
|
|
111
|
-
isVisible,
|
|
112
|
-
baseZIndex,
|
|
113
|
-
mouseDownHandler,
|
|
114
|
-
});
|
|
115
|
-
if (isVisible) {
|
|
116
|
-
this.bringToFront(element);
|
|
117
|
-
}
|
|
118
|
-
log("Tool registered with element:", id);
|
|
106
|
+
if (element)
|
|
107
|
+
this.updateToolElement(id, element);
|
|
119
108
|
}
|
|
120
109
|
/**
|
|
121
|
-
* Unregister a tool
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
* preserves the tool's activation state in {@link visibilityState}, so a
|
|
125
|
-
* subsequent re-registration of the same id (e.g. after an item re-render)
|
|
126
|
-
* restores whether the tool was on or off. Use {@link releaseTool} to also
|
|
127
|
-
* discard the activation state on genuine teardown.
|
|
110
|
+
* Unregister a tool's element binding, keeping its on/off state so a
|
|
111
|
+
* re-registration of the same id (an item re-render) restores it. Use
|
|
112
|
+
* {@link releaseTool} on genuine teardown.
|
|
128
113
|
*
|
|
129
114
|
* @param id Tool identifier
|
|
130
115
|
*/
|
|
131
116
|
unregisterTool(id) {
|
|
132
|
-
const
|
|
133
|
-
if (!
|
|
117
|
+
const entry = this.tools.get(id);
|
|
118
|
+
if (!entry?.registered)
|
|
134
119
|
return;
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
tool.element.removeEventListener("mousedown", tool.mouseDownHandler);
|
|
138
|
-
}
|
|
139
|
-
this.tools.delete(id);
|
|
120
|
+
this.detachElement(entry);
|
|
121
|
+
entry.registered = false;
|
|
140
122
|
}
|
|
141
123
|
/**
|
|
142
|
-
* Fully release a tool: unregister its element binding
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
* which keeps the on/off state alive across element re-registration.
|
|
124
|
+
* Fully release a tool: unregister its element binding and discard its
|
|
125
|
+
* on/off state. Call this on genuine teardown (leaving the item or section
|
|
126
|
+
* that owns the tool).
|
|
146
127
|
*
|
|
147
128
|
* @param id Tool identifier
|
|
148
129
|
*/
|
|
149
130
|
releaseTool(id) {
|
|
150
|
-
this.
|
|
151
|
-
|
|
131
|
+
const entry = this.tools.get(id);
|
|
132
|
+
if (!entry)
|
|
133
|
+
return;
|
|
134
|
+
this.detachElement(entry);
|
|
135
|
+
this.tools.delete(id);
|
|
136
|
+
if (entry.isVisible)
|
|
137
|
+
this.notifyListeners();
|
|
152
138
|
}
|
|
153
139
|
/**
|
|
154
140
|
* Show a tool
|
|
@@ -156,18 +142,14 @@ export class ToolCoordinator {
|
|
|
156
142
|
* @param id Tool identifier
|
|
157
143
|
*/
|
|
158
144
|
showTool(id) {
|
|
159
|
-
const
|
|
160
|
-
if (!
|
|
145
|
+
const entry = this.tools.get(id);
|
|
146
|
+
if (!entry) {
|
|
161
147
|
log(`Tool ${id} not found`);
|
|
162
148
|
return;
|
|
163
149
|
}
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
tool.isVisible = true;
|
|
169
|
-
this.visibilityState.set(id, true);
|
|
170
|
-
this.notifyListeners();
|
|
150
|
+
if (entry.element)
|
|
151
|
+
this.bringToFront(entry.element);
|
|
152
|
+
this.setVisible(entry, true);
|
|
171
153
|
}
|
|
172
154
|
/**
|
|
173
155
|
* Hide a tool
|
|
@@ -175,17 +157,12 @@ export class ToolCoordinator {
|
|
|
175
157
|
* @param id Tool identifier
|
|
176
158
|
*/
|
|
177
159
|
hideTool(id) {
|
|
178
|
-
const
|
|
179
|
-
if (!
|
|
160
|
+
const entry = this.tools.get(id);
|
|
161
|
+
if (!entry) {
|
|
180
162
|
log(`Tool ${id} not found`);
|
|
181
163
|
return;
|
|
182
164
|
}
|
|
183
|
-
|
|
184
|
-
tool.element.style.display = "none";
|
|
185
|
-
}
|
|
186
|
-
tool.isVisible = false;
|
|
187
|
-
this.visibilityState.set(id, false);
|
|
188
|
-
this.notifyListeners();
|
|
165
|
+
this.setVisible(entry, false);
|
|
189
166
|
}
|
|
190
167
|
/**
|
|
191
168
|
* Toggle tool visibility
|
|
@@ -193,14 +170,12 @@ export class ToolCoordinator {
|
|
|
193
170
|
* @param id Tool identifier
|
|
194
171
|
*/
|
|
195
172
|
toggleTool(id) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
log(`Tool ${id} not found. Registered tools:`, Array.from(this.tools.keys()));
|
|
173
|
+
const entry = this.tools.get(id);
|
|
174
|
+
if (!entry) {
|
|
175
|
+
log(`Tool ${id} not found`);
|
|
200
176
|
return;
|
|
201
177
|
}
|
|
202
|
-
|
|
203
|
-
if (tool.isVisible) {
|
|
178
|
+
if (entry.isVisible) {
|
|
204
179
|
this.hideTool(id);
|
|
205
180
|
}
|
|
206
181
|
else {
|
|
@@ -211,39 +186,29 @@ export class ToolCoordinator {
|
|
|
211
186
|
* Check if tool is visible
|
|
212
187
|
*
|
|
213
188
|
* @param id Tool identifier
|
|
214
|
-
* @returns true if tool is visible
|
|
215
189
|
*/
|
|
216
190
|
isToolVisible(id) {
|
|
217
|
-
|
|
218
|
-
if (tool)
|
|
219
|
-
return tool.isVisible;
|
|
220
|
-
// No live element registration (e.g. mid re-render, between unmount and
|
|
221
|
-
// re-mount): fall back to the preserved activation state so the tool
|
|
222
|
-
// doesn't read as "off" during the gap.
|
|
223
|
-
return this.visibilityState.get(id) ?? false;
|
|
191
|
+
return this.tools.get(id)?.isVisible ?? false;
|
|
224
192
|
}
|
|
225
193
|
/**
|
|
226
|
-
* Bring element to front of its layer
|
|
194
|
+
* Bring a bound element to the front of its tool's layer. An element no tool
|
|
195
|
+
* is bound to is left alone.
|
|
227
196
|
*
|
|
228
197
|
* @param element DOM element to bring forward
|
|
229
198
|
*/
|
|
230
199
|
bringToFront(element) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (!tool)
|
|
200
|
+
const entry = Array.from(this.tools.values()).find((t) => t.element === element);
|
|
201
|
+
if (!entry)
|
|
234
202
|
return;
|
|
235
|
-
|
|
236
|
-
const maxZIndexInLayer = this.getMaxZIndexInLayer(tool.layer);
|
|
237
|
-
const newZIndex = Math.max(maxZIndexInLayer + 1, tool.layer + 1);
|
|
238
|
-
// Update z-index
|
|
239
|
-
element.style.zIndex = String(newZIndex);
|
|
240
|
-
tool.baseZIndex = newZIndex;
|
|
203
|
+
this.stackOnTop(entry);
|
|
241
204
|
}
|
|
242
205
|
/**
|
|
243
|
-
*
|
|
206
|
+
* Ids of the tools an element registration currently holds.
|
|
244
207
|
*/
|
|
245
208
|
getRegisteredTools() {
|
|
246
|
-
return Array.from(this.tools.
|
|
209
|
+
return Array.from(this.tools.values())
|
|
210
|
+
.filter((entry) => entry.registered)
|
|
211
|
+
.map((entry) => entry.id);
|
|
247
212
|
}
|
|
248
213
|
/**
|
|
249
214
|
* Get tool element by ID
|
|
@@ -251,108 +216,101 @@ export class ToolCoordinator {
|
|
|
251
216
|
getToolElement(id) {
|
|
252
217
|
return this.tools.get(id)?.element ?? null;
|
|
253
218
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
this.layerCounters.set(layer, current + 1);
|
|
260
|
-
return current;
|
|
219
|
+
setVisible(entry, visible) {
|
|
220
|
+
if (entry.isVisible === visible)
|
|
221
|
+
return;
|
|
222
|
+
entry.isVisible = visible;
|
|
223
|
+
this.notifyListeners();
|
|
261
224
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
getMaxZIndexInLayer(layer) {
|
|
266
|
-
let max = layer;
|
|
267
|
-
for (const tool of this.tools.values()) {
|
|
268
|
-
if (tool.layer === layer) {
|
|
269
|
-
max = Math.max(max, tool.baseZIndex);
|
|
270
|
-
}
|
|
225
|
+
detachElement(entry) {
|
|
226
|
+
if (entry.element && entry.mouseDownHandler) {
|
|
227
|
+
entry.element.removeEventListener("mousedown", entry.mouseDownHandler);
|
|
271
228
|
}
|
|
272
|
-
|
|
229
|
+
entry.element = null;
|
|
230
|
+
entry.mouseDownHandler = undefined;
|
|
273
231
|
}
|
|
274
232
|
/**
|
|
275
|
-
*
|
|
233
|
+
* Put `entry` in front of its layer. The layer is renumbered from its base on
|
|
234
|
+
* every move, so its z-indices stay within it however often tools are raised.
|
|
276
235
|
*/
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
236
|
+
stackOnTop(entry) {
|
|
237
|
+
const others = Array.from(this.tools.values())
|
|
238
|
+
.filter((other) => other.registered && other.layer === entry.layer && other !== entry)
|
|
239
|
+
.sort((a, b) => a.baseZIndex - b.baseZIndex);
|
|
240
|
+
const top = entry.layer + others.length + 1;
|
|
241
|
+
if (entry.baseZIndex === top &&
|
|
242
|
+
others.every((other) => other.baseZIndex < top)) {
|
|
243
|
+
return;
|
|
282
244
|
}
|
|
245
|
+
[...others, entry].forEach((stacked, index) => {
|
|
246
|
+
stacked.baseZIndex = entry.layer + 1 + index;
|
|
247
|
+
if (stacked.element) {
|
|
248
|
+
stacked.element.style.zIndex = String(stacked.baseZIndex);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
283
251
|
}
|
|
284
252
|
/**
|
|
285
|
-
*
|
|
253
|
+
* Bind the element a tool stacks by. It takes the tool's z-index and comes to
|
|
254
|
+
* the front of the layer when pressed, and when bound while the tool is shown.
|
|
255
|
+
*
|
|
256
|
+
* The outermost element stacks: binding an element inside the bound one keeps
|
|
257
|
+
* the binding, so a tool rendered inside a toolbar's floating window stacks
|
|
258
|
+
* by that window whichever binds first.
|
|
286
259
|
*
|
|
287
260
|
* @param id Tool identifier
|
|
288
261
|
* @param element New DOM element
|
|
289
262
|
*/
|
|
290
263
|
updateToolElement(id, element) {
|
|
291
|
-
const
|
|
292
|
-
if (!
|
|
264
|
+
const entry = this.tools.get(id);
|
|
265
|
+
if (!entry?.registered) {
|
|
293
266
|
log(`Tool ${id} not found`);
|
|
294
267
|
return;
|
|
295
268
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
269
|
+
if (entry.element === element)
|
|
270
|
+
return;
|
|
271
|
+
if (entry.element?.isConnected && entry.element.contains(element))
|
|
272
|
+
return;
|
|
273
|
+
this.detachElement(entry);
|
|
301
274
|
const mouseDownHandler = () => this.bringToFront(element);
|
|
302
275
|
element.addEventListener("mousedown", mouseDownHandler);
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
if (tool.isVisible) {
|
|
309
|
-
element.style.display = "";
|
|
310
|
-
}
|
|
311
|
-
else {
|
|
312
|
-
element.style.display = "none";
|
|
313
|
-
}
|
|
276
|
+
entry.element = element;
|
|
277
|
+
entry.mouseDownHandler = mouseDownHandler;
|
|
278
|
+
element.style.zIndex = String(entry.baseZIndex);
|
|
279
|
+
if (entry.isVisible)
|
|
280
|
+
this.bringToFront(element);
|
|
314
281
|
}
|
|
315
282
|
/**
|
|
316
|
-
* Hide
|
|
283
|
+
* Hide every visible tool, or every instance of one tool with
|
|
284
|
+
* `{ baseId }`, notifying subscribers once.
|
|
317
285
|
*/
|
|
318
|
-
hideAllTools() {
|
|
319
|
-
|
|
320
|
-
|
|
286
|
+
hideAllTools(filter) {
|
|
287
|
+
let changed = false;
|
|
288
|
+
for (const entry of this.tools.values()) {
|
|
289
|
+
if (!entry.isVisible || !matchesFilter(entry.id, filter))
|
|
290
|
+
continue;
|
|
291
|
+
entry.isVisible = false;
|
|
292
|
+
changed = true;
|
|
321
293
|
}
|
|
322
|
-
|
|
294
|
+
if (changed)
|
|
295
|
+
this.notifyListeners();
|
|
323
296
|
}
|
|
324
297
|
/**
|
|
325
|
-
*
|
|
298
|
+
* State of a tool an element registration holds.
|
|
326
299
|
*
|
|
327
300
|
* @param id Tool identifier
|
|
328
|
-
* @returns Tool state or undefined
|
|
329
301
|
*/
|
|
330
302
|
getToolState(id) {
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
return undefined;
|
|
334
|
-
return {
|
|
335
|
-
id: tool.id,
|
|
336
|
-
name: tool.name,
|
|
337
|
-
isVisible: tool.isVisible,
|
|
338
|
-
element: tool.element ?? null,
|
|
339
|
-
layer: tool.layer,
|
|
340
|
-
};
|
|
303
|
+
const entry = this.tools.get(id);
|
|
304
|
+
return entry?.registered ? toToolState(entry) : undefined;
|
|
341
305
|
}
|
|
342
306
|
/**
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
* @
|
|
307
|
+
* Every visible tool, or every visible instance of one tool with
|
|
308
|
+
* `{ baseId }`. A tool shown while its element re-renders counts, as
|
|
309
|
+
* {@link isToolVisible} counts it.
|
|
346
310
|
*/
|
|
347
|
-
getVisibleTools() {
|
|
311
|
+
getVisibleTools(filter) {
|
|
348
312
|
return Array.from(this.tools.values())
|
|
349
|
-
.filter((
|
|
350
|
-
.map(
|
|
351
|
-
id: tool.id,
|
|
352
|
-
name: tool.name,
|
|
353
|
-
isVisible: tool.isVisible,
|
|
354
|
-
element: tool.element ?? null,
|
|
355
|
-
layer: tool.layer,
|
|
356
|
-
}));
|
|
313
|
+
.filter((entry) => entry.isVisible && matchesFilter(entry.id, filter))
|
|
314
|
+
.map(toToolState);
|
|
357
315
|
}
|
|
358
316
|
}
|