mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-26 04:12:07 +00:00
feat: plugins config APIs
This commit is contained in:
@@ -151,16 +151,27 @@
|
||||
<div id="configEditor" class="config-editor" hidden>
|
||||
<textarea id="configText" class="config-textarea thin-scroll" spellcheck="false"
|
||||
autocomplete="off" autocapitalize="off" aria-label="Capability configuration (JSON)"></textarea>
|
||||
<div class="config-editor-footer">
|
||||
<span id="configValidation" class="config-validation" role="status" aria-live="polite"></span>
|
||||
<button id="configSaveBtn" class="ButtonStyleConfirm ButtonTypeChoice" type="button">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Custom capability UI. Sandboxed without allow-same-origin, so the plugin's HTML
|
||||
runs in an opaque origin: it cannot touch this page, and the only host surface
|
||||
it gets is the window.orca getConfig/saveConfig bridge injected into srcdoc. -->
|
||||
<iframe id="configCustom" class="config-custom" title="Plugin configuration"
|
||||
sandbox="allow-scripts" referrerpolicy="no-referrer" hidden></iframe>
|
||||
<!-- Host chrome for both editors, not just the JSON one: a capability with a custom
|
||||
UI needs Restore just as much, and keeping it here leaves it out of the plugin's
|
||||
HTML and off the JS bridge. Save and the validation message belong to the JSON
|
||||
editor alone (a custom UI saves through its own controls), so they are hidden
|
||||
when a custom UI is showing. -->
|
||||
<div id="configFooter" class="config-view-footer" hidden>
|
||||
<span id="configValidation" class="config-validation" role="status" aria-live="polite"></span>
|
||||
<div class="config-actions">
|
||||
<button id="configRestoreBtn" class="ButtonStyleRegular ButtonTypeChoice" type="button"
|
||||
title="Discard the settings saved for this capability and restore the plugin's defaults">
|
||||
Restore defaults
|
||||
</button>
|
||||
<button id="configSaveBtn" class="ButtonStyleConfirm ButtonTypeChoice" type="button">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -70,7 +70,15 @@ function OnInit() {
|
||||
|
||||
document.getElementById("configSidebar")?.addEventListener("click", OnConfigSidebarClick);
|
||||
document.getElementById("configSaveBtn")?.addEventListener("click", SaveCapabilityConfig);
|
||||
document.getElementById("configText")?.addEventListener("input", ValidateConfigText);
|
||||
document.getElementById("configRestoreBtn")?.addEventListener("click", RestoreCapabilityConfig);
|
||||
|
||||
const configText = document.getElementById("configText");
|
||||
// why: common.js installs a document-level onkeydown that cancels the default action of every key
|
||||
// (returnValue=false) to block webview shortcuts; on the way up it also swallows typing. Stop
|
||||
// the editor's keydowns from bubbling to it so the textarea stays editable, leaving the global
|
||||
// guard intact. Same treatment as the search field (see plugin-search.js).
|
||||
configText?.addEventListener("keydown", (event) => event.stopPropagation());
|
||||
configText?.addEventListener("input", ValidateConfigText);
|
||||
// The custom capability UI is sandboxed into an opaque origin, so it reaches us only through
|
||||
// postMessage. Match on the frame's own contentWindow rather than the origin (which is "null"
|
||||
// for a sandboxed frame) and ignore anything else on the channel.
|
||||
@@ -939,12 +947,14 @@ function RequestCapabilityConfig() {
|
||||
}
|
||||
|
||||
// Empties both editors, so nothing from the previously selected capability can linger while the
|
||||
// next one is still in flight.
|
||||
// next one is still in flight. The footer goes with them: until a config has actually loaded there
|
||||
// is nothing to save or restore.
|
||||
function ClearCapabilityConfigView() {
|
||||
const editor = document.getElementById("configEditor");
|
||||
const custom = document.getElementById("configCustom");
|
||||
const text = document.getElementById("configText");
|
||||
const error = document.getElementById("configError");
|
||||
const footer = document.getElementById("configFooter");
|
||||
|
||||
if (editor)
|
||||
editor.hidden = true;
|
||||
@@ -958,6 +968,8 @@ function ClearCapabilityConfigView() {
|
||||
error.hidden = true;
|
||||
error.textContent = "";
|
||||
}
|
||||
if (footer)
|
||||
footer.hidden = true;
|
||||
SetConfigValidation("");
|
||||
}
|
||||
|
||||
@@ -986,6 +998,10 @@ function ApplyCapabilityConfig(payload) {
|
||||
const config = (payload && typeof payload.config === "object" && payload.config !== null) ? payload.config : {};
|
||||
const html = String(payload?.custom_html || "");
|
||||
|
||||
// Restore is host chrome and applies to either editor; Save and the validation message belong to
|
||||
// the JSON editor, since a custom UI saves through its own controls via the bridge.
|
||||
ShowConfigFooter(!html);
|
||||
|
||||
if (html) {
|
||||
// A capability with its own UI: hand it the config through the bridge, never the raw file.
|
||||
if (custom) {
|
||||
@@ -1010,6 +1026,21 @@ function ApplyCapabilityConfig(payload) {
|
||||
SetConfigValidation("");
|
||||
}
|
||||
|
||||
// Reveals the footer for the loaded capability. `withEditorControls` is false for a custom UI,
|
||||
// leaving Restore on its own.
|
||||
function ShowConfigFooter(withEditorControls) {
|
||||
const footer = document.getElementById("configFooter");
|
||||
const save = document.getElementById("configSaveBtn");
|
||||
const validation = document.getElementById("configValidation");
|
||||
|
||||
if (footer)
|
||||
footer.hidden = false;
|
||||
if (save)
|
||||
save.hidden = !withEditorControls;
|
||||
if (validation)
|
||||
validation.hidden = !withEditorControls;
|
||||
}
|
||||
|
||||
function SetConfigValidation(message) {
|
||||
const node = document.getElementById("configValidation");
|
||||
const save = document.getElementById("configSaveBtn");
|
||||
@@ -1054,6 +1085,21 @@ function SaveCapabilityConfig() {
|
||||
});
|
||||
}
|
||||
|
||||
// Asks the native side to write the capability's default config over whatever is stored. The
|
||||
// defaults come from the capability's get_default_config(), never from this page — the host does not
|
||||
// know what a given plugin considers default. The native side confirms before discarding anything,
|
||||
// and replies with the same "saved" payload, so both editors reload from what was persisted.
|
||||
function RestoreCapabilityConfig() {
|
||||
if (!selectedPluginId || !selectedCapabilityName)
|
||||
return;
|
||||
|
||||
SendMessage("restore_capability_config", {
|
||||
plugin_key: selectedPluginId,
|
||||
capability_name: selectedCapabilityName,
|
||||
capability_type: selectedCapabilityType
|
||||
});
|
||||
}
|
||||
|
||||
function ApplyCapabilityConfigSaved(payload) {
|
||||
if (!IsCurrentCapability(payload))
|
||||
return;
|
||||
|
||||
@@ -1182,9 +1182,9 @@ body {
|
||||
min-height: 0;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
/* common.css applies `user-select: none` to *, which in WebKit also stops a textarea taking a
|
||||
caret — the editor would be focusable but impossible to type into. Editable surfaces have to
|
||||
opt back in (same as include/xterm/xterm.css does for the terminal). */
|
||||
/* common.css applies `user-select: none` to *, so without this the user could type into the
|
||||
editor but not select, drag or copy what they had typed. (What blocks typing is the global
|
||||
onkeydown guard in common.js — see the keydown handler in index.js.) */
|
||||
-webkit-user-select: text;
|
||||
user-select: text;
|
||||
border: 1px solid var(--border);
|
||||
@@ -1204,13 +1204,29 @@ body {
|
||||
border-color: var(--main-color);
|
||||
}
|
||||
|
||||
.config-editor-footer {
|
||||
.config-view-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.config-view-footer[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Restore sits immediately left of Save, both pinned right; the validation message takes the
|
||||
remaining space on the left. */
|
||||
.config-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.config-actions > button[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.config-validation {
|
||||
color: var(--muted);
|
||||
font-size: 11px;
|
||||
|
||||
Reference in New Issue
Block a user