refactor: externalize local upload helpers
Add local-upload-runtime.js as a browser runtime module for upload and attachment helper functions, with sidebar fallback wrappers and a fixed runtime asset route. While validating task479, fix the editor attachment delete path so DOM-selected local attachment links are mapped back to a Tiptap text selection before delete_selection(), preserving undo history and adjacent links.
This commit is contained in:
@@ -98,6 +98,10 @@ pub fn build_router(state: AppState) -> Router {
|
||||
"/api/mnote-browser-runtime/resource-open-runtime.js",
|
||||
get(web_shell::resource_open_runtime_asset),
|
||||
)
|
||||
.route(
|
||||
"/api/mnote-browser-runtime/local-upload-runtime.js",
|
||||
get(web_shell::local_upload_runtime_asset),
|
||||
)
|
||||
.route(
|
||||
"/api/mnote-browser-runtime/tree-live-controller.js",
|
||||
get(web_shell::tree_live_controller_runtime_asset),
|
||||
|
||||
@@ -4381,6 +4381,20 @@ pub async fn resource_open_runtime_asset() -> Response {
|
||||
.unwrap_or_else(|_| Response::new(Body::empty()))
|
||||
}
|
||||
|
||||
pub async fn local_upload_runtime_asset() -> Response {
|
||||
const JS: &str = include_str!("../../browser/local-upload-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_live_controller_runtime_asset() -> Response {
|
||||
const JS: &str = include_str!("../../browser/tree-live-controller.js");
|
||||
Response::builder()
|
||||
|
||||
@@ -3140,15 +3140,27 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
}
|
||||
}
|
||||
|
||||
function localUploadRuntimeFunction(name) {
|
||||
var runtime = window.__mnoteLocalUploadRuntime;
|
||||
var fn = runtime && runtime[name];
|
||||
return typeof fn === 'function' ? fn : null;
|
||||
}
|
||||
|
||||
function uploadedAssetTitle(asset) {
|
||||
var runtimeFn = localUploadRuntimeFunction('uploadedAssetTitle');
|
||||
if (runtimeFn) return runtimeFn(asset);
|
||||
return String(asset && (asset.file_name || asset.title || asset.name) || '未命名附件').trim() || '未命名附件';
|
||||
}
|
||||
|
||||
function uploadedAssetUrl(asset) {
|
||||
var runtimeFn = localUploadRuntimeFunction('uploadedAssetUrl');
|
||||
if (runtimeFn) return runtimeFn(asset);
|
||||
return String(asset && (asset.sourcePath || asset.file_url || asset.signedUrl || asset.signed_url || asset.thumbnail_url) || '').trim();
|
||||
}
|
||||
|
||||
function localAssetOpenUrl(asset, download) {
|
||||
var runtimeFn = localUploadRuntimeFunction('localAssetOpenUrl');
|
||||
if (runtimeFn) return runtimeFn(asset, download, { rootUri: currentRootUri() });
|
||||
if (!isLocalUploadedAsset(asset)) return '';
|
||||
var rootUri = String(asset && (asset.rootUri || asset.root_uri) || '').trim() || currentRootUri();
|
||||
var rootRelativePath = String(asset && (asset.rootRelativePath || asset.root_relative_path) || '').trim();
|
||||
@@ -3161,10 +3173,14 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
}
|
||||
|
||||
function uploadedAssetType(asset) {
|
||||
var runtimeFn = localUploadRuntimeFunction('uploadedAssetType');
|
||||
if (runtimeFn) return runtimeFn(asset);
|
||||
return String(asset && (asset.asset_type || asset.assetType || asset.mime_type || '') || '').trim();
|
||||
}
|
||||
|
||||
function fileTreeIconKindForFileName(fileName) {
|
||||
var runtimeFn = localUploadRuntimeFunction('fileTreeIconKindForFileName');
|
||||
if (runtimeFn) return runtimeFn(fileName);
|
||||
var name = String(fileName || '').trim().toLowerCase();
|
||||
var ext = name.indexOf('.') >= 0 ? name.split('.').pop() : '';
|
||||
if (['doc', 'docx', 'odt', 'rtf', 'ppt', 'pptx', 'odp', 'xls', 'xlsx', 'ods', 'csv'].indexOf(ext) >= 0) return 'office';
|
||||
@@ -3179,16 +3195,22 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
}
|
||||
|
||||
function isLocalUploadedAsset(asset) {
|
||||
var runtimeFn = localUploadRuntimeFunction('isLocalUploadedAsset');
|
||||
if (runtimeFn) return runtimeFn(asset);
|
||||
var id = String(asset && asset.id || '').trim();
|
||||
return String(asset && asset.sourceKind || '').trim() === 'local_folder' || id.indexOf('local:asset:') === 0;
|
||||
}
|
||||
|
||||
function uploadedAssetExtension(asset) {
|
||||
var runtimeFn = localUploadRuntimeFunction('uploadedAssetExtension');
|
||||
if (runtimeFn) return runtimeFn(asset);
|
||||
var match = uploadedAssetTitle(asset).toLowerCase().match(/\.([a-z0-9]+)$/);
|
||||
return match ? match[1] : '';
|
||||
}
|
||||
|
||||
function isNonOfficeAttachmentName(name, ext) {
|
||||
var runtimeFn = localUploadRuntimeFunction('isNonOfficeAttachmentName');
|
||||
if (runtimeFn) return runtimeFn(name, ext);
|
||||
var codeFileNames = [
|
||||
'.dockerignore', '.editorconfig', '.env', '.eslintrc', '.gitattributes', '.gitignore', '.npmrc', '.prettierrc',
|
||||
'dockerfile', 'makefile', 'cmakelists.txt', 'gemfile', 'rakefile', 'procfile'
|
||||
@@ -3206,21 +3228,29 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
}
|
||||
|
||||
function attachmentExtensionFromFileName(fileName) {
|
||||
var runtimeFn = localUploadRuntimeFunction('attachmentExtensionFromFileName');
|
||||
if (runtimeFn) return runtimeFn(fileName);
|
||||
var name = String(fileName || '').trim().toLowerCase();
|
||||
return name.indexOf('.') >= 0 ? name.split('.').pop() : '';
|
||||
}
|
||||
|
||||
function isPdfAttachmentFileName(fileName) {
|
||||
var runtimeFn = localUploadRuntimeFunction('isPdfAttachmentFileName');
|
||||
if (runtimeFn) return runtimeFn(fileName);
|
||||
return attachmentExtensionFromFileName(fileName) === 'pdf';
|
||||
}
|
||||
|
||||
function isCodeAttachmentFileName(fileName) {
|
||||
var runtimeFn = localUploadRuntimeFunction('isCodeAttachmentFileName');
|
||||
if (runtimeFn) return runtimeFn(fileName);
|
||||
var name = String(fileName || '').trim().toLowerCase();
|
||||
var ext = attachmentExtensionFromFileName(name);
|
||||
return ext !== 'pdf' && isNonOfficeAttachmentName(name, ext);
|
||||
}
|
||||
|
||||
function inferCodeAttachmentLanguage(fileName) {
|
||||
var runtimeFn = localUploadRuntimeFunction('inferCodeAttachmentLanguage');
|
||||
if (runtimeFn) return runtimeFn(fileName);
|
||||
var name = String(fileName || '').trim().toLowerCase();
|
||||
var ext = attachmentExtensionFromFileName(name);
|
||||
var byName = {
|
||||
@@ -3250,6 +3280,8 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
}
|
||||
|
||||
function attachmentClassForFileName(fileName) {
|
||||
var runtimeFn = localUploadRuntimeFunction('attachmentClassForFileName');
|
||||
if (runtimeFn) return runtimeFn(fileName);
|
||||
var name = String(fileName || '').trim().toLowerCase();
|
||||
var ext = name.indexOf('.') >= 0 ? name.split('.').pop() : '';
|
||||
if (['doc', 'docx', 'odt', 'rtf'].indexOf(ext) >= 0) return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-word';
|
||||
@@ -3263,6 +3295,8 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
}
|
||||
|
||||
function uploadedAttachmentClass(asset) {
|
||||
var runtimeFn = localUploadRuntimeFunction('uploadedAttachmentClass');
|
||||
if (runtimeFn) return runtimeFn(asset);
|
||||
return attachmentClassForFileName(uploadedAssetTitle(asset));
|
||||
}
|
||||
|
||||
@@ -3296,6 +3330,8 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
}
|
||||
|
||||
function uploadedFileSize(asset) {
|
||||
var runtimeFn = localUploadRuntimeFunction('uploadedFileSize');
|
||||
if (runtimeFn) return runtimeFn(asset);
|
||||
var size = Number(asset && (asset.file_size || asset.fileSize) || 0);
|
||||
if (!Number.isFinite(size) || size <= 0) return '';
|
||||
if (size >= 1024 * 1024) return (size / 1024 / 1024).toFixed(size >= 10 * 1024 * 1024 ? 1 : 2) + ' MB';
|
||||
@@ -10417,6 +10453,7 @@ pub fn PageLayout(
|
||||
<div hidden data-testid="mnote-admin-access-policy-template-user" inner_html={user_access_policy_template}></div>
|
||||
<script inner_html={crate::ssr::pages::admin::ADMIN_POLICY_SCRIPT.to_string()}></script>
|
||||
<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 inner_html={SIDEBAR_TREE_JS.to_string()}></script>
|
||||
<script type="module" src="/api/mnote-browser-runtime/tree-live-controller.js"></script>
|
||||
</aside>
|
||||
|
||||
Reference in New Issue
Block a user