refactor: split tiptap block transform helpers
This commit is contained in:
+1
-1
@@ -252,7 +252,7 @@ cargo test --manifest-path rust/Cargo.toml -p mnote-web --lib routes::tree -- --
|
||||
|
||||
验收标准:
|
||||
|
||||
- [ ] `lib.rs` 少于 5,000 行。
|
||||
- [x] `lib.rs` 少于 5,000 行。
|
||||
- [ ] `block_handle_menu_view.rs` 可以超过 1,500 行,但必须有清晰入参 struct,避免二十多个 signal 直接散落。
|
||||
- [ ] 不改变 Tiptap command 行为,不新增编辑器功能。
|
||||
|
||||
|
||||
@@ -1,5 +1,273 @@
|
||||
use leptos_tiptap::{
|
||||
TiptapCodeBlockAttributes, TiptapColorAttributes, TiptapContent, TiptapEditorHandle,
|
||||
TiptapHeadingLevel, TiptapHighlightAttributes, TiptapNodeName, TiptapSchemaTarget,
|
||||
TiptapTextAlign, TiptapTocNodeAttrs,
|
||||
};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use crate::editor_runtime::attachment_upload::dispatch_editor_upload_request;
|
||||
use crate::editor_runtime::block_menu_document::mindmap_paragraph_node;
|
||||
use crate::editor_runtime::slash_actions::SlashActionKind;
|
||||
|
||||
pub(crate) fn apply_text_color(
|
||||
editor: TiptapEditorHandle,
|
||||
color: &str,
|
||||
) -> Result<&'static str, String> {
|
||||
editor
|
||||
.set_color(TiptapColorAttributes {
|
||||
color: color.to_string(),
|
||||
})
|
||||
.map(|_| "已更新文字颜色")
|
||||
.map_err(|err| format!("命令执行失败:{err}"))
|
||||
}
|
||||
|
||||
pub(crate) fn clear_text_color(editor: TiptapEditorHandle) -> Result<&'static str, String> {
|
||||
editor
|
||||
.unset_color()
|
||||
.map(|_| "已清除文字颜色")
|
||||
.map_err(|err| format!("命令执行失败:{err}"))
|
||||
}
|
||||
|
||||
pub(crate) fn apply_highlight_color(
|
||||
editor: TiptapEditorHandle,
|
||||
color: Option<&str>,
|
||||
) -> Result<&'static str, String> {
|
||||
match color {
|
||||
Some(color) => editor
|
||||
.set_highlight(Some(TiptapHighlightAttributes {
|
||||
color: Some(color.to_string()),
|
||||
}))
|
||||
.map(|_| "已更新背景色")
|
||||
.map_err(|err| format!("命令执行失败:{err}")),
|
||||
None => editor
|
||||
.unset_highlight()
|
||||
.map(|_| "已清除背景色")
|
||||
.map_err(|err| format!("命令执行失败:{err}")),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn apply_text_align(
|
||||
editor: TiptapEditorHandle,
|
||||
alignment: TiptapTextAlign,
|
||||
) -> Result<&'static str, String> {
|
||||
let message = match alignment {
|
||||
TiptapTextAlign::Left => "已切到左对齐",
|
||||
TiptapTextAlign::Center => "已切到居中",
|
||||
TiptapTextAlign::Right => "已切到右对齐",
|
||||
TiptapTextAlign::Justify => "已切到两端对齐",
|
||||
};
|
||||
editor
|
||||
.set_text_align(alignment)
|
||||
.map(|_| message)
|
||||
.map_err(|err| format!("命令执行失败:{err}"))
|
||||
}
|
||||
|
||||
pub(crate) fn apply_image_align(
|
||||
editor: TiptapEditorHandle,
|
||||
align: &'static str,
|
||||
) -> Result<&'static str, String> {
|
||||
let _ = editor.focus();
|
||||
let mut attrs = leptos_tiptap::TiptapAttributes::new();
|
||||
attrs.insert("data-align", align);
|
||||
editor
|
||||
.update_attributes(TiptapSchemaTarget::Node(TiptapNodeName::Image), attrs)
|
||||
.map(|_| "已更新图片对齐")
|
||||
.map_err(|err| format!("命令执行失败:{err}"))
|
||||
}
|
||||
|
||||
pub(crate) fn run_slash_action(
|
||||
editor: TiptapEditorHandle,
|
||||
action: SlashActionKind,
|
||||
) -> Result<&'static str, String> {
|
||||
let result = match action {
|
||||
SlashActionKind::AiAssistant
|
||||
| SlashActionKind::AiWrite
|
||||
| SlashActionKind::ContinueWriting
|
||||
| SlashActionKind::Summarize
|
||||
| SlashActionKind::MoreAi => return Ok("AI 命令入口已打开"),
|
||||
SlashActionKind::Paragraph => editor.set_paragraph(),
|
||||
SlashActionKind::Heading1 => editor.toggle_heading(TiptapHeadingLevel::H1),
|
||||
SlashActionKind::Heading2 => editor.toggle_heading(TiptapHeadingLevel::H2),
|
||||
SlashActionKind::Heading3 => editor.toggle_heading(TiptapHeadingLevel::H3),
|
||||
SlashActionKind::Heading4 => editor.toggle_heading(TiptapHeadingLevel::H4),
|
||||
SlashActionKind::BulletList => editor.toggle_bullet_list(),
|
||||
SlashActionKind::OrderedList => editor.toggle_ordered_list(),
|
||||
SlashActionKind::Todo | SlashActionKind::AdvancedTodo => editor.toggle_task_list(),
|
||||
SlashActionKind::Quote => editor.toggle_blockquote(),
|
||||
SlashActionKind::CodeBlock => editor.toggle_code_block(Some(TiptapCodeBlockAttributes {
|
||||
language: Some("rust".into()),
|
||||
})),
|
||||
SlashActionKind::Divider => editor.set_horizontal_rule(),
|
||||
SlashActionKind::SimpleTable => {
|
||||
let _ = editor.focus();
|
||||
editor.insert_table(4, 3, false)
|
||||
}
|
||||
SlashActionKind::Mindmap => {
|
||||
editor.insert_content(TiptapContent::json(mindmap_paragraph_node(next_mindmap_id)), None)
|
||||
}
|
||||
SlashActionKind::Image => {
|
||||
dispatch_editor_upload_request("image", "image/*")?;
|
||||
return Ok("已打开图片上传");
|
||||
}
|
||||
SlashActionKind::UploadAttachment => {
|
||||
dispatch_editor_upload_request("attachment", "")?;
|
||||
return Ok("已打开附件上传");
|
||||
}
|
||||
SlashActionKind::Toc => editor.insert_toc_node(TiptapTocNodeAttrs {
|
||||
top_offset: Some(0),
|
||||
max_show_count: Some(20),
|
||||
show_title: Some(true),
|
||||
}),
|
||||
};
|
||||
|
||||
result
|
||||
.map(|_| match action {
|
||||
SlashActionKind::AiAssistant
|
||||
| SlashActionKind::AiWrite
|
||||
| SlashActionKind::ContinueWriting
|
||||
| SlashActionKind::Summarize
|
||||
| SlashActionKind::MoreAi => "AI 命令入口已打开",
|
||||
SlashActionKind::Paragraph => "已切到文本",
|
||||
SlashActionKind::Heading1 => "已切到一级标题",
|
||||
SlashActionKind::Heading2 => "已切到二级标题",
|
||||
SlashActionKind::Heading3 => "已切到三级标题",
|
||||
SlashActionKind::Heading4 => "已切到四级标题",
|
||||
SlashActionKind::BulletList => "已切到无序列表",
|
||||
SlashActionKind::OrderedList => "已切到有序列表",
|
||||
SlashActionKind::Todo | SlashActionKind::AdvancedTodo => "已切到待办列表",
|
||||
SlashActionKind::Quote => "已切到引述文字",
|
||||
SlashActionKind::CodeBlock => "已切到代码块",
|
||||
SlashActionKind::Divider => "已插入分割线",
|
||||
SlashActionKind::SimpleTable => "已插入简单表格",
|
||||
SlashActionKind::Mindmap => "已插入思维导图",
|
||||
SlashActionKind::Image => "已打开图片上传",
|
||||
SlashActionKind::UploadAttachment => "已打开附件上传",
|
||||
SlashActionKind::Toc => "已插入页面目录",
|
||||
})
|
||||
.map_err(|err| format!("命令执行失败:{err}"))
|
||||
}
|
||||
|
||||
pub(crate) fn top_level_block_is_page(
|
||||
editor: TiptapEditorHandle,
|
||||
block_index: usize,
|
||||
) -> bool {
|
||||
editor
|
||||
.get_json()
|
||||
.ok()
|
||||
.and_then(|document| {
|
||||
document
|
||||
.get("content")
|
||||
.and_then(Value::as_array)
|
||||
.and_then(|content| content.get(block_index).cloned())
|
||||
})
|
||||
.map(|block| inline_has_page_block_link(&block))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub(crate) fn top_level_block_matches_action(
|
||||
editor: TiptapEditorHandle,
|
||||
block_index: usize,
|
||||
action: SlashActionKind,
|
||||
) -> bool {
|
||||
let Some(block) = editor.get_json().ok().and_then(|document| {
|
||||
document
|
||||
.get("content")
|
||||
.and_then(Value::as_array)
|
||||
.and_then(|content| content.get(block_index).cloned())
|
||||
}) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let node_type = block
|
||||
.get("type")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or_default();
|
||||
match action {
|
||||
SlashActionKind::Paragraph => {
|
||||
node_type == "paragraph" && !inline_has_page_block_link(&block)
|
||||
}
|
||||
SlashActionKind::Heading1
|
||||
| SlashActionKind::Heading2
|
||||
| SlashActionKind::Heading3
|
||||
| SlashActionKind::Heading4 => {
|
||||
let expected_level = match action {
|
||||
SlashActionKind::Heading1 => 1,
|
||||
SlashActionKind::Heading2 => 2,
|
||||
SlashActionKind::Heading3 => 3,
|
||||
SlashActionKind::Heading4 => 4,
|
||||
_ => 0,
|
||||
};
|
||||
node_type == "heading"
|
||||
&& block
|
||||
.get("attrs")
|
||||
.and_then(|attrs| attrs.get("level"))
|
||||
.and_then(Value::as_i64)
|
||||
.map(|level| level == expected_level)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
SlashActionKind::BulletList => node_type == "bulletList",
|
||||
SlashActionKind::OrderedList => node_type == "orderedList",
|
||||
SlashActionKind::Todo | SlashActionKind::AdvancedTodo => node_type == "taskList",
|
||||
SlashActionKind::Quote => node_type == "blockquote",
|
||||
SlashActionKind::CodeBlock => node_type == "codeBlock",
|
||||
SlashActionKind::Divider => node_type == "horizontalRule",
|
||||
SlashActionKind::SimpleTable => node_type == "table",
|
||||
SlashActionKind::Mindmap => {
|
||||
node_type == "paragraph"
|
||||
&& block
|
||||
.get("attrs")
|
||||
.and_then(|attrs| attrs.get("mnoteBlockType"))
|
||||
.and_then(Value::as_str)
|
||||
== Some("mindmap")
|
||||
}
|
||||
SlashActionKind::Image => node_type == "image",
|
||||
SlashActionKind::UploadAttachment => false,
|
||||
SlashActionKind::Toc => node_type == "tocNode",
|
||||
SlashActionKind::AiAssistant
|
||||
| SlashActionKind::AiWrite
|
||||
| SlashActionKind::ContinueWriting
|
||||
| SlashActionKind::Summarize
|
||||
| SlashActionKind::MoreAi => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn next_mindmap_id() -> String {
|
||||
format!(
|
||||
"mindmap-{}",
|
||||
(js_sys::Math::random() * 1_000_000_000.0).round() as u64
|
||||
)
|
||||
}
|
||||
|
||||
fn inline_has_page_block_link(node: &Value) -> bool {
|
||||
if node
|
||||
.get("marks")
|
||||
.and_then(Value::as_array)
|
||||
.map(|marks| {
|
||||
marks.iter().any(|mark| {
|
||||
mark.get("type").and_then(Value::as_str) == Some("link")
|
||||
&& mark
|
||||
.get("attrs")
|
||||
.and_then(|attrs| attrs.get("class"))
|
||||
.and_then(Value::as_str)
|
||||
.map(|class_name| {
|
||||
class_name
|
||||
.split_whitespace()
|
||||
.any(|part| part == "mnote-page-block-link")
|
||||
})
|
||||
.unwrap_or(false)
|
||||
})
|
||||
})
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
node.get("content")
|
||||
.and_then(Value::as_array)
|
||||
.map(|children| children.iter().any(inline_has_page_block_link))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// 将 delta operations 应用到 Tiptap JSON 树(原地修改)。
|
||||
/// 返回 true 表示树发生了变更。
|
||||
pub(crate) fn apply_block_delta_to_json(content: &mut Value, operations: &[Value]) -> bool {
|
||||
|
||||
@@ -3,8 +3,7 @@ use leptos::mount::{mount_to, mount_to_body};
|
||||
use leptos::prelude::*;
|
||||
use leptos_dom::helpers::window_event_listener;
|
||||
use leptos_tiptap::{
|
||||
TiptapCodeBlockAttributes, TiptapColorAttributes, TiptapContent, TiptapEditor,
|
||||
TiptapEditorHandle, TiptapExtension, TiptapHeadingLevel, TiptapHighlightAttributes,
|
||||
TiptapContent, TiptapEditor, TiptapEditorHandle, TiptapExtension, TiptapHeadingLevel,
|
||||
TiptapInsertContentOptions, TiptapLinkResource, TiptapMarkName, TiptapNodeName, TiptapRange,
|
||||
TiptapSchemaTarget, TiptapSelectionState, TiptapTextAlign, TiptapTocNodeAttrs,
|
||||
};
|
||||
@@ -19,7 +18,6 @@ use web_sys::{
|
||||
MouseEvent, Node, RequestInit, RequestMode, Response, WheelEvent,
|
||||
};
|
||||
|
||||
use editor_runtime::attachment_upload::dispatch_editor_upload_request;
|
||||
use editor_runtime::block_dnd::{
|
||||
block_state_from_index as block_state_from_index_runtime,
|
||||
drop_indicator_from_point as drop_indicator_from_point_runtime,
|
||||
@@ -33,7 +31,11 @@ use editor_runtime::block_menu_document::{
|
||||
collect_plain_text, mindmap_paragraph_node, paragraph_node,
|
||||
};
|
||||
use editor_runtime::block_menu_overlay;
|
||||
use editor_runtime::block_transform::apply_block_delta_to_json;
|
||||
use editor_runtime::block_transform::{
|
||||
apply_block_delta_to_json, apply_highlight_color, apply_image_align, apply_text_align,
|
||||
apply_text_color, clear_text_color, run_slash_action, top_level_block_is_page,
|
||||
top_level_block_matches_action,
|
||||
};
|
||||
use editor_runtime::bridge_dispatch::HostCommandKind;
|
||||
use editor_runtime::bridge_events::{
|
||||
BridgeSelectorsPayload, ChangeMetaPayload, ChangePayload, HeightPayload, HostCommandEnvelope,
|
||||
@@ -1315,142 +1317,6 @@ fn apply_host_document_payload(
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_text_color(editor: TiptapEditorHandle, color: &str) -> Result<&'static str, String> {
|
||||
editor
|
||||
.set_color(TiptapColorAttributes {
|
||||
color: color.to_string(),
|
||||
})
|
||||
.map(|_| "已更新文字颜色")
|
||||
.map_err(|err| format!("命令执行失败:{err}"))
|
||||
}
|
||||
|
||||
fn clear_text_color(editor: TiptapEditorHandle) -> Result<&'static str, String> {
|
||||
editor
|
||||
.unset_color()
|
||||
.map(|_| "已清除文字颜色")
|
||||
.map_err(|err| format!("命令执行失败:{err}"))
|
||||
}
|
||||
|
||||
fn apply_highlight_color(
|
||||
editor: TiptapEditorHandle,
|
||||
color: Option<&str>,
|
||||
) -> Result<&'static str, String> {
|
||||
match color {
|
||||
Some(color) => editor
|
||||
.set_highlight(Some(TiptapHighlightAttributes {
|
||||
color: Some(color.to_string()),
|
||||
}))
|
||||
.map(|_| "已更新背景色")
|
||||
.map_err(|err| format!("命令执行失败:{err}")),
|
||||
None => editor
|
||||
.unset_highlight()
|
||||
.map(|_| "已清除背景色")
|
||||
.map_err(|err| format!("命令执行失败:{err}")),
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_text_align(
|
||||
editor: TiptapEditorHandle,
|
||||
alignment: TiptapTextAlign,
|
||||
) -> Result<&'static str, String> {
|
||||
let message = match alignment {
|
||||
TiptapTextAlign::Left => "已切到左对齐",
|
||||
TiptapTextAlign::Center => "已切到居中",
|
||||
TiptapTextAlign::Right => "已切到右对齐",
|
||||
TiptapTextAlign::Justify => "已切到两端对齐",
|
||||
};
|
||||
editor
|
||||
.set_text_align(alignment)
|
||||
.map(|_| message)
|
||||
.map_err(|err| format!("命令执行失败:{err}"))
|
||||
}
|
||||
|
||||
fn apply_image_align(
|
||||
editor: TiptapEditorHandle,
|
||||
align: &'static str,
|
||||
) -> Result<&'static str, String> {
|
||||
let _ = editor.focus();
|
||||
let mut attrs = leptos_tiptap::TiptapAttributes::new();
|
||||
attrs.insert("data-align", align);
|
||||
editor
|
||||
.update_attributes(TiptapSchemaTarget::Node(TiptapNodeName::Image), attrs)
|
||||
.map(|_| "已更新图片对齐")
|
||||
.map_err(|err| format!("命令执行失败:{err}"))
|
||||
}
|
||||
|
||||
fn run_slash_action(
|
||||
editor: TiptapEditorHandle,
|
||||
action: SlashActionKind,
|
||||
) -> Result<&'static str, String> {
|
||||
let result = match action {
|
||||
SlashActionKind::AiAssistant
|
||||
| SlashActionKind::AiWrite
|
||||
| SlashActionKind::ContinueWriting
|
||||
| SlashActionKind::Summarize
|
||||
| SlashActionKind::MoreAi => return Ok("AI 命令入口已打开"),
|
||||
SlashActionKind::Paragraph => editor.set_paragraph(),
|
||||
SlashActionKind::Heading1 => editor.toggle_heading(TiptapHeadingLevel::H1),
|
||||
SlashActionKind::Heading2 => editor.toggle_heading(TiptapHeadingLevel::H2),
|
||||
SlashActionKind::Heading3 => editor.toggle_heading(TiptapHeadingLevel::H3),
|
||||
SlashActionKind::Heading4 => editor.toggle_heading(TiptapHeadingLevel::H4),
|
||||
SlashActionKind::BulletList => editor.toggle_bullet_list(),
|
||||
SlashActionKind::OrderedList => editor.toggle_ordered_list(),
|
||||
SlashActionKind::Todo | SlashActionKind::AdvancedTodo => editor.toggle_task_list(),
|
||||
SlashActionKind::Quote => editor.toggle_blockquote(),
|
||||
SlashActionKind::CodeBlock => editor.toggle_code_block(Some(TiptapCodeBlockAttributes {
|
||||
language: Some("rust".into()),
|
||||
})),
|
||||
SlashActionKind::Divider => editor.set_horizontal_rule(),
|
||||
SlashActionKind::SimpleTable => {
|
||||
let _ = editor.focus();
|
||||
editor.insert_table(4, 3, false)
|
||||
}
|
||||
SlashActionKind::Mindmap => editor.insert_content(
|
||||
TiptapContent::json(mindmap_paragraph_node(next_mindmap_id)),
|
||||
None,
|
||||
),
|
||||
SlashActionKind::Image => {
|
||||
dispatch_editor_upload_request("image", "image/*")?;
|
||||
return Ok("已打开图片上传");
|
||||
}
|
||||
SlashActionKind::UploadAttachment => {
|
||||
dispatch_editor_upload_request("attachment", "")?;
|
||||
return Ok("已打开附件上传");
|
||||
}
|
||||
SlashActionKind::Toc => editor.insert_toc_node(TiptapTocNodeAttrs {
|
||||
top_offset: Some(0),
|
||||
max_show_count: Some(20),
|
||||
show_title: Some(true),
|
||||
}),
|
||||
};
|
||||
|
||||
result
|
||||
.map(|_| match action {
|
||||
SlashActionKind::AiAssistant
|
||||
| SlashActionKind::AiWrite
|
||||
| SlashActionKind::ContinueWriting
|
||||
| SlashActionKind::Summarize
|
||||
| SlashActionKind::MoreAi => "AI 命令入口已打开",
|
||||
SlashActionKind::Paragraph => "已切到文本",
|
||||
SlashActionKind::Heading1 => "已切到一级标题",
|
||||
SlashActionKind::Heading2 => "已切到二级标题",
|
||||
SlashActionKind::Heading3 => "已切到三级标题",
|
||||
SlashActionKind::Heading4 => "已切到四级标题",
|
||||
SlashActionKind::BulletList => "已切到无序列表",
|
||||
SlashActionKind::OrderedList => "已切到有序列表",
|
||||
SlashActionKind::Todo | SlashActionKind::AdvancedTodo => "已切到待办列表",
|
||||
SlashActionKind::Quote => "已切到引述文字",
|
||||
SlashActionKind::CodeBlock => "已切到代码块",
|
||||
SlashActionKind::Divider => "已插入分割线",
|
||||
SlashActionKind::SimpleTable => "已插入简单表格",
|
||||
SlashActionKind::Mindmap => "已插入思维导图",
|
||||
SlashActionKind::Image => "已打开图片上传",
|
||||
SlashActionKind::UploadAttachment => "已打开附件上传",
|
||||
SlashActionKind::Toc => "已插入页面目录",
|
||||
})
|
||||
.map_err(|err| format!("命令执行失败:{err}"))
|
||||
}
|
||||
|
||||
fn run_block_turn_into_action(
|
||||
editor: TiptapEditorHandle,
|
||||
block_index: usize,
|
||||
@@ -1709,117 +1575,6 @@ fn block_plain_text_from_index(
|
||||
Ok(normalized_page_block_title(&collect_plain_text(block)))
|
||||
}
|
||||
|
||||
fn inline_has_page_block_link(node: &Value) -> bool {
|
||||
if node
|
||||
.get("marks")
|
||||
.and_then(Value::as_array)
|
||||
.map(|marks| {
|
||||
marks.iter().any(|mark| {
|
||||
mark.get("type").and_then(Value::as_str) == Some("link")
|
||||
&& mark
|
||||
.get("attrs")
|
||||
.and_then(|attrs| attrs.get("class"))
|
||||
.and_then(Value::as_str)
|
||||
.map(|class_name| {
|
||||
class_name
|
||||
.split_whitespace()
|
||||
.any(|part| part == "mnote-page-block-link")
|
||||
})
|
||||
.unwrap_or(false)
|
||||
})
|
||||
})
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
node.get("content")
|
||||
.and_then(Value::as_array)
|
||||
.map(|children| children.iter().any(inline_has_page_block_link))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn top_level_block_is_page(editor: TiptapEditorHandle, block_index: usize) -> bool {
|
||||
editor
|
||||
.get_json()
|
||||
.ok()
|
||||
.and_then(|document| {
|
||||
document
|
||||
.get("content")
|
||||
.and_then(Value::as_array)
|
||||
.and_then(|content| content.get(block_index).cloned())
|
||||
})
|
||||
.map(|block| inline_has_page_block_link(&block))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn top_level_block_matches_action(
|
||||
editor: TiptapEditorHandle,
|
||||
block_index: usize,
|
||||
action: SlashActionKind,
|
||||
) -> bool {
|
||||
let Some(block) = editor.get_json().ok().and_then(|document| {
|
||||
document
|
||||
.get("content")
|
||||
.and_then(Value::as_array)
|
||||
.and_then(|content| content.get(block_index).cloned())
|
||||
}) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let node_type = block
|
||||
.get("type")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or_default();
|
||||
match action {
|
||||
SlashActionKind::Paragraph => {
|
||||
node_type == "paragraph" && !inline_has_page_block_link(&block)
|
||||
}
|
||||
SlashActionKind::Heading1
|
||||
| SlashActionKind::Heading2
|
||||
| SlashActionKind::Heading3
|
||||
| SlashActionKind::Heading4 => {
|
||||
let expected_level = match action {
|
||||
SlashActionKind::Heading1 => 1,
|
||||
SlashActionKind::Heading2 => 2,
|
||||
SlashActionKind::Heading3 => 3,
|
||||
SlashActionKind::Heading4 => 4,
|
||||
_ => 0,
|
||||
};
|
||||
node_type == "heading"
|
||||
&& block
|
||||
.get("attrs")
|
||||
.and_then(|attrs| attrs.get("level"))
|
||||
.and_then(Value::as_i64)
|
||||
.map(|level| level == expected_level)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
SlashActionKind::BulletList => node_type == "bulletList",
|
||||
SlashActionKind::OrderedList => node_type == "orderedList",
|
||||
SlashActionKind::Todo | SlashActionKind::AdvancedTodo => node_type == "taskList",
|
||||
SlashActionKind::Quote => node_type == "blockquote",
|
||||
SlashActionKind::CodeBlock => node_type == "codeBlock",
|
||||
SlashActionKind::Divider => node_type == "horizontalRule",
|
||||
SlashActionKind::SimpleTable => node_type == "table",
|
||||
SlashActionKind::Mindmap => {
|
||||
node_type == "paragraph"
|
||||
&& block
|
||||
.get("attrs")
|
||||
.and_then(|attrs| attrs.get("mnoteBlockType"))
|
||||
.and_then(Value::as_str)
|
||||
== Some("mindmap")
|
||||
}
|
||||
SlashActionKind::Image => node_type == "image",
|
||||
SlashActionKind::UploadAttachment => false,
|
||||
SlashActionKind::Toc => node_type == "tocNode",
|
||||
SlashActionKind::AiAssistant
|
||||
| SlashActionKind::AiWrite
|
||||
| SlashActionKind::ContinueWriting
|
||||
| SlashActionKind::Summarize
|
||||
| SlashActionKind::MoreAi => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn page_reference_paragraph_node(page_id: &str, workspace_id: Option<&str>, title: &str) -> Value {
|
||||
let href = if page_id.trim().is_empty() {
|
||||
"#".to_string()
|
||||
|
||||
Reference in New Issue
Block a user