refactor: split tree shell state runtime
This commit is contained in:
@@ -10,6 +10,15 @@ import {
|
||||
createTreeShellActionButton,
|
||||
createTreeShellKindBadge as createKindBadge,
|
||||
} from "./tree-shell-icons-runtime.js";
|
||||
import {
|
||||
normalizeTreeShellNumber as normalizeNumber,
|
||||
normalizeTreeShellStringArray as normalizeStringArray,
|
||||
normalizeTreeShellText as normalizeText,
|
||||
parseTreeShellState,
|
||||
parseTreeShellStateFromHtml,
|
||||
resolveTreeShellMode,
|
||||
resolveTreeShellTargetOrigin,
|
||||
} from "./tree-shell-state-runtime.js";
|
||||
|
||||
function buildFileTreeRuntimeEnvironment(runtimeContext) {
|
||||
const fileTreeRowById = runtimeContext.fileTreeRowById || new Map();
|
||||
@@ -37,15 +46,7 @@ function startTreeShellRuntime() {
|
||||
return;
|
||||
}
|
||||
|
||||
const parseState = () => {
|
||||
try {
|
||||
return JSON.parse(stateElement.textContent || "{}");
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
const state = parseState();
|
||||
const state = parseTreeShellState(stateElement);
|
||||
const rendererInput =
|
||||
state.rendererInput && typeof state.rendererInput === "object"
|
||||
? state.rendererInput
|
||||
@@ -77,12 +78,6 @@ function startTreeShellRuntime() {
|
||||
runtimeArtifact.runtimeApi && typeof runtimeArtifact.runtimeApi === "object"
|
||||
? runtimeArtifact.runtimeApi
|
||||
: {};
|
||||
const normalizeStringArray = (value) =>
|
||||
Array.isArray(value)
|
||||
? value
|
||||
.map((item) => (typeof item === "string" ? item.trim() : ""))
|
||||
.filter(Boolean)
|
||||
: [];
|
||||
const hostOverride =
|
||||
window.__MNOTE_TREE_SHELL_OVERRIDE__ &&
|
||||
typeof window.__MNOTE_TREE_SHELL_OVERRIDE__ === "object"
|
||||
@@ -128,13 +123,7 @@ function startTreeShellRuntime() {
|
||||
: typeof state.activePickerItemKey === "string" && state.activePickerItemKey.trim()
|
||||
? state.activePickerItemKey.trim()
|
||||
: "";
|
||||
const mode = (() => {
|
||||
const rawMode =
|
||||
typeof state.mode === "string" ? state.mode.trim() : "";
|
||||
if (rawMode === "picker") return "picker";
|
||||
if (rawMode === "filetree") return "filetree";
|
||||
return "page";
|
||||
})();
|
||||
const mode = resolveTreeShellMode(state);
|
||||
const allowRootPick = state.allowRootPick === true;
|
||||
const excludedIds = new Set(
|
||||
normalizeStringArray(rendererInput.excludedPickerIds).length > 0
|
||||
@@ -171,20 +160,7 @@ function startTreeShellRuntime() {
|
||||
const titleElement = document.getElementById("tree-shell-title");
|
||||
const summaryElement = document.getElementById("tree-shell-summary");
|
||||
const toolbarElement = document.getElementById("tree-shell-toolbar");
|
||||
const targetOrigin = (() => {
|
||||
try {
|
||||
if (!document.referrer) return "*";
|
||||
return new URL(document.referrer).origin || "*";
|
||||
} catch {
|
||||
return "*";
|
||||
}
|
||||
})();
|
||||
|
||||
const normalizeText = (value, fallback = "") => {
|
||||
if (typeof value !== "string") return fallback;
|
||||
const trimmed = value.trim();
|
||||
return trimmed || fallback;
|
||||
};
|
||||
const targetOrigin = resolveTreeShellTargetOrigin(document);
|
||||
const initialRenameRowId = (() => {
|
||||
try {
|
||||
return normalizeText(new URL(window.location.href).searchParams.get("renameRowId"));
|
||||
@@ -202,10 +178,6 @@ function startTreeShellRuntime() {
|
||||
return normalized || null;
|
||||
};
|
||||
|
||||
const normalizeNumber = (value, fallback = Number.MAX_SAFE_INTEGER) => {
|
||||
return Number.isFinite(value) ? Number(value) : fallback;
|
||||
};
|
||||
|
||||
const normalizeRowKind = (value) => {
|
||||
const normalized = normalizeText(value).toLowerCase();
|
||||
if (normalized === "index") return "index";
|
||||
@@ -1544,17 +1516,6 @@ function startTreeShellRuntime() {
|
||||
}
|
||||
};
|
||||
|
||||
const parseTreeShellStateFromHtml = (html) => {
|
||||
const doc = new DOMParser().parseFromString(html, "text/html");
|
||||
const nextStateElement = doc.getElementById("tree-shell-state");
|
||||
if (!nextStateElement) return null;
|
||||
try {
|
||||
return JSON.parse(nextStateElement.textContent || "{}");
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const applyTreeShellStateSnapshot = (nextState, options = {}) => {
|
||||
if (!nextState || typeof nextState !== "object") return false;
|
||||
mediaAssets = Array.isArray(nextState.mediaAssets) ? nextState.mediaAssets : [];
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// MNote debug /tree shell state parsing and normalization helpers.
|
||||
|
||||
export function parseTreeShellState(stateElement) {
|
||||
try {
|
||||
return JSON.parse(stateElement?.textContent || "{}");
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeTreeShellText(value, fallback = "") {
|
||||
if (typeof value !== "string") return fallback;
|
||||
const trimmed = value.trim();
|
||||
return trimmed || fallback;
|
||||
}
|
||||
|
||||
export function normalizeTreeShellStringArray(value) {
|
||||
return Array.isArray(value)
|
||||
? value
|
||||
.map((item) => (typeof item === "string" ? item.trim() : ""))
|
||||
.filter(Boolean)
|
||||
: [];
|
||||
}
|
||||
|
||||
export function normalizeTreeShellNumber(value, fallback = Number.MAX_SAFE_INTEGER) {
|
||||
return Number.isFinite(value) ? Number(value) : fallback;
|
||||
}
|
||||
|
||||
export function resolveTreeShellMode(state) {
|
||||
const rawMode = typeof state?.mode === "string" ? state.mode.trim() : "";
|
||||
if (rawMode === "picker") return "picker";
|
||||
if (rawMode === "filetree") return "filetree";
|
||||
return "page";
|
||||
}
|
||||
|
||||
export function resolveTreeShellTargetOrigin(documentRef) {
|
||||
try {
|
||||
if (!documentRef?.referrer) return "*";
|
||||
return new URL(documentRef.referrer).origin || "*";
|
||||
} catch {
|
||||
return "*";
|
||||
}
|
||||
}
|
||||
|
||||
export function parseTreeShellStateFromHtml(html) {
|
||||
const doc = new DOMParser().parseFromString(html, "text/html");
|
||||
const nextStateElement = doc.getElementById("tree-shell-state");
|
||||
if (!nextStateElement) return null;
|
||||
try {
|
||||
return JSON.parse(nextStateElement.textContent || "{}");
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -170,6 +170,10 @@ pub fn build_router(state: AppState) -> Router {
|
||||
"/api/mnote-browser-runtime/tree-shell-page-runtime.js",
|
||||
get(web_shell::tree_shell_page_runtime_asset),
|
||||
)
|
||||
.route(
|
||||
"/api/mnote-browser-runtime/tree-shell-state-runtime.js",
|
||||
get(web_shell::tree_shell_state_runtime_asset),
|
||||
)
|
||||
.route(
|
||||
"/api/mnote-browser-runtime/tree-shell-icons-runtime.js",
|
||||
get(web_shell::tree_shell_icons_runtime_asset),
|
||||
@@ -626,6 +630,7 @@ mod tests {
|
||||
"/api/mnote-browser-runtime/tree-live-controller.js",
|
||||
"/api/mnote-browser-runtime/tree-shell-runtime.js",
|
||||
"/api/mnote-browser-runtime/tree-shell-page-runtime.js",
|
||||
"/api/mnote-browser-runtime/tree-shell-state-runtime.js",
|
||||
"/api/mnote-browser-runtime/tree-shell-icons-runtime.js",
|
||||
"/api/mnote-browser-runtime/document-conflict-panel-runtime.js",
|
||||
"/api/mnote-browser-runtime/document-pane-runtime.js",
|
||||
|
||||
@@ -952,6 +952,20 @@ pub async fn tree_shell_page_runtime_asset() -> Response {
|
||||
.unwrap_or_else(|_| Response::new(Body::empty()))
|
||||
}
|
||||
|
||||
pub async fn tree_shell_state_runtime_asset() -> Response {
|
||||
const JS: &str = include_str!("../../browser/tree-shell-state-runtime.js");
|
||||
Response::builder()
|
||||
.status(StatusCode::OK)
|
||||
.header(
|
||||
header::CONTENT_TYPE,
|
||||
"application/javascript; charset=utf-8",
|
||||
)
|
||||
.header(header::CACHE_CONTROL, "no-store")
|
||||
.header(HEADER_MNOTE_WEB_OWNER, "mnote-web")
|
||||
.body(Body::from(JS))
|
||||
.unwrap_or_else(|_| Response::new(Body::empty()))
|
||||
}
|
||||
|
||||
pub async fn tree_shell_icons_runtime_asset() -> Response {
|
||||
const JS: &str = include_str!("../../browser/tree-shell-icons-runtime.js");
|
||||
Response::builder()
|
||||
|
||||
Reference in New Issue
Block a user