ultravisor 1.0.3 → 1.0.8
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/.claude/launch.json +11 -0
- package/.claude/ultravisor-dev-config.json +3 -0
- package/card-audit.json +1545 -0
- package/docs/_sidebar.md +17 -0
- package/docs/css/docuserve.css +73 -0
- package/docs/features/beacon-authentication.md +209 -0
- package/docs/features/beacon-providers.md +1299 -0
- package/docs/features/beacons.md +530 -0
- package/docs/features/capabilities.md +193 -0
- package/docs/features/llm-model-setup.md +505 -0
- package/docs/features/llm.md +262 -0
- package/docs/features/tasks-content-system.md +110 -0
- package/docs/features/tasks-data-transform.md +233 -0
- package/docs/features/tasks-extension.md +36 -0
- package/docs/features/tasks-file-system.md +203 -0
- package/docs/features/tasks-flow-control.md +125 -0
- package/docs/features/tasks-http-client.md +119 -0
- package/docs/features/tasks-llm.md +118 -0
- package/docs/features/tasks-meadow-api.md +163 -0
- package/docs/features/tasks-user-interaction.md +49 -0
- package/docs/features/tasks.md +14 -0
- package/docs/index.html +1 -1
- package/docs/retold-catalog.json +1 -1
- package/docs/retold-keyword-index.json +17374 -5
- package/operation-library/api-data-pipeline.json +143 -0
- package/operation-library/beacon-remote-command.json +72 -0
- package/operation-library/conditional-file-backup.json +143 -0
- package/operation-library/config-processor.json +136 -0
- package/operation-library/csv-data-analysis.json +228 -0
- package/operation-library/csv-to-json.json +160 -0
- package/operation-library/directory-inventory.json +128 -0
- package/operation-library/expression-calculator.json +114 -0
- package/operation-library/file-search-replace.json +175 -0
- package/operation-library/git-status-report.json +368 -0
- package/operation-library/health-check-ping.json +329 -0
- package/operation-library/json-config-merge.json +313 -0
- package/operation-library/llm-embedding-tool-use.json +314 -0
- package/operation-library/llm-multi-turn-analysis.json +322 -0
- package/operation-library/llm-summarize.json +264 -0
- package/operation-library/log-line-counter.json +185 -0
- package/operation-library/meadow-crud-lifecycle.json +264 -0
- package/operation-library/npm-project-validator.json +193 -0
- package/operation-library/rest-api-orchestrator.json +218 -0
- package/operation-library/shell-system-info.json +137 -0
- package/operation-library/simple-echo.json +95 -0
- package/operation-library/template-processor.json +299 -0
- package/operation-library/text-sanitizer.json +176 -0
- package/package.json +12 -8
- package/source/Ultravisor.cjs +30 -3
- package/source/beacon/Ultravisor-Beacon-CLI.cjs +143 -0
- package/source/beacon/Ultravisor-Beacon-CapabilityProvider.cjs +129 -0
- package/source/beacon/Ultravisor-Beacon-Client.cjs +568 -0
- package/source/beacon/Ultravisor-Beacon-Executor.cjs +500 -0
- package/source/beacon/Ultravisor-Beacon-ProviderRegistry.cjs +330 -0
- package/source/beacon/providers/Ultravisor-Beacon-Provider-FileSystem.cjs +331 -0
- package/source/beacon/providers/Ultravisor-Beacon-Provider-LLM.cjs +966 -0
- package/source/beacon/providers/Ultravisor-Beacon-Provider-Shell.cjs +95 -0
- package/source/cli/Ultravisor-CLIProgram.cjs +44 -22
- package/source/cli/commands/Ultravisor-Command-SingleOperation.cjs +29 -18
- package/source/cli/commands/Ultravisor-Command-SingleTask.cjs +62 -19
- package/source/cli/commands/Ultravisor-Command-UpdateTask.cjs +27 -15
- package/source/config/Ultravisor-Default-Command-Configuration.cjs +12 -3
- package/source/services/Ultravisor-Beacon-Coordinator.cjs +966 -0
- package/source/services/Ultravisor-ExecutionEngine.cjs +1093 -0
- package/source/services/Ultravisor-ExecutionManifest.cjs +629 -0
- package/source/services/Ultravisor-Hypervisor-State.cjs +270 -97
- package/source/services/Ultravisor-Hypervisor.cjs +185 -75
- package/source/services/Ultravisor-Schedule-Persistence-Base.cjs +45 -0
- package/source/services/Ultravisor-StateManager.cjs +253 -0
- package/source/services/Ultravisor-TaskTypeRegistry.cjs +213 -0
- package/source/services/persistence/Ultravisor-Schedule-Persistence-JSONFile.cjs +140 -0
- package/source/services/tasks/Ultravisor-BuiltIn-TaskConfigs.cjs +19 -0
- package/source/services/tasks/Ultravisor-TaskHelper-BeaconDispatch.cjs +107 -0
- package/source/services/tasks/Ultravisor-TaskType-Base.cjs +125 -0
- package/source/services/tasks/content-system/Ultravisor-TaskConfigs-ContentSystem.cjs +90 -0
- package/source/services/tasks/content-system/definitions/content-create-folder.json +24 -0
- package/source/services/tasks/content-system/definitions/content-list-files.json +27 -0
- package/source/services/tasks/content-system/definitions/content-read-file.json +26 -0
- package/source/services/tasks/content-system/definitions/content-save-file.json +26 -0
- package/source/services/tasks/data-transform/Ultravisor-TaskConfigs-DataTransform.cjs +577 -0
- package/source/services/tasks/data-transform/Ultravisor-TaskType-ReplaceString.cjs +80 -0
- package/source/services/tasks/data-transform/Ultravisor-TaskType-SetValues.cjs +74 -0
- package/source/services/tasks/data-transform/Ultravisor-TaskType-StringAppender.cjs +90 -0
- package/source/services/tasks/data-transform/definitions/comprehension-intersect.json +24 -0
- package/source/services/tasks/data-transform/definitions/csv-transform.json +24 -0
- package/source/services/tasks/data-transform/definitions/expression-solver.json +20 -0
- package/source/services/tasks/data-transform/definitions/histogram.json +23 -0
- package/source/services/tasks/data-transform/definitions/parse-csv.json +27 -0
- package/source/services/tasks/data-transform/definitions/replace-string.json +27 -0
- package/source/services/tasks/data-transform/definitions/set-values.json +17 -0
- package/source/services/tasks/data-transform/definitions/string-appender.json +22 -0
- package/source/services/tasks/data-transform/definitions/template-string.json +20 -0
- package/source/services/tasks/extension/Ultravisor-TaskConfigs-Extension.cjs +87 -0
- package/source/services/tasks/extension/definitions/beacon-dispatch.json +32 -0
- package/source/services/tasks/file-system/Ultravisor-TaskConfigs-FileSystem.cjs +509 -0
- package/source/services/tasks/file-system/Ultravisor-TaskType-ReadFile.cjs +96 -0
- package/source/services/tasks/file-system/Ultravisor-TaskType-ReadFileBuffered.cjs +123 -0
- package/source/services/tasks/file-system/Ultravisor-TaskType-WriteFile.cjs +106 -0
- package/source/services/tasks/file-system/definitions/copy-file.json +27 -0
- package/source/services/tasks/file-system/definitions/list-files.json +27 -0
- package/source/services/tasks/file-system/definitions/read-file-buffered.json +31 -0
- package/source/services/tasks/file-system/definitions/read-file.json +26 -0
- package/source/services/tasks/file-system/definitions/read-json.json +23 -0
- package/source/services/tasks/file-system/definitions/write-file.json +29 -0
- package/source/services/tasks/file-system/definitions/write-json.json +30 -0
- package/source/services/tasks/flow-control/Ultravisor-TaskConfigs-FlowControl.cjs +353 -0
- package/source/services/tasks/flow-control/Ultravisor-TaskType-IfConditional.cjs +125 -0
- package/source/services/tasks/flow-control/Ultravisor-TaskType-LaunchOperation.cjs +186 -0
- package/source/services/tasks/flow-control/Ultravisor-TaskType-SplitExecute.cjs +164 -0
- package/source/services/tasks/flow-control/definitions/if-conditional.json +25 -0
- package/source/services/tasks/flow-control/definitions/launch-operation.json +27 -0
- package/source/services/tasks/flow-control/definitions/split-execute.json +32 -0
- package/source/services/tasks/http-client/Ultravisor-TaskConfigs-HttpClient.cjs +281 -0
- package/source/services/tasks/http-client/definitions/get-json.json +26 -0
- package/source/services/tasks/http-client/definitions/get-text.json +26 -0
- package/source/services/tasks/http-client/definitions/rest-request.json +32 -0
- package/source/services/tasks/http-client/definitions/send-json.json +28 -0
- package/source/services/tasks/llm/Ultravisor-TaskConfigs-LLM.cjs +605 -0
- package/source/services/tasks/llm/definitions/llm-chat-completion.json +46 -0
- package/source/services/tasks/llm/definitions/llm-embedding.json +31 -0
- package/source/services/tasks/llm/definitions/llm-tool-use.json +42 -0
- package/source/services/tasks/meadow-api/Ultravisor-TaskConfigs-MeadowApi.cjs +341 -0
- package/source/services/tasks/meadow-api/definitions/meadow-count.json +26 -0
- package/source/services/tasks/meadow-api/definitions/meadow-create.json +26 -0
- package/source/services/tasks/meadow-api/definitions/meadow-delete.json +23 -0
- package/source/services/tasks/meadow-api/definitions/meadow-read.json +26 -0
- package/source/services/tasks/meadow-api/definitions/meadow-reads.json +29 -0
- package/source/services/tasks/meadow-api/definitions/meadow-update.json +26 -0
- package/source/services/tasks/shell/Ultravisor-TaskConfigs-Shell.cjs +63 -0
- package/source/services/tasks/shell/definitions/command.json +29 -0
- package/source/services/tasks/user-interaction/Ultravisor-TaskConfigs-UserInteraction.cjs +64 -0
- package/source/services/tasks/user-interaction/Ultravisor-TaskType-ErrorMessage.cjs +55 -0
- package/source/services/tasks/user-interaction/Ultravisor-TaskType-ValueInput.cjs +47 -0
- package/source/services/tasks/user-interaction/definitions/error-message.json +18 -0
- package/source/services/tasks/user-interaction/definitions/value-input.json +23 -0
- package/source/web_server/Ultravisor-API-Server.cjs +849 -124
- package/test/Ultravisor_browser_tests.js +2226 -0
- package/test/Ultravisor_operation_library_tests.js +894 -0
- package/test/Ultravisor_tests.js +4946 -5044
- package/test/workflows/test-content-concatenate-all.json +339 -0
- package/test/workflows/test-content-full-pipeline.json +159 -0
- package/test/workflows/test-content-list-files.json +76 -0
- package/test/workflows/test-content-save-and-read.json +106 -0
- package/webinterface/css/ultravisor-themes.css +668 -0
- package/webinterface/css/ultravisor.css +37 -14
- package/webinterface/docs/card-help/beacon-dispatch.md +30 -0
- package/webinterface/docs/card-help/command.md +27 -0
- package/webinterface/docs/card-help/comprehension-intersect.md +24 -0
- package/webinterface/docs/card-help/content-create-folder.md +22 -0
- package/webinterface/docs/card-help/content-list-files.md +25 -0
- package/webinterface/docs/card-help/content-read-file.md +24 -0
- package/webinterface/docs/card-help/content-save-file.md +24 -0
- package/webinterface/docs/card-help/copy-file.md +25 -0
- package/webinterface/docs/card-help/csv-transform.md +24 -0
- package/webinterface/docs/card-help/end.md +11 -0
- package/webinterface/docs/card-help/error-message.md +16 -0
- package/webinterface/docs/card-help/expression-solver.md +21 -0
- package/webinterface/docs/card-help/get-json.md +24 -0
- package/webinterface/docs/card-help/get-text.md +24 -0
- package/webinterface/docs/card-help/histogram.md +23 -0
- package/webinterface/docs/card-help/if-conditional.md +23 -0
- package/webinterface/docs/card-help/launch-operation.md +25 -0
- package/webinterface/docs/card-help/list-files.md +25 -0
- package/webinterface/docs/card-help/llm-chat-completion.md +43 -0
- package/webinterface/docs/card-help/llm-embedding.md +24 -0
- package/webinterface/docs/card-help/llm-tool-use.md +39 -0
- package/webinterface/docs/card-help/meadow-count.md +24 -0
- package/webinterface/docs/card-help/meadow-create.md +24 -0
- package/webinterface/docs/card-help/meadow-delete.md +19 -0
- package/webinterface/docs/card-help/meadow-read.md +24 -0
- package/webinterface/docs/card-help/meadow-reads.md +27 -0
- package/webinterface/docs/card-help/meadow-update.md +24 -0
- package/webinterface/docs/card-help/parse-csv.md +27 -0
- package/webinterface/docs/card-help/read-file-buffered.md +29 -0
- package/webinterface/docs/card-help/read-file.md +24 -0
- package/webinterface/docs/card-help/read-json.md +21 -0
- package/webinterface/docs/card-help/replace-string.md +25 -0
- package/webinterface/docs/card-help/rest-request.md +30 -0
- package/webinterface/docs/card-help/send-json.md +26 -0
- package/webinterface/docs/card-help/set-values.md +16 -0
- package/webinterface/docs/card-help/split-execute.md +35 -0
- package/webinterface/docs/card-help/start.md +11 -0
- package/webinterface/docs/card-help/string-appender.md +22 -0
- package/webinterface/docs/card-help/template-string.md +21 -0
- package/webinterface/docs/card-help/value-input.md +24 -0
- package/webinterface/docs/card-help/write-file.md +27 -0
- package/webinterface/docs/card-help/write-json.md +28 -0
- package/webinterface/html/index.html +5 -0
- package/webinterface/package.json +13 -4
- package/webinterface/source/Pict-Application-Ultravisor.js +564 -70
- package/webinterface/source/Ultravisor-TimingUtils.js +99 -0
- package/webinterface/source/card-help-content.js +46 -0
- package/webinterface/source/cards/Ultravisor-BuiltIn-CardConfigs.js +174 -0
- package/webinterface/source/cards/Ultravisor-CardConfigGenerator.js +431 -0
- package/webinterface/source/data/ExampleFlow-CSVPipeline.js +231 -0
- package/webinterface/source/data/ExampleFlow-FileProcessor.js +315 -0
- package/webinterface/source/data/ExampleFlow-MeadowPipeline.js +328 -0
- package/webinterface/source/panels/Ultravisor-CardSettingsPanel.js +902 -0
- package/webinterface/source/providers/PictRouter-Ultravisor-Configuration.json +20 -8
- package/webinterface/source/views/PictView-Ultravisor-BeaconList.js +817 -0
- package/webinterface/source/views/PictView-Ultravisor-BottomBar.js +5 -5
- package/webinterface/source/views/PictView-Ultravisor-Dashboard.js +25 -25
- package/webinterface/source/views/PictView-Ultravisor-Documentation.js +856 -0
- package/webinterface/source/views/PictView-Ultravisor-FlowEditor.js +777 -0
- package/webinterface/source/views/PictView-Ultravisor-ManifestList.js +321 -58
- package/webinterface/source/views/PictView-Ultravisor-OperationEdit.js +36 -91
- package/webinterface/source/views/PictView-Ultravisor-OperationList.js +388 -16
- package/webinterface/source/views/PictView-Ultravisor-PendingInput.js +314 -0
- package/webinterface/source/views/PictView-Ultravisor-Schedule.js +521 -65
- package/webinterface/source/views/PictView-Ultravisor-TimingView.js +333 -71
- package/webinterface/source/views/PictView-Ultravisor-TopBar.js +257 -21
- package/webinterface/theme-sampler.html +645 -0
- package/debug/Harness.js +0 -6
- package/source/services/Ultravisor-Operation-Manifest.cjs +0 -160
- package/source/services/Ultravisor-Operation.cjs +0 -200
- package/source/services/Ultravisor-Task.cjs +0 -349
- package/source/services/events/Ultravisor-Hypervisor-Event-Solver.cjs +0 -11
- package/source/services/tasks/Ultravisor-Task-Base.cjs +0 -264
- package/source/services/tasks/Ultravisor-Task-CollectValues.cjs +0 -188
- package/source/services/tasks/Ultravisor-Task-Command.cjs +0 -65
- package/source/services/tasks/Ultravisor-Task-CommandEach.cjs +0 -190
- package/source/services/tasks/Ultravisor-Task-Conditional.cjs +0 -104
- package/source/services/tasks/Ultravisor-Task-DateWindow.cjs +0 -72
- package/source/services/tasks/Ultravisor-Task-GeneratePagedOperation.cjs +0 -336
- package/source/services/tasks/Ultravisor-Task-LaunchOperation.cjs +0 -143
- package/source/services/tasks/Ultravisor-Task-LaunchTask.cjs +0 -146
- package/source/services/tasks/Ultravisor-Task-LineMatch.cjs +0 -158
- package/source/services/tasks/Ultravisor-Task-Request.cjs +0 -56
- package/source/services/tasks/Ultravisor-Task-Solver.cjs +0 -89
- package/source/services/tasks/Ultravisor-Task-TemplateString.cjs +0 -93
- package/source/services/tasks/rest/Ultravisor-Task-GetBinary.cjs +0 -127
- package/source/services/tasks/rest/Ultravisor-Task-GetJSON.cjs +0 -119
- package/source/services/tasks/rest/Ultravisor-Task-GetText.cjs +0 -109
- package/source/services/tasks/rest/Ultravisor-Task-GetXML.cjs +0 -112
- package/source/services/tasks/rest/Ultravisor-Task-RestRequest.cjs +0 -499
- package/source/services/tasks/rest/Ultravisor-Task-SendJSON.cjs +0 -150
- package/source/services/tasks/stagingfiles/Ultravisor-Task-CopyFile.cjs +0 -110
- package/source/services/tasks/stagingfiles/Ultravisor-Task-ListFiles.cjs +0 -89
- package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadBinary.cjs +0 -87
- package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadJSON.cjs +0 -67
- package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadText.cjs +0 -66
- package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadXML.cjs +0 -69
- package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteBinary.cjs +0 -95
- package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteJSON.cjs +0 -96
- package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteText.cjs +0 -99
- package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteXML.cjs +0 -102
- package/webinterface/source/views/PictView-Ultravisor-TaskEdit.js +0 -220
- package/webinterface/source/views/PictView-Ultravisor-TaskList.js +0 -248
|
@@ -0,0 +1,902 @@
|
|
|
1
|
+
const libPictFlowCardPropertiesPanel = require('pict-section-flow/source/PictFlowCardPropertiesPanel.js');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Ultravisor Card Settings Panel
|
|
5
|
+
*
|
|
6
|
+
* A custom properties panel for Ultravisor flow cards that provides
|
|
7
|
+
* per-field mode toggles: Constant, Address, or Default.
|
|
8
|
+
*
|
|
9
|
+
* - Constant: a literal value edited with a type-appropriate input
|
|
10
|
+
* - Address: a Manyfest address expression resolved at execution time
|
|
11
|
+
* - Default: use the task type's default value (field omitted from Data)
|
|
12
|
+
*
|
|
13
|
+
* Each field has a single toggle button to the left of the input that
|
|
14
|
+
* cycles through modes on click. Values are remembered per-mode so
|
|
15
|
+
* switching away and back restores what was there before.
|
|
16
|
+
*
|
|
17
|
+
* The panel reads the task definition schema (SettingsInputs + DefaultSettings)
|
|
18
|
+
* from the panel Configuration, and stores mode metadata in the node's
|
|
19
|
+
* Data._FieldModes object alongside the actual field values.
|
|
20
|
+
*
|
|
21
|
+
* Panel type identifier: 'UltravisorSettings'
|
|
22
|
+
* Service type: 'PictFlowCardPropertiesPanel-UltravisorSettings'
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// Mode cycle order
|
|
26
|
+
const _ModeCycle = ['constant', 'address', 'default'];
|
|
27
|
+
|
|
28
|
+
// Mode display labels (shown in italic on the toggle button)
|
|
29
|
+
const _ModeLabels =
|
|
30
|
+
{
|
|
31
|
+
'constant': 'C',
|
|
32
|
+
'address': 'A',
|
|
33
|
+
'default': 'D'
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Mode tooltip text
|
|
37
|
+
const _ModeTitles =
|
|
38
|
+
{
|
|
39
|
+
'constant': 'Constant',
|
|
40
|
+
'address': 'Address',
|
|
41
|
+
'default': 'Default'
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class UltravisorCardSettingsPanel extends libPictFlowCardPropertiesPanel
|
|
46
|
+
{
|
|
47
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
48
|
+
{
|
|
49
|
+
super(pFable, pOptions, pServiceHash);
|
|
50
|
+
|
|
51
|
+
this.serviceType = 'PictFlowCardPropertiesPanel-UltravisorSettings';
|
|
52
|
+
|
|
53
|
+
// Schema from the task definition
|
|
54
|
+
this._Schema = (this._Configuration && Array.isArray(this._Configuration.Schema))
|
|
55
|
+
? this._Configuration.Schema
|
|
56
|
+
: [];
|
|
57
|
+
this._Defaults = (this._Configuration && typeof(this._Configuration.Defaults) === 'object')
|
|
58
|
+
? this._Configuration.Defaults
|
|
59
|
+
: {};
|
|
60
|
+
|
|
61
|
+
// Per-field state: { fieldName: { mode, constantValue, addressValue, dataType, defaultValue } }
|
|
62
|
+
this._FieldStates = {};
|
|
63
|
+
|
|
64
|
+
// Track whether CSS has been injected
|
|
65
|
+
this._CSSInjected = false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ====================================================================
|
|
69
|
+
// Render
|
|
70
|
+
// ====================================================================
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Render the settings panel into the provided container.
|
|
74
|
+
*
|
|
75
|
+
* @param {HTMLElement} pContainer - The DOM element to render into
|
|
76
|
+
* @param {Object} pNodeData - The node data object (has .Data property)
|
|
77
|
+
*/
|
|
78
|
+
render(pContainer, pNodeData)
|
|
79
|
+
{
|
|
80
|
+
super.render(pContainer, pNodeData);
|
|
81
|
+
|
|
82
|
+
this._injectCSS();
|
|
83
|
+
this._initializeFieldStates(pNodeData);
|
|
84
|
+
|
|
85
|
+
let tmpHTML = '<div class="uv-settings-panel">';
|
|
86
|
+
|
|
87
|
+
for (let i = 0; i < this._Schema.length; i++)
|
|
88
|
+
{
|
|
89
|
+
let tmpSetting = this._Schema[i];
|
|
90
|
+
let tmpFieldName = tmpSetting.Name;
|
|
91
|
+
let tmpState = this._FieldStates[tmpFieldName];
|
|
92
|
+
|
|
93
|
+
if (!tmpState)
|
|
94
|
+
{
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
tmpHTML += this._renderField(tmpSetting, tmpState);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
tmpHTML += '</div>';
|
|
102
|
+
pContainer.innerHTML = tmpHTML;
|
|
103
|
+
|
|
104
|
+
this._wireEventListeners(pContainer);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ====================================================================
|
|
108
|
+
// Field State Initialization
|
|
109
|
+
// ====================================================================
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Initialize _FieldStates from the node's Data and _FieldModes.
|
|
113
|
+
*
|
|
114
|
+
* Each field stores separate constantValue and addressValue so that
|
|
115
|
+
* switching modes preserves what was entered in each.
|
|
116
|
+
*
|
|
117
|
+
* Backward compatibility: when _FieldModes is absent, infer modes:
|
|
118
|
+
* - string value containing '{~' → address
|
|
119
|
+
* - value present → constant
|
|
120
|
+
* - value absent → default
|
|
121
|
+
*
|
|
122
|
+
* @param {Object} pNodeData
|
|
123
|
+
*/
|
|
124
|
+
_initializeFieldStates(pNodeData)
|
|
125
|
+
{
|
|
126
|
+
this._FieldStates = {};
|
|
127
|
+
|
|
128
|
+
let tmpData = (pNodeData && pNodeData.Data && typeof(pNodeData.Data) === 'object')
|
|
129
|
+
? pNodeData.Data
|
|
130
|
+
: {};
|
|
131
|
+
let tmpFieldModes = (tmpData._FieldModes && typeof(tmpData._FieldModes) === 'object')
|
|
132
|
+
? tmpData._FieldModes
|
|
133
|
+
: null;
|
|
134
|
+
|
|
135
|
+
for (let i = 0; i < this._Schema.length; i++)
|
|
136
|
+
{
|
|
137
|
+
let tmpSetting = this._Schema[i];
|
|
138
|
+
let tmpFieldName = tmpSetting.Name;
|
|
139
|
+
let tmpDataType = tmpSetting.DataType || 'String';
|
|
140
|
+
let tmpDefault = (this._Defaults.hasOwnProperty(tmpFieldName))
|
|
141
|
+
? this._Defaults[tmpFieldName]
|
|
142
|
+
: '';
|
|
143
|
+
|
|
144
|
+
let tmpMode = 'default';
|
|
145
|
+
let tmpConstantValue = tmpDefault;
|
|
146
|
+
let tmpAddressValue = '';
|
|
147
|
+
|
|
148
|
+
if (tmpFieldModes && tmpFieldModes.hasOwnProperty(tmpFieldName))
|
|
149
|
+
{
|
|
150
|
+
// Explicit mode from _FieldModes
|
|
151
|
+
tmpMode = tmpFieldModes[tmpFieldName];
|
|
152
|
+
|
|
153
|
+
if (tmpMode === 'address')
|
|
154
|
+
{
|
|
155
|
+
tmpAddressValue = this._extractAddressFromTemplate(tmpData[tmpFieldName]);
|
|
156
|
+
}
|
|
157
|
+
else if (tmpMode === 'constant')
|
|
158
|
+
{
|
|
159
|
+
tmpConstantValue = tmpData.hasOwnProperty(tmpFieldName) ? tmpData[tmpFieldName] : tmpDefault;
|
|
160
|
+
}
|
|
161
|
+
// mode === 'default' → constantValue stays at schema default
|
|
162
|
+
}
|
|
163
|
+
else
|
|
164
|
+
{
|
|
165
|
+
// Infer mode from existing data (backward compatibility)
|
|
166
|
+
if (tmpData.hasOwnProperty(tmpFieldName))
|
|
167
|
+
{
|
|
168
|
+
let tmpExistingValue = tmpData[tmpFieldName];
|
|
169
|
+
|
|
170
|
+
if (typeof(tmpExistingValue) === 'string' && tmpExistingValue.indexOf('{~') >= 0)
|
|
171
|
+
{
|
|
172
|
+
tmpMode = 'address';
|
|
173
|
+
tmpAddressValue = this._extractAddressFromTemplate(tmpExistingValue);
|
|
174
|
+
}
|
|
175
|
+
else
|
|
176
|
+
{
|
|
177
|
+
tmpMode = 'constant';
|
|
178
|
+
tmpConstantValue = tmpExistingValue;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// else: absent → default
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
this._FieldStates[tmpFieldName] =
|
|
185
|
+
{
|
|
186
|
+
mode: tmpMode,
|
|
187
|
+
constantValue: tmpConstantValue,
|
|
188
|
+
addressValue: tmpAddressValue,
|
|
189
|
+
dataType: tmpDataType,
|
|
190
|
+
defaultValue: tmpDefault
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ====================================================================
|
|
196
|
+
// HTML Generation
|
|
197
|
+
// ====================================================================
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Render a single field row: label + [toggle | editor] + description.
|
|
201
|
+
*
|
|
202
|
+
* Layout:
|
|
203
|
+
* FieldName*
|
|
204
|
+
* [C] [ input______________________ ]
|
|
205
|
+
* description text
|
|
206
|
+
*
|
|
207
|
+
* @param {Object} pSetting - The SettingsInput definition
|
|
208
|
+
* @param {Object} pState - The field's current state from _FieldStates
|
|
209
|
+
* @returns {string} HTML string
|
|
210
|
+
*/
|
|
211
|
+
_renderField(pSetting, pState)
|
|
212
|
+
{
|
|
213
|
+
let tmpFieldName = pSetting.Name;
|
|
214
|
+
let tmpRequired = pSetting.Required ? '<span class="uv-settings-field-required">*</span>' : '';
|
|
215
|
+
let tmpDescription = pSetting.Description
|
|
216
|
+
? '<div class="uv-settings-field-description">' + this._escapeHTML(pSetting.Description) + '</div>'
|
|
217
|
+
: '';
|
|
218
|
+
let tmpAttrName = this._escapeAttr(tmpFieldName);
|
|
219
|
+
|
|
220
|
+
let tmpEditorHTML = this._renderFieldEditor(tmpFieldName, pState);
|
|
221
|
+
|
|
222
|
+
let tmpModeClass = 'uv-mode-' + pState.mode;
|
|
223
|
+
let tmpLabel = _ModeLabels[pState.mode] || 'C';
|
|
224
|
+
let tmpTitle = _ModeTitles[pState.mode] || '';
|
|
225
|
+
|
|
226
|
+
return '<div class="uv-settings-field" data-field-name="' + tmpAttrName + '">'
|
|
227
|
+
+ '<div class="uv-settings-field-label">' + this._escapeHTML(tmpFieldName) + tmpRequired + '</div>'
|
|
228
|
+
+ '<div class="uv-settings-field-row">'
|
|
229
|
+
+ '<button class="uv-mode-toggle ' + tmpModeClass + '" data-field="' + tmpAttrName + '" title="' + this._escapeAttr(tmpTitle) + '">' + tmpLabel + '</button>'
|
|
230
|
+
+ '<div class="uv-settings-field-editor" data-field="' + tmpAttrName + '">'
|
|
231
|
+
+ tmpEditorHTML
|
|
232
|
+
+ '</div>'
|
|
233
|
+
+ '</div>'
|
|
234
|
+
+ tmpDescription
|
|
235
|
+
+ '</div>';
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Render the editor widget for a field based on its current mode.
|
|
240
|
+
*
|
|
241
|
+
* @param {string} pFieldName
|
|
242
|
+
* @param {Object} pState
|
|
243
|
+
* @returns {string} HTML string
|
|
244
|
+
*/
|
|
245
|
+
_renderFieldEditor(pFieldName, pState)
|
|
246
|
+
{
|
|
247
|
+
let tmpAttrName = this._escapeAttr(pFieldName);
|
|
248
|
+
|
|
249
|
+
switch (pState.mode)
|
|
250
|
+
{
|
|
251
|
+
case 'constant':
|
|
252
|
+
return this._renderConstantEditor(tmpAttrName, pState);
|
|
253
|
+
|
|
254
|
+
case 'address':
|
|
255
|
+
return this._renderAddressEditor(tmpAttrName, pState);
|
|
256
|
+
|
|
257
|
+
case 'default':
|
|
258
|
+
return this._renderDefaultDisplay(pState);
|
|
259
|
+
|
|
260
|
+
default:
|
|
261
|
+
return '';
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Render a type-appropriate constant value editor.
|
|
267
|
+
*/
|
|
268
|
+
_renderConstantEditor(pAttrName, pState)
|
|
269
|
+
{
|
|
270
|
+
let tmpValue = pState.constantValue;
|
|
271
|
+
|
|
272
|
+
switch (pState.dataType)
|
|
273
|
+
{
|
|
274
|
+
case 'Boolean':
|
|
275
|
+
{
|
|
276
|
+
let tmpChecked = (tmpValue === true || tmpValue === 'true') ? ' checked' : '';
|
|
277
|
+
return '<label class="uv-settings-checkbox">'
|
|
278
|
+
+ '<input type="checkbox" class="uv-settings-input-bool" data-field="' + pAttrName + '"' + tmpChecked + '>'
|
|
279
|
+
+ '<span>Enabled</span>'
|
|
280
|
+
+ '</label>';
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
case 'Number':
|
|
284
|
+
{
|
|
285
|
+
let tmpNumVal = (tmpValue !== undefined && tmpValue !== null && tmpValue !== '') ? tmpValue : '';
|
|
286
|
+
return '<input type="number" class="uv-settings-input" data-field="' + pAttrName + '" value="' + this._escapeAttr(String(tmpNumVal)) + '">';
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
case 'Array':
|
|
290
|
+
case 'Object':
|
|
291
|
+
{
|
|
292
|
+
let tmpDisplayValue = '';
|
|
293
|
+
if (typeof(tmpValue) === 'object' && tmpValue !== null)
|
|
294
|
+
{
|
|
295
|
+
tmpDisplayValue = JSON.stringify(tmpValue, null, '\t');
|
|
296
|
+
}
|
|
297
|
+
else if (typeof(tmpValue) === 'string')
|
|
298
|
+
{
|
|
299
|
+
tmpDisplayValue = tmpValue;
|
|
300
|
+
}
|
|
301
|
+
return '<textarea class="uv-settings-textarea" data-field="' + pAttrName + '">' + this._escapeHTML(tmpDisplayValue) + '</textarea>';
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
default: // String
|
|
305
|
+
{
|
|
306
|
+
let tmpStrVal = (tmpValue !== undefined && tmpValue !== null) ? String(tmpValue) : '';
|
|
307
|
+
return '<input type="text" class="uv-settings-input" data-field="' + pAttrName + '" value="' + this._escapeAttr(tmpStrVal) + '">';
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Render the address mode editor: text input with placeholder.
|
|
314
|
+
*/
|
|
315
|
+
_renderAddressEditor(pAttrName, pState)
|
|
316
|
+
{
|
|
317
|
+
let tmpAddress = (typeof(pState.addressValue) === 'string') ? pState.addressValue : '';
|
|
318
|
+
|
|
319
|
+
return '<input type="text" class="uv-settings-input uv-settings-address-input" data-field="' + pAttrName + '" value="' + this._escapeAttr(tmpAddress) + '" placeholder="e.g. Operation.InputFilePath">';
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Render the default mode display: read-only showing the schema default.
|
|
324
|
+
*/
|
|
325
|
+
_renderDefaultDisplay(pState)
|
|
326
|
+
{
|
|
327
|
+
let tmpDefaultStr = '';
|
|
328
|
+
|
|
329
|
+
if (pState.defaultValue === undefined || pState.defaultValue === null || pState.defaultValue === '')
|
|
330
|
+
{
|
|
331
|
+
tmpDefaultStr = 'default: empty';
|
|
332
|
+
}
|
|
333
|
+
else if (typeof(pState.defaultValue) === 'object')
|
|
334
|
+
{
|
|
335
|
+
tmpDefaultStr = 'default: ' + JSON.stringify(pState.defaultValue);
|
|
336
|
+
}
|
|
337
|
+
else
|
|
338
|
+
{
|
|
339
|
+
tmpDefaultStr = 'default: ' + String(pState.defaultValue);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return '<div class="uv-settings-default-display">' + this._escapeHTML(tmpDefaultStr) + '</div>';
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// ====================================================================
|
|
346
|
+
// Event Handling
|
|
347
|
+
// ====================================================================
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Wire up event listeners on the rendered panel DOM.
|
|
351
|
+
*
|
|
352
|
+
* @param {HTMLElement} pContainer
|
|
353
|
+
*/
|
|
354
|
+
_wireEventListeners(pContainer)
|
|
355
|
+
{
|
|
356
|
+
let tmpSelf = this;
|
|
357
|
+
|
|
358
|
+
// Mode toggle buttons — use pointerup instead of click to avoid
|
|
359
|
+
// SVG foreignObject event routing issues in Safari
|
|
360
|
+
let tmpToggles = pContainer.querySelectorAll('.uv-mode-toggle');
|
|
361
|
+
for (let i = 0; i < tmpToggles.length; i++)
|
|
362
|
+
{
|
|
363
|
+
tmpToggles[i].addEventListener('pointerdown', function (pEvent)
|
|
364
|
+
{
|
|
365
|
+
pEvent.stopPropagation();
|
|
366
|
+
pEvent.preventDefault();
|
|
367
|
+
});
|
|
368
|
+
tmpToggles[i].addEventListener('pointerup', function (pEvent)
|
|
369
|
+
{
|
|
370
|
+
pEvent.stopPropagation();
|
|
371
|
+
pEvent.preventDefault();
|
|
372
|
+
|
|
373
|
+
let tmpFieldName = this.getAttribute('data-field');
|
|
374
|
+
tmpSelf._cycleFieldMode(pContainer, tmpFieldName);
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Wire input listeners for all existing editors
|
|
379
|
+
this._wireInputListeners(pContainer);
|
|
380
|
+
|
|
381
|
+
// Prevent pointer events from propagating to the SVG layer
|
|
382
|
+
this._wirePointerIsolation(pContainer);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Stop pointer events on interactive elements from reaching the SVG canvas.
|
|
387
|
+
*
|
|
388
|
+
* @param {HTMLElement} pContainer
|
|
389
|
+
*/
|
|
390
|
+
_wirePointerIsolation(pContainer)
|
|
391
|
+
{
|
|
392
|
+
let tmpElements = pContainer.querySelectorAll('input, textarea, button, select');
|
|
393
|
+
for (let i = 0; i < tmpElements.length; i++)
|
|
394
|
+
{
|
|
395
|
+
tmpElements[i].addEventListener('pointerdown', function (pEvent)
|
|
396
|
+
{
|
|
397
|
+
pEvent.stopPropagation();
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Attach change/input listeners to editor elements so field state
|
|
404
|
+
* is kept up to date as the user types.
|
|
405
|
+
*
|
|
406
|
+
* @param {HTMLElement} pContainer
|
|
407
|
+
*/
|
|
408
|
+
_wireInputListeners(pContainer)
|
|
409
|
+
{
|
|
410
|
+
let tmpSelf = this;
|
|
411
|
+
|
|
412
|
+
// Text and number inputs
|
|
413
|
+
let tmpTextInputs = pContainer.querySelectorAll('.uv-settings-input');
|
|
414
|
+
for (let i = 0; i < tmpTextInputs.length; i++)
|
|
415
|
+
{
|
|
416
|
+
tmpTextInputs[i].addEventListener('input', function ()
|
|
417
|
+
{
|
|
418
|
+
let tmpFieldName = this.getAttribute('data-field');
|
|
419
|
+
let tmpState = tmpSelf._FieldStates[tmpFieldName];
|
|
420
|
+
|
|
421
|
+
if (!tmpState)
|
|
422
|
+
{
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if (tmpState.mode === 'address')
|
|
427
|
+
{
|
|
428
|
+
tmpState.addressValue = this.value;
|
|
429
|
+
}
|
|
430
|
+
else if (tmpState.dataType === 'Number')
|
|
431
|
+
{
|
|
432
|
+
tmpState.constantValue = this.value === '' ? '' : Number(this.value);
|
|
433
|
+
}
|
|
434
|
+
else
|
|
435
|
+
{
|
|
436
|
+
tmpState.constantValue = this.value;
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Checkbox inputs
|
|
442
|
+
let tmpCheckboxes = pContainer.querySelectorAll('.uv-settings-input-bool');
|
|
443
|
+
for (let i = 0; i < tmpCheckboxes.length; i++)
|
|
444
|
+
{
|
|
445
|
+
tmpCheckboxes[i].addEventListener('change', function ()
|
|
446
|
+
{
|
|
447
|
+
let tmpFieldName = this.getAttribute('data-field');
|
|
448
|
+
let tmpState = tmpSelf._FieldStates[tmpFieldName];
|
|
449
|
+
|
|
450
|
+
if (tmpState)
|
|
451
|
+
{
|
|
452
|
+
tmpState.constantValue = this.checked;
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Textareas (Array/Object JSON)
|
|
458
|
+
let tmpTextareas = pContainer.querySelectorAll('.uv-settings-textarea');
|
|
459
|
+
for (let i = 0; i < tmpTextareas.length; i++)
|
|
460
|
+
{
|
|
461
|
+
tmpTextareas[i].addEventListener('input', function ()
|
|
462
|
+
{
|
|
463
|
+
let tmpFieldName = this.getAttribute('data-field');
|
|
464
|
+
let tmpState = tmpSelf._FieldStates[tmpFieldName];
|
|
465
|
+
|
|
466
|
+
if (tmpState)
|
|
467
|
+
{
|
|
468
|
+
// Store raw string; JSON.parse happens in marshal
|
|
469
|
+
tmpState.constantValue = this.value;
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Cycle a field to the next mode (constant → address → default → constant)
|
|
477
|
+
* and re-render just that field's editor + toggle button.
|
|
478
|
+
*
|
|
479
|
+
* @param {HTMLElement} pContainer
|
|
480
|
+
* @param {string} pFieldName
|
|
481
|
+
*/
|
|
482
|
+
_cycleFieldMode(pContainer, pFieldName)
|
|
483
|
+
{
|
|
484
|
+
let tmpState = this._FieldStates[pFieldName];
|
|
485
|
+
|
|
486
|
+
if (!tmpState)
|
|
487
|
+
{
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Find next mode in cycle
|
|
492
|
+
let tmpCurrentIndex = _ModeCycle.indexOf(tmpState.mode);
|
|
493
|
+
let tmpNextIndex = (tmpCurrentIndex + 1) % _ModeCycle.length;
|
|
494
|
+
let tmpNewMode = _ModeCycle[tmpNextIndex];
|
|
495
|
+
|
|
496
|
+
tmpState.mode = tmpNewMode;
|
|
497
|
+
|
|
498
|
+
// Update the toggle button
|
|
499
|
+
let tmpFieldContainer = pContainer.querySelector('.uv-settings-field[data-field-name="' + pFieldName + '"]');
|
|
500
|
+
|
|
501
|
+
if (!tmpFieldContainer)
|
|
502
|
+
{
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
let tmpToggle = tmpFieldContainer.querySelector('.uv-mode-toggle');
|
|
507
|
+
if (tmpToggle)
|
|
508
|
+
{
|
|
509
|
+
// Update CSS class
|
|
510
|
+
tmpToggle.className = 'uv-mode-toggle uv-mode-' + tmpNewMode;
|
|
511
|
+
// Update label
|
|
512
|
+
tmpToggle.textContent = _ModeLabels[tmpNewMode] || 'C';
|
|
513
|
+
// Update tooltip
|
|
514
|
+
tmpToggle.title = _ModeTitles[tmpNewMode] || '';
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Re-render the editor area
|
|
518
|
+
let tmpEditorContainer = tmpFieldContainer.querySelector('.uv-settings-field-editor');
|
|
519
|
+
if (tmpEditorContainer)
|
|
520
|
+
{
|
|
521
|
+
tmpEditorContainer.innerHTML = this._renderFieldEditor(pFieldName, tmpState);
|
|
522
|
+
|
|
523
|
+
// Re-wire listeners on new elements
|
|
524
|
+
this._wireInputListeners(tmpEditorContainer);
|
|
525
|
+
this._wirePointerIsolation(tmpEditorContainer);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// ====================================================================
|
|
530
|
+
// Marshal
|
|
531
|
+
// ====================================================================
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Marshal data from the panel UI back into the node's Data object.
|
|
535
|
+
*
|
|
536
|
+
* @param {Object} pNodeData
|
|
537
|
+
*/
|
|
538
|
+
marshalFromPanel(pNodeData)
|
|
539
|
+
{
|
|
540
|
+
if (!pNodeData || !this._FieldStates)
|
|
541
|
+
{
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (!pNodeData.Data)
|
|
546
|
+
{
|
|
547
|
+
pNodeData.Data = {};
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
let tmpFieldModes = {};
|
|
551
|
+
let tmpHasNonDefault = false;
|
|
552
|
+
|
|
553
|
+
let tmpFieldNames = Object.keys(this._FieldStates);
|
|
554
|
+
|
|
555
|
+
for (let i = 0; i < tmpFieldNames.length; i++)
|
|
556
|
+
{
|
|
557
|
+
let tmpFieldName = tmpFieldNames[i];
|
|
558
|
+
let tmpState = this._FieldStates[tmpFieldName];
|
|
559
|
+
|
|
560
|
+
switch (tmpState.mode)
|
|
561
|
+
{
|
|
562
|
+
case 'constant':
|
|
563
|
+
{
|
|
564
|
+
let tmpValue = tmpState.constantValue;
|
|
565
|
+
|
|
566
|
+
// Parse JSON for Array/Object data types
|
|
567
|
+
if ((tmpState.dataType === 'Array' || tmpState.dataType === 'Object') && typeof(tmpValue) === 'string')
|
|
568
|
+
{
|
|
569
|
+
let tmpTrimmed = tmpValue.trim();
|
|
570
|
+
|
|
571
|
+
if (tmpTrimmed.length > 0)
|
|
572
|
+
{
|
|
573
|
+
try
|
|
574
|
+
{
|
|
575
|
+
tmpValue = JSON.parse(tmpTrimmed);
|
|
576
|
+
}
|
|
577
|
+
catch (pParseError)
|
|
578
|
+
{
|
|
579
|
+
// Keep as raw string if not valid JSON
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
pNodeData.Data[tmpFieldName] = tmpValue;
|
|
585
|
+
tmpFieldModes[tmpFieldName] = 'constant';
|
|
586
|
+
tmpHasNonDefault = true;
|
|
587
|
+
break;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
case 'address':
|
|
591
|
+
{
|
|
592
|
+
let tmpAddress = (typeof(tmpState.addressValue) === 'string') ? tmpState.addressValue.trim() : '';
|
|
593
|
+
pNodeData.Data[tmpFieldName] = this._buildTemplateFromAddress(tmpAddress);
|
|
594
|
+
tmpFieldModes[tmpFieldName] = 'address';
|
|
595
|
+
tmpHasNonDefault = true;
|
|
596
|
+
break;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
case 'default':
|
|
600
|
+
{
|
|
601
|
+
// Remove the field so the task falls back to its built-in default
|
|
602
|
+
delete pNodeData.Data[tmpFieldName];
|
|
603
|
+
// Not added to _FieldModes — absent means 'default'
|
|
604
|
+
break;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Store _FieldModes metadata if any field is non-default
|
|
610
|
+
if (tmpHasNonDefault)
|
|
611
|
+
{
|
|
612
|
+
pNodeData.Data._FieldModes = tmpFieldModes;
|
|
613
|
+
}
|
|
614
|
+
else
|
|
615
|
+
{
|
|
616
|
+
delete pNodeData.Data._FieldModes;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// ====================================================================
|
|
621
|
+
// Destroy
|
|
622
|
+
// ====================================================================
|
|
623
|
+
|
|
624
|
+
destroy()
|
|
625
|
+
{
|
|
626
|
+
this._Schema = null;
|
|
627
|
+
this._Defaults = null;
|
|
628
|
+
this._FieldStates = null;
|
|
629
|
+
super.destroy();
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// ====================================================================
|
|
633
|
+
// Address Utilities
|
|
634
|
+
// ====================================================================
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Extract a bare Manyfest address from a Pict template expression.
|
|
638
|
+
*
|
|
639
|
+
* '{~D:Record.Operation.InputFilePath~}' → 'Operation.InputFilePath'
|
|
640
|
+
*
|
|
641
|
+
* @param {*} pTemplateString
|
|
642
|
+
* @returns {string}
|
|
643
|
+
*/
|
|
644
|
+
_extractAddressFromTemplate(pTemplateString)
|
|
645
|
+
{
|
|
646
|
+
if (typeof(pTemplateString) !== 'string')
|
|
647
|
+
{
|
|
648
|
+
return '';
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
let tmpMatch = pTemplateString.match(/\{~D:Record\.(.+?)~\}/);
|
|
652
|
+
return tmpMatch ? tmpMatch[1] : '';
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Build a Pict template expression from a bare Manyfest address.
|
|
657
|
+
*
|
|
658
|
+
* 'Operation.InputFilePath' → '{~D:Record.Operation.InputFilePath~}'
|
|
659
|
+
*
|
|
660
|
+
* @param {string} pAddress
|
|
661
|
+
* @returns {string}
|
|
662
|
+
*/
|
|
663
|
+
_buildTemplateFromAddress(pAddress)
|
|
664
|
+
{
|
|
665
|
+
if (!pAddress || typeof(pAddress) !== 'string')
|
|
666
|
+
{
|
|
667
|
+
return '';
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
return '{~D:Record.' + pAddress + '~}';
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// ====================================================================
|
|
674
|
+
// Escape Utilities
|
|
675
|
+
// ====================================================================
|
|
676
|
+
|
|
677
|
+
_escapeHTML(pString)
|
|
678
|
+
{
|
|
679
|
+
if (typeof(pString) !== 'string')
|
|
680
|
+
{
|
|
681
|
+
return '';
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
return pString
|
|
685
|
+
.replace(/&/g, '&')
|
|
686
|
+
.replace(/</g, '<')
|
|
687
|
+
.replace(/>/g, '>')
|
|
688
|
+
.replace(/"/g, '"');
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
_escapeAttr(pString)
|
|
692
|
+
{
|
|
693
|
+
if (typeof(pString) !== 'string')
|
|
694
|
+
{
|
|
695
|
+
return '';
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
return pString
|
|
699
|
+
.replace(/&/g, '&')
|
|
700
|
+
.replace(/"/g, '"')
|
|
701
|
+
.replace(/'/g, ''');
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// ====================================================================
|
|
705
|
+
// CSS Injection
|
|
706
|
+
// ====================================================================
|
|
707
|
+
|
|
708
|
+
_injectCSS()
|
|
709
|
+
{
|
|
710
|
+
if (this._CSSInjected)
|
|
711
|
+
{
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// Use the CSSMap service (same pattern as PictProvider-Flow-CSS)
|
|
716
|
+
if (this.fable && this.fable.CSSMap)
|
|
717
|
+
{
|
|
718
|
+
this.fable.CSSMap.addCSS('UltravisorCardSettingsPanel', UltravisorCardSettingsPanel.CSS, 600, 'UltravisorCardSettingsPanel');
|
|
719
|
+
this.fable.CSSMap.injectCSS();
|
|
720
|
+
this._CSSInjected = true;
|
|
721
|
+
}
|
|
722
|
+
else
|
|
723
|
+
{
|
|
724
|
+
this.log.warn('UltravisorCardSettingsPanel: CSSMap not available; CSS not registered.');
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// ========================================================================
|
|
730
|
+
// Static CSS
|
|
731
|
+
// ========================================================================
|
|
732
|
+
|
|
733
|
+
UltravisorCardSettingsPanel.CSS = [
|
|
734
|
+
'/* ── Ultravisor Card Settings Panel ───────────────────────────────── */',
|
|
735
|
+
|
|
736
|
+
'.uv-settings-panel {',
|
|
737
|
+
' padding: 8px 10px;',
|
|
738
|
+
'}',
|
|
739
|
+
|
|
740
|
+
'/* Field container */',
|
|
741
|
+
'.uv-settings-field {',
|
|
742
|
+
' margin-bottom: 10px;',
|
|
743
|
+
' padding-bottom: 8px;',
|
|
744
|
+
' border-bottom: 1px solid var(--pf-panel-titlebar-border, #343c44);',
|
|
745
|
+
'}',
|
|
746
|
+
'.uv-settings-field:last-child {',
|
|
747
|
+
' border-bottom: none;',
|
|
748
|
+
' margin-bottom: 0;',
|
|
749
|
+
'}',
|
|
750
|
+
|
|
751
|
+
'/* Field label */',
|
|
752
|
+
'.uv-settings-field-label {',
|
|
753
|
+
' font-weight: 600;',
|
|
754
|
+
' font-size: 0.82em;',
|
|
755
|
+
' color: var(--pf-panel-text, #c8d0d8);',
|
|
756
|
+
' margin-bottom: 4px;',
|
|
757
|
+
'}',
|
|
758
|
+
'.uv-settings-field-required {',
|
|
759
|
+
' color: #c44e4e;',
|
|
760
|
+
' margin-left: 1px;',
|
|
761
|
+
' font-weight: 700;',
|
|
762
|
+
'}',
|
|
763
|
+
|
|
764
|
+
'/* Input row: toggle button + editor side by side */',
|
|
765
|
+
'.uv-settings-field-row {',
|
|
766
|
+
' display: flex;',
|
|
767
|
+
' align-items: flex-start;',
|
|
768
|
+
' gap: 5px;',
|
|
769
|
+
'}',
|
|
770
|
+
|
|
771
|
+
'/* ── Mode toggle: single cycling button ─────────────────────────── */',
|
|
772
|
+
'.uv-mode-toggle {',
|
|
773
|
+
' flex-shrink: 0;',
|
|
774
|
+
' width: 22px;',
|
|
775
|
+
' height: 24px;',
|
|
776
|
+
' border: 1px solid var(--pf-panel-titlebar-border, #3a4450);',
|
|
777
|
+
' background: var(--pf-panel-bg, #1e2228);',
|
|
778
|
+
' color: #607080;',
|
|
779
|
+
' font-size: 0.72em;',
|
|
780
|
+
' font-style: italic;',
|
|
781
|
+
' font-weight: 700;',
|
|
782
|
+
' cursor: pointer;',
|
|
783
|
+
' border-radius: 3px;',
|
|
784
|
+
' padding: 0;',
|
|
785
|
+
' line-height: 24px;',
|
|
786
|
+
' text-align: center;',
|
|
787
|
+
' margin-top: 1px;',
|
|
788
|
+
'}',
|
|
789
|
+
'/* Mode-specific toggle colors (no :hover — causes compositor desync in SVG foreignObject) */',
|
|
790
|
+
'.uv-mode-toggle.uv-mode-constant {',
|
|
791
|
+
' border-color: #5ab88a60;',
|
|
792
|
+
' color: #5ab88a;',
|
|
793
|
+
' background: #1a2820;',
|
|
794
|
+
'}',
|
|
795
|
+
'.uv-mode-toggle.uv-mode-address {',
|
|
796
|
+
' border-color: #d4884a60;',
|
|
797
|
+
' color: #d4884a;',
|
|
798
|
+
' background: #2a1e14;',
|
|
799
|
+
'}',
|
|
800
|
+
'.uv-mode-toggle.uv-mode-default {',
|
|
801
|
+
' border-color: var(--pf-panel-titlebar-border, #3a4450);',
|
|
802
|
+
' color: #607080;',
|
|
803
|
+
' background: var(--pf-panel-bg, #1e2228);',
|
|
804
|
+
'}',
|
|
805
|
+
|
|
806
|
+
'/* ── Editor area ────────────────────────────────────────────────── */',
|
|
807
|
+
'.uv-settings-field-editor {',
|
|
808
|
+
' flex: 1;',
|
|
809
|
+
' min-width: 0;',
|
|
810
|
+
'}',
|
|
811
|
+
'.uv-settings-input {',
|
|
812
|
+
' width: 100%;',
|
|
813
|
+
' box-sizing: border-box;',
|
|
814
|
+
' padding: 4px 8px;',
|
|
815
|
+
' height: 26px;',
|
|
816
|
+
' border: 1px solid var(--pf-panel-titlebar-border, #343c44);',
|
|
817
|
+
' background: var(--pf-panel-input-bg, #181c22);',
|
|
818
|
+
' color: var(--pf-panel-text, #b8c4cc);',
|
|
819
|
+
' border-radius: 3px;',
|
|
820
|
+
' font-size: 0.82em;',
|
|
821
|
+
' font-family: inherit;',
|
|
822
|
+
'}',
|
|
823
|
+
'.uv-settings-input:focus {',
|
|
824
|
+
' border-color: #5a9ecb;',
|
|
825
|
+
' outline: none;',
|
|
826
|
+
'}',
|
|
827
|
+
'.uv-settings-textarea {',
|
|
828
|
+
' width: 100%;',
|
|
829
|
+
' box-sizing: border-box;',
|
|
830
|
+
' min-height: 56px;',
|
|
831
|
+
' padding: 4px 8px;',
|
|
832
|
+
' border: 1px solid var(--pf-panel-titlebar-border, #343c44);',
|
|
833
|
+
' background: var(--pf-panel-input-bg, #181c22);',
|
|
834
|
+
' color: var(--pf-panel-text, #b8c4cc);',
|
|
835
|
+
' border-radius: 3px;',
|
|
836
|
+
' font-family: monospace;',
|
|
837
|
+
' font-size: 0.78em;',
|
|
838
|
+
' resize: vertical;',
|
|
839
|
+
'}',
|
|
840
|
+
'.uv-settings-textarea:focus {',
|
|
841
|
+
' border-color: #5a9ecb;',
|
|
842
|
+
' outline: none;',
|
|
843
|
+
'}',
|
|
844
|
+
'.uv-settings-checkbox {',
|
|
845
|
+
' display: flex;',
|
|
846
|
+
' align-items: center;',
|
|
847
|
+
' gap: 6px;',
|
|
848
|
+
' height: 24px;',
|
|
849
|
+
' color: var(--pf-panel-text, #b8c4cc);',
|
|
850
|
+
' font-size: 0.82em;',
|
|
851
|
+
' cursor: pointer;',
|
|
852
|
+
'}',
|
|
853
|
+
'.uv-settings-checkbox input[type="checkbox"] {',
|
|
854
|
+
' accent-color: #5ab88a;',
|
|
855
|
+
'}',
|
|
856
|
+
|
|
857
|
+
'/* Address mode styling */',
|
|
858
|
+
'.uv-settings-address-input {',
|
|
859
|
+
' border-color: #d4884a40;',
|
|
860
|
+
' font-style: italic;',
|
|
861
|
+
'}',
|
|
862
|
+
'.uv-settings-address-input:focus {',
|
|
863
|
+
' border-color: #d4884a;',
|
|
864
|
+
'}',
|
|
865
|
+
|
|
866
|
+
'/* Default mode */',
|
|
867
|
+
'.uv-settings-default-display {',
|
|
868
|
+
' padding: 4px 8px;',
|
|
869
|
+
' height: 24px;',
|
|
870
|
+
' line-height: 16px;',
|
|
871
|
+
' background: transparent;',
|
|
872
|
+
' border: 1px dashed var(--pf-panel-titlebar-border, #343c44);',
|
|
873
|
+
' border-radius: 3px;',
|
|
874
|
+
' color: var(--pf-text-tertiary, #506878);',
|
|
875
|
+
' font-size: 0.78em;',
|
|
876
|
+
' font-style: italic;',
|
|
877
|
+
'}',
|
|
878
|
+
|
|
879
|
+
'/* Description */',
|
|
880
|
+
'.uv-settings-field-description {',
|
|
881
|
+
' font-size: 0.68em;',
|
|
882
|
+
' color: var(--pf-text-tertiary, #506070);',
|
|
883
|
+
' margin-top: 3px;',
|
|
884
|
+
' padding-left: 27px;',
|
|
885
|
+
' line-height: 1.3;',
|
|
886
|
+
'}'
|
|
887
|
+
].join('\n');
|
|
888
|
+
|
|
889
|
+
module.exports = UltravisorCardSettingsPanel;
|
|
890
|
+
|
|
891
|
+
module.exports.default_configuration = Object.assign(
|
|
892
|
+
{},
|
|
893
|
+
libPictFlowCardPropertiesPanel.default_configuration,
|
|
894
|
+
{
|
|
895
|
+
PanelType: 'UltravisorSettings',
|
|
896
|
+
Configuration:
|
|
897
|
+
{
|
|
898
|
+
Schema: [],
|
|
899
|
+
Defaults: {}
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
);
|