@pie-players/pie-assessment-toolkit 0.3.74 → 1.0.0-beta.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/README.md +658 -714
- package/custom-elements.json +1315 -0
- package/dist/attempt/TestSession.d.ts +1 -21
- package/dist/attempt/TestSession.js +16 -102
- 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-3zrc4p3d.js +4 -0
- package/dist/components/chunks/ItemToolBar-66hcwmfw.js +2 -0
- package/dist/components/chunks/ItemToolBar-9gqhfxtn.js +40 -0
- package/dist/components/chunks/ItemToolBar-hzc5wyjp.js +2 -0
- package/dist/components/chunks/{ItemToolBar-gmrryv2v.js → ItemToolBar-kkj69ptr.js} +1 -1
- package/dist/components/chunks/ItemToolBar-vdkyn9f3.js +2 -0
- package/dist/components/chunks/sre-engine-bj997w4b.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 +33 -6
- package/dist/index.d.ts +25 -50
- package/dist/index.js +15 -45
- package/dist/policy/core/PolicySource.d.ts +2 -2
- package/dist/policy/core/ToolPolicyEngine.d.ts +118 -34
- package/dist/policy/core/ToolPolicyEngine.js +203 -56
- package/dist/policy/core/compose-decision.d.ts +28 -7
- package/dist/policy/core/compose-decision.js +95 -74
- package/dist/policy/core/decision-types.d.ts +98 -55
- package/dist/policy/core/feature-decision.d.ts +28 -19
- package/dist/policy/core/feature-decision.js +15 -11
- package/dist/policy/core/pnp-policy-inputs.d.ts +29 -35
- package/dist/policy/core/pnp-policy-inputs.js +40 -88
- package/dist/policy/core/provenance.d.ts +10 -5
- package/dist/policy/core/provenance.js +1 -1
- package/dist/policy/core/tool-parameters.d.ts +11 -0
- package/dist/policy/core/tool-parameters.js +15 -0
- package/dist/policy/engine.d.ts +7 -23
- package/dist/policy/engine.js +5 -20
- package/dist/policy/sources/PnpPolicySource.d.ts +43 -68
- package/dist/policy/sources/PnpPolicySource.js +133 -132
- package/dist/runtime/SectionControllerBinding.d.ts +283 -0
- package/dist/runtime/SectionControllerBinding.js +456 -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 -3
- package/dist/runtime/adapter/subscriber-fanout.js +2 -6
- 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 +12 -18
- package/dist/runtime/composition-emit-scheduler.js +10 -16
- package/dist/runtime/content-language.d.ts +32 -0
- package/dist/runtime/content-language.js +46 -0
- package/dist/runtime/content-region.d.ts +13 -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 -4
- package/dist/runtime/core/SectionEngineCore.js +2 -6
- package/dist/runtime/core/cohort.d.ts +1 -6
- package/dist/runtime/core/cohort.js +1 -10
- 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 +17 -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 +74 -53
- 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 +22 -14
- package/dist/runtime/runtime-event-claim.d.ts +8 -0
- package/dist/runtime/runtime-event-claim.js +15 -0
- package/dist/runtime/runtime-id.d.ts +1 -1
- package/dist/runtime/runtime-id.js +1 -1
- 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 +194 -0
- package/dist/runtime/tool-host-contract.d.ts +8 -14
- package/dist/runtime/tool-host-contract.js +12 -12
- package/dist/runtime/unclaimed-registration-watch.d.ts +7 -0
- package/dist/runtime/unclaimed-registration-watch.js +23 -0
- package/dist/services/AccessibilityCatalogResolver.d.ts +21 -31
- package/dist/services/AccessibilityCatalogResolver.js +29 -42
- package/dist/services/ElementToolStateStore.d.ts +42 -67
- package/dist/services/ElementToolStateStore.js +65 -71
- package/dist/services/HighlightCoordinator.d.ts +28 -40
- package/dist/services/HighlightCoordinator.js +459 -381
- package/dist/services/RangeSerializer.d.ts +11 -33
- package/dist/services/RangeSerializer.js +88 -59
- package/dist/services/SSMLExtractor.d.ts +8 -31
- package/dist/services/SSMLExtractor.js +18 -40
- package/dist/services/TTSService.d.ts +159 -119
- package/dist/services/TTSService.js +937 -822
- package/dist/services/ToolCoordinator.d.ts +42 -102
- package/dist/services/ToolCoordinator.js +178 -256
- package/dist/services/ToolRegistry.d.ts +152 -133
- package/dist/services/ToolRegistry.js +192 -178
- package/dist/services/ToolkitCoordinator.d.ts +233 -237
- package/dist/services/ToolkitCoordinator.js +615 -557
- 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 +51 -13
- package/dist/services/framework-error.js +19 -20
- package/dist/services/interfaces.d.ts +189 -184
- package/dist/services/section-controller-types.d.ts +7 -7
- package/dist/services/section-session-assignment.d.ts +21 -0
- package/dist/services/section-session-assignment.js +80 -0
- package/dist/services/spoken-audio-cards.d.ts +2 -6
- package/dist/services/spoken-audio-cards.js +2 -6
- 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 +9 -12
- package/dist/services/tool-config-validation.js +47 -87
- package/dist/services/tool-context.d.ts +7 -31
- package/dist/services/tool-context.js +99 -65
- package/dist/services/tool-failure.d.ts +30 -0
- package/dist/services/tool-failure.js +11 -0
- package/dist/services/tool-icons.d.ts +5 -5
- package/dist/services/tool-icons.js +6 -5
- package/dist/services/tool-instance-id.d.ts +8 -7
- package/dist/services/tool-instance-id.js +12 -24
- package/dist/services/tool-providers/TTSToolProvider.d.ts +20 -58
- package/dist/services/tool-providers/TTSToolProvider.js +32 -85
- package/dist/services/tool-providers/ToolProviderApi.d.ts +10 -11
- package/dist/services/tool-providers/ToolProviderRegistry.d.ts +29 -60
- package/dist/services/tool-providers/ToolProviderRegistry.js +128 -144
- package/dist/services/tool-request.d.ts +31 -12
- package/dist/services/tool-request.js +31 -16
- package/dist/services/toolbar-decided-tools.d.ts +16 -0
- package/dist/services/toolbar-decided-tools.js +29 -0
- package/dist/services/toolbar-items.js +2 -5
- package/dist/services/tools-config-normalizer.d.ts +33 -29
- package/dist/services/tools-config-normalizer.js +26 -28
- package/dist/services/tts/browser-provider.d.ts +39 -6
- package/dist/services/tts/browser-provider.js +280 -160
- package/dist/services/tts/catalog-span-alignment.js +14 -7
- package/dist/services/tts/flat-tree.d.ts +64 -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/dom/to-chunk-inputs.d.ts +2 -2
- package/dist/services/tts/generated-speech/index.d.ts +1 -1
- package/dist/services/tts/generated-speech/index.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/generated-speech/types.d.ts +1 -1
- package/dist/services/tts/generated-speech/types.js +1 -1
- package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +22 -16
- 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/highlight-target-resolver.d.ts +12 -0
- package/dist/services/tts/math-aware-text-processing.d.ts +5 -1
- package/dist/services/tts/math-aware-text-processing.js +42 -47
- 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 +12 -1
- package/dist/services/tts/math-speech.js +54 -18
- package/dist/services/tts/mathml-sanitization.d.ts +7 -0
- package/dist/services/tts/mathml-sanitization.js +9 -1
- package/dist/services/tts/provider-options.d.ts +52 -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 +4 -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 +12 -0
- package/dist/services/tts/text-segmentation.js +60 -10
- package/dist/services/tts-runtime-config.d.ts +54 -26
- package/dist/services/tts-runtime-config.js +27 -112
- package/dist/tools/content-capability-resolution.d.ts +9 -11
- package/dist/tools/content-capability-resolution.js +8 -45
- package/dist/tools/registration.d.ts +59 -0
- package/dist/tools/registration.js +55 -0
- package/dist/tools/registrations/toolbar-registration-helpers.d.ts +6 -0
- package/dist/tools/registrations/toolbar-registration-helpers.js +8 -2
- package/dist/tools/tool-surface-host.d.ts +6 -10
- package/dist/tools/tool-surface-host.js +45 -50
- 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 +15 -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/ContextVariableStore.d.ts +0 -113
- package/dist/services/ContextVariableStore.js +0 -206
- 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/services/tts-control-events.d.ts +0 -13
- package/dist/services/tts-control-events.js +0 -7
- 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
- package/dist/utils/logger.d.ts +0 -6
- package/dist/utils/logger.js +0 -10
|
@@ -1,19 +1,17 @@
|
|
|
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
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* Part of PIE Assessment Toolkit.
|
|
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.
|
|
14
11
|
*/
|
|
15
|
-
import {
|
|
16
|
-
|
|
12
|
+
import { createPieLogger, isGlobalDebugEnabled, } from "@pie-players/pie-players-shared/pie";
|
|
13
|
+
import { parseScopedToolId } from "./tool-instance-id.js";
|
|
14
|
+
const logger = createPieLogger("ToolCoordinator", isGlobalDebugEnabled);
|
|
17
15
|
/**
|
|
18
16
|
* Z-index layers for assessment components
|
|
19
17
|
*/
|
|
@@ -25,27 +23,23 @@ export var ZIndexLayer;
|
|
|
25
23
|
ZIndexLayer[ZIndexLayer["CONTROL"] = 3000] = "CONTROL";
|
|
26
24
|
ZIndexLayer[ZIndexLayer["HIGHLIGHT"] = 4000] = "HIGHLIGHT";
|
|
27
25
|
})(ZIndexLayer || (ZIndexLayer = {}));
|
|
26
|
+
function matchesFilter(id, filter) {
|
|
27
|
+
if (!filter?.baseId)
|
|
28
|
+
return true;
|
|
29
|
+
return (parseScopedToolId(id)?.baseToolId ?? id) === filter.baseId;
|
|
30
|
+
}
|
|
31
|
+
function toToolState(entry) {
|
|
32
|
+
return {
|
|
33
|
+
id: entry.id,
|
|
34
|
+
name: entry.name,
|
|
35
|
+
isVisible: entry.isVisible,
|
|
36
|
+
element: entry.element,
|
|
37
|
+
layer: entry.layer,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
28
40
|
export class ToolCoordinator {
|
|
29
41
|
tools = new Map();
|
|
30
|
-
layerCounters = new Map();
|
|
31
42
|
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
43
|
/**
|
|
50
44
|
* Subscribe to tool state changes
|
|
51
45
|
* Returns unsubscribe function
|
|
@@ -56,303 +50,231 @@ export class ToolCoordinator {
|
|
|
56
50
|
this.listeners.delete(listener);
|
|
57
51
|
};
|
|
58
52
|
}
|
|
59
|
-
/**
|
|
60
|
-
* Notify all listeners of state change
|
|
61
|
-
*/
|
|
62
53
|
notifyListeners() {
|
|
63
|
-
this.listeners
|
|
54
|
+
for (const listener of this.listeners) {
|
|
55
|
+
try {
|
|
56
|
+
listener();
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
console.warn("[ToolCoordinator] listener failed:", error);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
64
62
|
}
|
|
65
63
|
/**
|
|
66
|
-
* Register a tool with the coordinator
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* @param element DOM element for the tool (optional)
|
|
71
|
-
* @param layer Z-index layer (defaults to MODAL)
|
|
64
|
+
* Register a tool with the coordinator. Registering a known id keeps its
|
|
65
|
+
* on/off state and takes the name, the element when one is given, and the
|
|
66
|
+
* layer when none was declared before. Without a `layer` the tool stacks on
|
|
67
|
+
* TOOL until a registration names one.
|
|
72
68
|
*/
|
|
73
|
-
registerTool(id, name, element, layer
|
|
74
|
-
|
|
75
|
-
if (this.tools.has(id)) {
|
|
76
|
-
log(`Tool ${id} is already registered`);
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
// Restore prior on/off state. A re-registration (e.g. after an item
|
|
80
|
-
// re-render unmounts and re-mounts the tool element) must preserve the
|
|
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, {
|
|
86
|
-
id,
|
|
87
|
-
name,
|
|
88
|
-
element: null,
|
|
89
|
-
layer,
|
|
90
|
-
isVisible,
|
|
91
|
-
baseZIndex: layer,
|
|
92
|
-
});
|
|
93
|
-
log("Tool registered without element:", id);
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
// Calculate base z-index for this layer
|
|
97
|
-
const baseZIndex = layer + this.getNextLayerOffset(layer);
|
|
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, {
|
|
69
|
+
registerTool(id, name, element, layer) {
|
|
70
|
+
logger.debug("registerTool called:", {
|
|
107
71
|
id,
|
|
108
72
|
name,
|
|
109
|
-
element,
|
|
73
|
+
hasElement: !!element,
|
|
110
74
|
layer,
|
|
111
|
-
isVisible,
|
|
112
|
-
baseZIndex,
|
|
113
|
-
mouseDownHandler,
|
|
114
75
|
});
|
|
115
|
-
|
|
116
|
-
|
|
76
|
+
let entry = this.tools.get(id);
|
|
77
|
+
if (entry) {
|
|
78
|
+
entry.name = name;
|
|
79
|
+
const wasRegistered = entry.registered;
|
|
80
|
+
entry.registered = true;
|
|
81
|
+
if (layer !== undefined && !entry.layerDeclared) {
|
|
82
|
+
entry.layer = layer;
|
|
83
|
+
entry.layerDeclared = true;
|
|
84
|
+
this.stackOnTop(entry);
|
|
85
|
+
}
|
|
86
|
+
else if (!wasRegistered) {
|
|
87
|
+
this.stackOnTop(entry);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
entry = {
|
|
92
|
+
id,
|
|
93
|
+
name,
|
|
94
|
+
registered: true,
|
|
95
|
+
element: null,
|
|
96
|
+
layer: layer ?? ZIndexLayer.TOOL,
|
|
97
|
+
layerDeclared: layer !== undefined,
|
|
98
|
+
isVisible: false,
|
|
99
|
+
baseZIndex: 0,
|
|
100
|
+
};
|
|
101
|
+
this.tools.set(id, entry);
|
|
102
|
+
this.stackOnTop(entry);
|
|
117
103
|
}
|
|
118
|
-
|
|
104
|
+
if (element)
|
|
105
|
+
this.updateToolElement(id, element);
|
|
119
106
|
}
|
|
120
107
|
/**
|
|
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.
|
|
128
|
-
*
|
|
129
|
-
* @param id Tool identifier
|
|
108
|
+
* Unregister a tool's element binding, keeping its on/off state so a
|
|
109
|
+
* re-registration of the same id (an item re-render) restores it. Use
|
|
110
|
+
* {@link releaseTool} on genuine teardown.
|
|
130
111
|
*/
|
|
131
112
|
unregisterTool(id) {
|
|
132
|
-
const
|
|
133
|
-
if (!
|
|
113
|
+
const entry = this.tools.get(id);
|
|
114
|
+
if (!entry?.registered)
|
|
134
115
|
return;
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
tool.element.removeEventListener("mousedown", tool.mouseDownHandler);
|
|
138
|
-
}
|
|
139
|
-
this.tools.delete(id);
|
|
116
|
+
this.detachElement(entry);
|
|
117
|
+
entry.registered = false;
|
|
140
118
|
}
|
|
141
119
|
/**
|
|
142
|
-
* Fully release a tool: unregister its element binding
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
* which keeps the on/off state alive across element re-registration.
|
|
146
|
-
*
|
|
147
|
-
* @param id Tool identifier
|
|
120
|
+
* Fully release a tool: unregister its element binding and discard its
|
|
121
|
+
* on/off state. Call this on genuine teardown (leaving the item or section
|
|
122
|
+
* that owns the tool).
|
|
148
123
|
*/
|
|
149
124
|
releaseTool(id) {
|
|
150
|
-
this.
|
|
151
|
-
|
|
125
|
+
const entry = this.tools.get(id);
|
|
126
|
+
if (!entry)
|
|
127
|
+
return;
|
|
128
|
+
this.detachElement(entry);
|
|
129
|
+
this.tools.delete(id);
|
|
130
|
+
if (entry.isVisible)
|
|
131
|
+
this.notifyListeners();
|
|
152
132
|
}
|
|
153
|
-
/**
|
|
154
|
-
* Show a tool
|
|
155
|
-
*
|
|
156
|
-
* @param id Tool identifier
|
|
157
|
-
*/
|
|
158
133
|
showTool(id) {
|
|
159
|
-
const
|
|
160
|
-
if (!
|
|
161
|
-
|
|
134
|
+
const entry = this.tools.get(id);
|
|
135
|
+
if (!entry) {
|
|
136
|
+
logger.debug(`Tool ${id} not found`);
|
|
162
137
|
return;
|
|
163
138
|
}
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
tool.isVisible = true;
|
|
169
|
-
this.visibilityState.set(id, true);
|
|
170
|
-
this.notifyListeners();
|
|
139
|
+
if (entry.element)
|
|
140
|
+
this.bringToFront(entry.element);
|
|
141
|
+
this.setVisible(entry, true);
|
|
171
142
|
}
|
|
172
|
-
/**
|
|
173
|
-
* Hide a tool
|
|
174
|
-
*
|
|
175
|
-
* @param id Tool identifier
|
|
176
|
-
*/
|
|
177
143
|
hideTool(id) {
|
|
178
|
-
const
|
|
179
|
-
if (!
|
|
180
|
-
|
|
144
|
+
const entry = this.tools.get(id);
|
|
145
|
+
if (!entry) {
|
|
146
|
+
logger.debug(`Tool ${id} not found`);
|
|
181
147
|
return;
|
|
182
148
|
}
|
|
183
|
-
|
|
184
|
-
tool.element.style.display = "none";
|
|
185
|
-
}
|
|
186
|
-
tool.isVisible = false;
|
|
187
|
-
this.visibilityState.set(id, false);
|
|
188
|
-
this.notifyListeners();
|
|
149
|
+
this.setVisible(entry, false);
|
|
189
150
|
}
|
|
190
|
-
/**
|
|
191
|
-
* Toggle tool visibility
|
|
192
|
-
*
|
|
193
|
-
* @param id Tool identifier
|
|
194
|
-
*/
|
|
195
151
|
toggleTool(id) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
log(`Tool ${id} not found. Registered tools:`, Array.from(this.tools.keys()));
|
|
152
|
+
const entry = this.tools.get(id);
|
|
153
|
+
if (!entry) {
|
|
154
|
+
logger.debug(`Tool ${id} not found`);
|
|
200
155
|
return;
|
|
201
156
|
}
|
|
202
|
-
|
|
203
|
-
if (tool.isVisible) {
|
|
157
|
+
if (entry.isVisible) {
|
|
204
158
|
this.hideTool(id);
|
|
205
159
|
}
|
|
206
160
|
else {
|
|
207
161
|
this.showTool(id);
|
|
208
162
|
}
|
|
209
163
|
}
|
|
210
|
-
/**
|
|
211
|
-
* Check if tool is visible
|
|
212
|
-
*
|
|
213
|
-
* @param id Tool identifier
|
|
214
|
-
* @returns true if tool is visible
|
|
215
|
-
*/
|
|
216
164
|
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;
|
|
165
|
+
return this.tools.get(id)?.isVisible ?? false;
|
|
224
166
|
}
|
|
225
167
|
/**
|
|
226
|
-
* Bring element to front of its layer
|
|
227
|
-
*
|
|
228
|
-
* @param element DOM element to bring forward
|
|
168
|
+
* Bring a bound element to the front of its tool's layer. An element no tool
|
|
169
|
+
* is bound to is left alone.
|
|
229
170
|
*/
|
|
230
171
|
bringToFront(element) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (!tool)
|
|
172
|
+
const entry = Array.from(this.tools.values()).find((t) => t.element === element);
|
|
173
|
+
if (!entry)
|
|
234
174
|
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;
|
|
241
|
-
}
|
|
242
|
-
/**
|
|
243
|
-
* Get all registered tool IDs
|
|
244
|
-
*/
|
|
245
|
-
getRegisteredTools() {
|
|
246
|
-
return Array.from(this.tools.keys());
|
|
175
|
+
this.stackOnTop(entry);
|
|
247
176
|
}
|
|
248
177
|
/**
|
|
249
|
-
*
|
|
178
|
+
* Release every tool, registered or not, and drop the subscribers. The
|
|
179
|
+
* owning toolkit coordinator calls this when it is disposed.
|
|
250
180
|
*/
|
|
251
|
-
|
|
252
|
-
|
|
181
|
+
destroy() {
|
|
182
|
+
const anyVisible = Array.from(this.tools.values()).some((entry) => entry.isVisible);
|
|
183
|
+
for (const entry of this.tools.values())
|
|
184
|
+
this.detachElement(entry);
|
|
185
|
+
this.tools.clear();
|
|
186
|
+
if (anyVisible)
|
|
187
|
+
this.notifyListeners();
|
|
188
|
+
this.listeners.clear();
|
|
253
189
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
this.layerCounters.set(layer, current + 1);
|
|
260
|
-
return current;
|
|
190
|
+
setVisible(entry, visible) {
|
|
191
|
+
if (entry.isVisible === visible)
|
|
192
|
+
return;
|
|
193
|
+
entry.isVisible = visible;
|
|
194
|
+
this.notifyListeners();
|
|
261
195
|
}
|
|
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
|
-
}
|
|
196
|
+
detachElement(entry) {
|
|
197
|
+
if (entry.element && entry.mouseDownHandler) {
|
|
198
|
+
entry.element.removeEventListener("mousedown", entry.mouseDownHandler);
|
|
271
199
|
}
|
|
272
|
-
|
|
200
|
+
entry.element = null;
|
|
201
|
+
entry.mouseDownHandler = undefined;
|
|
273
202
|
}
|
|
274
203
|
/**
|
|
275
|
-
*
|
|
204
|
+
* Put `entry` in front of its layer. The layer is renumbered from its base on
|
|
205
|
+
* every move, so its z-indices stay within it however often tools are raised.
|
|
276
206
|
*/
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
207
|
+
stackOnTop(entry) {
|
|
208
|
+
const others = Array.from(this.tools.values())
|
|
209
|
+
.filter((other) => other.registered && other.layer === entry.layer && other !== entry)
|
|
210
|
+
.sort((a, b) => a.baseZIndex - b.baseZIndex);
|
|
211
|
+
const top = entry.layer + others.length + 1;
|
|
212
|
+
if (entry.baseZIndex === top &&
|
|
213
|
+
others.every((other) => other.baseZIndex < top)) {
|
|
214
|
+
return;
|
|
282
215
|
}
|
|
216
|
+
[...others, entry].forEach((stacked, index) => {
|
|
217
|
+
stacked.baseZIndex = entry.layer + 1 + index;
|
|
218
|
+
if (stacked.element) {
|
|
219
|
+
stacked.element.style.zIndex = String(stacked.baseZIndex);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
283
222
|
}
|
|
284
223
|
/**
|
|
285
|
-
*
|
|
224
|
+
* Bind the element a tool stacks by. It takes the tool's z-index and comes to
|
|
225
|
+
* the front of the layer when pressed, and when bound while the tool is shown.
|
|
286
226
|
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
227
|
+
* The outermost element stacks: binding an element inside the bound one keeps
|
|
228
|
+
* the binding, so a tool rendered inside a toolbar's floating window stacks
|
|
229
|
+
* by that window whichever binds first.
|
|
289
230
|
*/
|
|
290
231
|
updateToolElement(id, element) {
|
|
291
|
-
const
|
|
292
|
-
if (!
|
|
293
|
-
|
|
232
|
+
const entry = this.tools.get(id);
|
|
233
|
+
if (!entry?.registered) {
|
|
234
|
+
logger.debug(`Tool ${id} not found`);
|
|
294
235
|
return;
|
|
295
236
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
237
|
+
if (entry.element === element)
|
|
238
|
+
return;
|
|
239
|
+
if (entry.element?.isConnected && entry.element.contains(element))
|
|
240
|
+
return;
|
|
241
|
+
this.detachElement(entry);
|
|
301
242
|
const mouseDownHandler = () => this.bringToFront(element);
|
|
302
243
|
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
|
-
}
|
|
244
|
+
entry.element = element;
|
|
245
|
+
entry.mouseDownHandler = mouseDownHandler;
|
|
246
|
+
element.style.zIndex = String(entry.baseZIndex);
|
|
247
|
+
if (entry.isVisible)
|
|
248
|
+
this.bringToFront(element);
|
|
314
249
|
}
|
|
315
250
|
/**
|
|
316
|
-
* Hide
|
|
251
|
+
* Hide every visible tool, or every instance of one tool with
|
|
252
|
+
* `{ baseId }`, notifying subscribers once.
|
|
317
253
|
*/
|
|
318
|
-
hideAllTools() {
|
|
319
|
-
|
|
320
|
-
|
|
254
|
+
hideAllTools(filter) {
|
|
255
|
+
let changed = false;
|
|
256
|
+
for (const entry of this.tools.values()) {
|
|
257
|
+
if (!entry.isVisible || !matchesFilter(entry.id, filter))
|
|
258
|
+
continue;
|
|
259
|
+
entry.isVisible = false;
|
|
260
|
+
changed = true;
|
|
321
261
|
}
|
|
322
|
-
|
|
262
|
+
if (changed)
|
|
263
|
+
this.notifyListeners();
|
|
323
264
|
}
|
|
324
|
-
/**
|
|
325
|
-
* Get tool state (interface method)
|
|
326
|
-
*
|
|
327
|
-
* @param id Tool identifier
|
|
328
|
-
* @returns Tool state or undefined
|
|
329
|
-
*/
|
|
265
|
+
/** State of a tool an element registration holds. */
|
|
330
266
|
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
|
-
};
|
|
267
|
+
const entry = this.tools.get(id);
|
|
268
|
+
return entry?.registered ? toToolState(entry) : undefined;
|
|
341
269
|
}
|
|
342
270
|
/**
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
* @
|
|
271
|
+
* Every visible tool, or every visible instance of one tool with
|
|
272
|
+
* `{ baseId }`. A tool shown while its element re-renders counts, as
|
|
273
|
+
* {@link isToolVisible} counts it.
|
|
346
274
|
*/
|
|
347
|
-
getVisibleTools() {
|
|
275
|
+
getVisibleTools(filter) {
|
|
348
276
|
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
|
-
}));
|
|
277
|
+
.filter((entry) => entry.isVisible && matchesFilter(entry.id, filter))
|
|
278
|
+
.map(toToolState);
|
|
357
279
|
}
|
|
358
280
|
}
|