refactor: externalize filetree selection runtime

This commit is contained in:
lix-2026
2026-05-25 00:37:47 +08:00
parent 2f01dc3a2e
commit ec623c9a82
6 changed files with 335 additions and 50 deletions
@@ -3162,6 +3162,18 @@ const SIDEBAR_TREE_JS: &str = r##"
};
}
function fileTreeSelectionRuntimeFunction(name) {
var runtime = window.__mnoteFileTreeSelectionRuntime;
var fn = runtime && runtime[name];
return typeof fn === 'function' ? fn : null;
}
function fileTreeSelectionRuntimeDeps() {
return {
cssEscape: cssEscape
};
}
function uploadedAssetTitle(asset) {
var runtimeFn = localUploadRuntimeFunction('uploadedAssetTitle');
if (runtimeFn) return runtimeFn(asset);
@@ -4946,6 +4958,8 @@ const SIDEBAR_TREE_JS: &str = r##"
}
function visibleFileTreeRows() {
var runtimeFn = fileTreeSelectionRuntimeFunction('visibleFileTreeRows');
if (runtimeFn) return runtimeFn(fileTreeSelectionRuntimeDeps());
return Array.from(document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"]'))
.filter(function(row) {
if (!(row instanceof HTMLElement)) return false;
@@ -4955,6 +4969,11 @@ const SIDEBAR_TREE_JS: &str = r##"
}
function syncSidebarFileTreeSelection() {
var runtimeFn = fileTreeSelectionRuntimeFunction('syncSidebarFileTreeSelection');
if (runtimeFn) {
runtimeFn(sidebarFileTreeSelection, fileTreeSelectionRuntimeDeps());
return;
}
var rows = visibleFileTreeRows();
rows.forEach(function(row) {
var rowId = row.getAttribute('data-row-id') || '';
@@ -4971,6 +4990,8 @@ const SIDEBAR_TREE_JS: &str = r##"
}
function selectSidebarFileTreeRow(row, modifiers) {
var runtimeFn = fileTreeSelectionRuntimeFunction('selectSidebarFileTreeRow');
if (runtimeFn) return runtimeFn(row, sidebarFileTreeSelection, modifiers, fileTreeSelectionRuntimeDeps());
if (!(row instanceof HTMLElement)) return [];
var rowId = row.getAttribute('data-row-id') || '';
if (!rowId) return [];
@@ -5110,6 +5131,8 @@ const SIDEBAR_TREE_JS: &str = r##"
}
function selectedSidebarFileTreeRowIdsForDrag(row) {
var runtimeFn = fileTreeSelectionRuntimeFunction('selectedSidebarFileTreeRowIdsForDrag');
if (runtimeFn) return runtimeFn(row, sidebarFileTreeSelection);
var rowId = row instanceof HTMLElement ? row.getAttribute('data-row-id') || '' : '';
if (rowId && sidebarFileTreeSelection.selectedRowIds.has(rowId)) {
return Array.from(sidebarFileTreeSelection.selectedRowIds);
@@ -5118,6 +5141,8 @@ const SIDEBAR_TREE_JS: &str = r##"
}
function selectedSidebarFileTreeRows() {
var runtimeFn = fileTreeSelectionRuntimeFunction('selectedSidebarFileTreeRows');
if (runtimeFn) return runtimeFn(sidebarFileTreeSelection, fileTreeSelectionRuntimeDeps());
var selectedIds = sidebarFileTreeSelection.selectedRowIds;
var rows = visibleFileTreeRows().filter(function(row) {
var rowId = row.getAttribute('data-row-id') || '';
@@ -10538,6 +10563,7 @@ pub fn PageLayout(
<script type="module" src="/api/mnote-browser-runtime/resource-open-runtime.js"></script>
<script type="module" src="/api/mnote-browser-runtime/local-upload-runtime.js"></script>
<script type="module" src="/api/mnote-browser-runtime/filetree-runtime.js"></script>
<script type="module" src="/api/mnote-browser-runtime/filetree-selection-runtime.js"></script>
<script type="module" src="/api/mnote-browser-runtime/filetree-context-menu-runtime.js"></script>
<script inner_html={SIDEBAR_TREE_JS.to_string()}></script>
<script type="module" src="/api/mnote-browser-runtime/tree-live-controller.js"></script>
@@ -10582,6 +10608,8 @@ mod tests {
const FILETREE_CONTEXT_MENU_RUNTIME_JS: &str =
include_str!("../../../browser/filetree-context-menu-runtime.js");
const FILETREE_RUNTIME_JS: &str = include_str!("../../../browser/filetree-runtime.js");
const FILETREE_SELECTION_RUNTIME_JS: &str =
include_str!("../../../browser/filetree-selection-runtime.js");
const TREE_LIVE_CONTROLLER_JS: &str = include_str!("../../../browser/tree-live-controller.js");
fn js_function_body(source: &str, name: &str) -> String {
@@ -10937,6 +10965,40 @@ mod tests {
assert!(FILETREE_RUNTIME_JS.contains("function fileTreeChildCount"));
}
#[test]
fn sidebar_filetree_selection_runtime_helpers_are_externalized_with_inline_fallback() {
assert!(SIDEBAR_TREE_JS.contains("function fileTreeSelectionRuntimeFunction"));
assert!(SIDEBAR_TREE_JS.contains("window.__mnoteFileTreeSelectionRuntime"));
assert!(SIDEBAR_TREE_JS.contains("fileTreeSelectionRuntimeFunction('visibleFileTreeRows')"));
assert!(SIDEBAR_TREE_JS
.contains("fileTreeSelectionRuntimeFunction('syncSidebarFileTreeSelection')"));
assert!(SIDEBAR_TREE_JS
.contains("fileTreeSelectionRuntimeFunction('selectSidebarFileTreeRow')"));
assert!(SIDEBAR_TREE_JS
.contains("fileTreeSelectionRuntimeFunction('selectedSidebarFileTreeRowIdsForDrag')"));
assert!(SIDEBAR_TREE_JS
.contains("fileTreeSelectionRuntimeFunction('selectedSidebarFileTreeRows')"));
let select_body = js_function_body(SIDEBAR_TREE_JS, "selectSidebarFileTreeRow");
assert!(
select_body.contains("shiftKey && sidebarFileTreeSelection.anchorRowId")
&& select_body.contains("ctrlKey"),
"inline fallback 必须保留 shift range 与 ctrl/meta toggle"
);
}
#[test]
fn filetree_selection_runtime_contains_selection_helpers() {
assert!(FILETREE_SELECTION_RUNTIME_JS.contains("window.__mnoteFileTreeSelectionRuntime"));
assert!(FILETREE_SELECTION_RUNTIME_JS.contains("function visibleFileTreeRows"));
assert!(FILETREE_SELECTION_RUNTIME_JS.contains("function syncSidebarFileTreeSelection"));
assert!(FILETREE_SELECTION_RUNTIME_JS.contains("function selectSidebarFileTreeRow"));
assert!(
FILETREE_SELECTION_RUNTIME_JS.contains("function selectedSidebarFileTreeRowIdsForDrag")
);
assert!(FILETREE_SELECTION_RUNTIME_JS.contains("function selectedSidebarFileTreeRows"));
assert!(FILETREE_SELECTION_RUNTIME_JS.contains("tree.filetree.selection.changed"));
}
#[test]
fn sidebar_tree_runtime_focuses_restored_local_folder_row() {
assert!(SIDEBAR_TREE_JS.contains("applyPendingLocalFolderRestoreFocusOnce"));