refactor: split tree shell page runtime
This commit is contained in:
+1
-1
@@ -205,7 +205,7 @@ cargo test --manifest-path rust/Cargo.toml -p mnote-web --lib ssr::pages::layout
|
||||
拆分项:
|
||||
|
||||
- [ ] D1. `tree-shell-state-runtime.js`:state hydration、serialization、patch dispatch。
|
||||
- [ ] D2. `tree-shell-page-runtime.js`:page tree keyboard、expand、focus、drag/drop intent。
|
||||
- [x] D2. `tree-shell-page-runtime.js`:page tree keyboard、expand、focus、drag/drop intent。
|
||||
- [ ] D3. `tree-shell-filetree-runtime.js`:filetree row normalization、resource meta、open target。
|
||||
- [ ] D4. `tree-shell-picker-runtime.js`:picker search/focus/pick root。
|
||||
- [ ] D5. `tree-shell-dom-runtime.js`:DOM patch/render helpers。
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
// MNote debug /tree shell page-mode runtime helpers.
|
||||
|
||||
export async function reducePageActionWithRuntime(runtimeContext, action, item) {
|
||||
if (runtimeContext.mode !== "page" || !runtimeContext.runtimeReduceEndpoint) {
|
||||
return null;
|
||||
}
|
||||
const runtimeAction = runtimeContext.buildPageRuntimeAction(action, item);
|
||||
if (!runtimeAction) return null;
|
||||
const response = await fetch(runtimeContext.runtimeReduceEndpoint, {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
mode: "page",
|
||||
requestId: `page-runtime-${Date.now()}`,
|
||||
environment: runtimeContext.buildPageRuntimeEnvironment(),
|
||||
state: runtimeContext.readPageRuntimeState(action, item),
|
||||
action: runtimeAction,
|
||||
}),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(await runtimeContext.readErrorMessage(response));
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
export function reconcilePageRuntimeResult(runtimeContext, runtimeResult, item) {
|
||||
const result = runtimeContext.normalizePageRuntimeResult(runtimeResult);
|
||||
if (!result) return false;
|
||||
const previousExpanded = new Set(runtimeContext.expanded);
|
||||
let shouldPatchTree = false;
|
||||
if (Array.isArray(result.expandedIds)) {
|
||||
shouldPatchTree =
|
||||
runtimeContext.commitPageExpandedIds(result.expandedIds) || shouldPatchTree;
|
||||
}
|
||||
const currentFocusedNodeId = runtimeContext.getFocusedNodeId();
|
||||
if (result.focusedId && result.focusedId !== currentFocusedNodeId) {
|
||||
runtimeContext.setFocusedNodeId(result.focusedId);
|
||||
runtimeContext.postPageFocusChange(result.focusedId);
|
||||
shouldPatchTree = true;
|
||||
}
|
||||
const itemNodeId = runtimeContext.normalizeText(item?.nodeId);
|
||||
if (
|
||||
itemNodeId &&
|
||||
previousExpanded.has(itemNodeId) !== runtimeContext.expanded.has(itemNodeId)
|
||||
) {
|
||||
runtimeContext.postPageExpandChange(itemNodeId, runtimeContext.expanded.has(itemNodeId));
|
||||
}
|
||||
if (shouldPatchTree) {
|
||||
runtimeContext.patchPageTreeAfterRuntimeState(
|
||||
Array.isArray(result.expandedIds) ? [itemNodeId, ...result.expandedIds] : [itemNodeId],
|
||||
result.focusedId || runtimeContext.getFocusedNodeId(),
|
||||
);
|
||||
}
|
||||
return shouldPatchTree;
|
||||
}
|
||||
@@ -1,6 +1,11 @@
|
||||
// MNote debug /tree shell 浏览器运行时外置模块。
|
||||
// 该文件由 tree.rs 原 inline runtime 同构迁出,语义仍由 Rust tree_shell reducer 主导。
|
||||
|
||||
import {
|
||||
reconcilePageRuntimeResult,
|
||||
reducePageActionWithRuntime,
|
||||
} from "./tree-shell-page-runtime.js";
|
||||
|
||||
function buildFileTreeRuntimeEnvironment(runtimeContext) {
|
||||
const fileTreeRowById = runtimeContext.fileTreeRowById || new Map();
|
||||
return {
|
||||
@@ -17,60 +22,6 @@ function buildFileTreeRuntimeEnvironment(runtimeContext) {
|
||||
};
|
||||
}
|
||||
|
||||
async function reducePageActionWithRuntime(runtimeContext, action, item) {
|
||||
if (runtimeContext.mode !== "page" || !runtimeContext.runtimeReduceEndpoint) {
|
||||
return null;
|
||||
}
|
||||
const runtimeAction = runtimeContext.buildPageRuntimeAction(action, item);
|
||||
if (!runtimeAction) return null;
|
||||
const response = await fetch(runtimeContext.runtimeReduceEndpoint, {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
mode: "page",
|
||||
requestId: `page-runtime-${Date.now()}`,
|
||||
environment: runtimeContext.buildPageRuntimeEnvironment(),
|
||||
state: runtimeContext.readPageRuntimeState(action, item),
|
||||
action: runtimeAction,
|
||||
}),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(await runtimeContext.readErrorMessage(response));
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
function reconcilePageRuntimeResult(runtimeContext, runtimeResult, item) {
|
||||
const result = runtimeContext.normalizePageRuntimeResult(runtimeResult);
|
||||
if (!result) return false;
|
||||
const previousExpanded = new Set(runtimeContext.expanded);
|
||||
let shouldPatchTree = false;
|
||||
if (Array.isArray(result.expandedIds)) {
|
||||
shouldPatchTree =
|
||||
runtimeContext.commitPageExpandedIds(result.expandedIds) || shouldPatchTree;
|
||||
}
|
||||
const currentFocusedNodeId = runtimeContext.getFocusedNodeId();
|
||||
if (result.focusedId && result.focusedId !== currentFocusedNodeId) {
|
||||
runtimeContext.setFocusedNodeId(result.focusedId);
|
||||
runtimeContext.postPageFocusChange(result.focusedId);
|
||||
shouldPatchTree = true;
|
||||
}
|
||||
const itemNodeId = runtimeContext.normalizeText(item?.nodeId);
|
||||
if (
|
||||
itemNodeId &&
|
||||
previousExpanded.has(itemNodeId) !== runtimeContext.expanded.has(itemNodeId)
|
||||
) {
|
||||
runtimeContext.postPageExpandChange(itemNodeId, runtimeContext.expanded.has(itemNodeId));
|
||||
}
|
||||
if (shouldPatchTree) {
|
||||
runtimeContext.patchPageTreeAfterRuntimeState(
|
||||
Array.isArray(result.expandedIds) ? [itemNodeId, ...result.expandedIds] : [itemNodeId],
|
||||
result.focusedId || runtimeContext.getFocusedNodeId(),
|
||||
);
|
||||
}
|
||||
return shouldPatchTree;
|
||||
}
|
||||
|
||||
function startTreeShellRuntime() {
|
||||
const stateElement = document.getElementById("tree-shell-state");
|
||||
const appElement = document.getElementById("tree-shell-app");
|
||||
|
||||
@@ -166,6 +166,10 @@ pub fn build_router(state: AppState) -> Router {
|
||||
"/api/mnote-browser-runtime/tree-shell-runtime.js",
|
||||
get(web_shell::tree_shell_runtime_asset),
|
||||
)
|
||||
.route(
|
||||
"/api/mnote-browser-runtime/tree-shell-page-runtime.js",
|
||||
get(web_shell::tree_shell_page_runtime_asset),
|
||||
)
|
||||
.route(
|
||||
"/api/mnote-browser-runtime/document-conflict-panel-runtime.js",
|
||||
get(web_shell::document_conflict_panel_runtime_asset),
|
||||
@@ -617,6 +621,7 @@ mod tests {
|
||||
"/api/mnote-browser-runtime/sidebar-tree-runtime.js",
|
||||
"/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/document-conflict-panel-runtime.js",
|
||||
"/api/mnote-browser-runtime/document-pane-runtime.js",
|
||||
"/api/mnote-browser-runtime/document-mindmap-host-runtime.js",
|
||||
|
||||
@@ -938,6 +938,20 @@ pub async fn tree_shell_runtime_asset() -> Response {
|
||||
.unwrap_or_else(|_| Response::new(Body::empty()))
|
||||
}
|
||||
|
||||
pub async fn tree_shell_page_runtime_asset() -> Response {
|
||||
const JS: &str = include_str!("../../browser/tree-shell-page-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 document_conflict_panel_runtime_asset() -> Response {
|
||||
// include_str! 路径相对于当前源文件 (src/routes/web_shell.rs -> ../../browser/)
|
||||
const JS: &str = include_str!("../../browser/document-conflict-panel-runtime.js");
|
||||
|
||||
Reference in New Issue
Block a user