From 78e65267a99c5f00b0b3cc1a490058342b7bb681 Mon Sep 17 00:00:00 2001 From: dualwind Date: Thu, 1 Feb 2024 22:21:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 89 ------------------------------------ README.md | 60 ++++++++++++------------ README_en_US.md | 58 ++++++++++++----------- package.json | 2 +- plugin.json | 6 +-- src/VueApp.vue | 4 +- src/components/TableData.vue | 79 ++++++++++++++++++++++++++------ 7 files changed, 128 insertions(+), 170 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5116c8..4dc68c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,91 +1,2 @@ # Changelog -## 0.3.2 2024-01 - -## 0.3.1 2023-12-06 - -* [Support `Dock Plugin` and `Command Palette` on mobile](https://github.com/siyuan-note/siyuan/issues/9926) - -## 0.3.0 2023-12-05 - -* Upgrade Siyuan to 0.9.0 -* Support more platforms - -## 0.2.9 2023-11-28 - -* [Add plugin method `openMobileFileById`](https://github.com/siyuan-note/siyuan/issues/9738) - - -## 0.2.8 2023-11-15 - -* [`resize` cannot be triggered after dragging to unpin the dock](https://github.com/siyuan-note/siyuan/issues/9640) - -## 0.2.7 2023-10-31 - -* [Export `Constants` to plugin](https://github.com/siyuan-note/siyuan/issues/9555) -* [Add plugin `app.appId`](https://github.com/siyuan-note/siyuan/issues/9538) -* [Add plugin event bus `switch-protyle`](https://github.com/siyuan-note/siyuan/issues/9454) - -## 0.2.6 2023-10-24 - -* [Deprecated `loaded-protyle` use `loaded-protyle-static` instead](https://github.com/siyuan-note/siyuan/issues/9468) - -## 0.2.5 2023-10-10 - -* [Add plugin event bus `open-menu-doctree`](https://github.com/siyuan-note/siyuan/issues/9351) - -## 0.2.4 2023-09-19 - -* Supports use in windows -* [Add plugin function `transaction`](https://github.com/siyuan-note/siyuan/issues/9172) - -## 0.2.3 2023-09-05 - -* [Add plugin function `transaction`](https://github.com/siyuan-note/siyuan/issues/9172) -* [Plugin API add openWindow and command.globalCallback](https://github.com/siyuan-note/siyuan/issues/9032) - -## 0.2.2 2023-08-29 - -* [Add plugin event bus `destroy-protyle`](https://github.com/siyuan-note/siyuan/issues/9033) -* [Add plugin event bus `loaded-protyle-dynamic`](https://github.com/siyuan-note/siyuan/issues/9021) - -## 0.2.1 2023-08-21 - -* [Plugin API add getOpenedTab method](https://github.com/siyuan-note/siyuan/issues/9002) -* [Plugin API custom.fn => custom.id in openTab](https://github.com/siyuan-note/siyuan/issues/8944) - -## 0.2.0 2023-08-15 - -* [Add plugin event bus `open-siyuan-url-plugin` and `open-siyuan-url-block`](https://github.com/siyuan-note/siyuan/pull/8927) - - -## 0.1.12 2023-08-01 - -* Upgrade siyuan to 0.7.9 - -## 0.1.11 - -* [Add `input-search` event bus to plugins](https://github.com/siyuan-note/siyuan/issues/8725) - - -## 0.1.10 - -* [Add `bind this` example for eventBus in plugins](https://github.com/siyuan-note/siyuan/issues/8668) -* [Add `open-menu-breadcrumbmore` event bus to plugins](https://github.com/siyuan-note/siyuan/issues/8666) - -## 0.1.9 - -* [Add `open-menu-xxx` event bus for plugins ](https://github.com/siyuan-note/siyuan/issues/8617) - -## 0.1.8 - -* [Add protyleSlash to the plugin](https://github.com/siyuan-note/siyuan/issues/8599) -* [Add plugin API protyle](https://github.com/siyuan-note/siyuan/issues/8445) - -## 0.1.7 - -* [Support build js and json](https://github.com/siyuan-note/plugin-sample/pull/8) - -## 0.1.6 - -* add `fetchPost` example diff --git a/README.md b/README.md index e51e412..76e915f 100644 --- a/README.md +++ b/README.md @@ -2,38 +2,34 @@ [English](./README_en_US.md) -思源笔记插件,仿 Remnote 的 Table View 功能,利用标签,在表格中展示笔记数据 - -- 每行表示某个`概念`的所有`属性` -- 支持标题、列表、超级块等形式组织的笔记,但`属性`标识(标签)需放在首行 -- ❗不在代码块、数学公式块等非段落块搜寻`属性`标识(标签),如需加入标签,请作为列表项的子块 -- ❕支持多级表头,如`概念1/属性1/子属性2`,但是并不推荐这么做,因为非叶子节点(如`概念1/属性1`)所属内容将不会在表格中渲染 - -> ❗❗ 表格展示不是数据库,表格所展示的数据直接来源于你的笔记,并且禁止在表格中编辑内容 +思源笔记插件,Query View 类,仿 Remnote 的 Table View 功能,在表格中展示笔记数据。 + +> ❗ 表格展示不是数据库,表格所展示的数据直接来源于你的笔记,并且禁止在表格中编辑内容。 + +## 基本概念 + +- 概念 + - 一般表示一个对象,如`三国演义` + - 展示在表格左侧第 1 列 + - 一般为列表项块、标题块 + - 概念标识(概念所在块确定方式) + - 指定标签所在块,如含有`#书籍#`的块 + - 直接搜索选择指定块 +- 属性 + - 如`作者`,`出版社`等 + - 展示在概念所在行 + - ⚠️ 属性所在块应为`概念`所在块的后代块 + - 属性名展示在表头,⚠️ 支持多级表头,如`概念1/属性1/子属性2`,但是并不推荐这么做,因为非叶子节点(如`概念1/属性1`)所属内容将不会在表格中渲染 + - 渲染效果与笔记内一致,支持列表、超级块等容器块,但属性标识需放在首行 + - ❗ 不在代码块、数学公式块等非段落块搜寻属性标识,请作为容器块的子块 + - 属性标识 + - 指定标签所在块,如含有`#作者#`的块 + - 概念标签的子标签所在块,如含有`#书籍/作者#`的块 + - 含有指定分隔符号所在块,如以`作者::`开头的块 ## 使用方法 -1. 利用标签标记块: - - 在`概念`所在块上使用`类别`标签,如在`三国演义`的标题上使用`书籍`标签 - - 在`概念`的`后代块`中,使用子标签标记`属性`块如在`罗贯中`所在块使用`书籍/作者`标签,并且`罗贯中`所在块应在`三国演义`的子块中(不限层级) -2. 在顶栏中点击`表格展示`,打开新页签 -3. 在输入框输入刚才标记的标签,如`书籍`,注意,直接输入不会触发任何动作,需要在弹出的自动补全列表中点击`书籍`标签 -4. 等待一会,会发现下面的表格出现如下内容: - |名称|作者| - |---|---| - |三国演义|罗贯中| - -## 工作流程 - -了解该插件的工作流程可能对取得预期的效果有所帮助 - -1. 初始化时插件会拉取所有标签,之后只要不关闭窗口,这些标签将会被复用 -2. 选择某个标签后(标签 1),插件会进行如下操作: - 1. 查找所有子标签,即以`标签1`开头的标签,将它们作为表头 - 2. 查找含有`标签1`的所有块,将它们的`content`填入`名称`列 - 3. 查找上一步找到块的所有后代块 - - 如果是段落块,将查找其父块的所有后代块,这意味着,如果段落块位于超级块、列表项块、引述块中,将查找超级块、列表项块、引述块的所有后代块 - 4. 在后代块的内容中查找子标签 - - 使用距离含有`标签1`的块层级最近的块(这意味着,优先使用超级块、列表项块、引述块,而不是其它们的子段落块) - 5. 将上一步找到的块放入相应单元格 -3. 除`名称`列单元格直接使用文本外,其余所有单元格都是使用思源编辑器渲染,这意味着,其所有子块都将被渲染 +1. 选择查找`概念`所在块的方式 +2. `下一步`,选择查找`属性`所在块的方式 + ⚠️ 属性所在块只在`概念`所在块的后代块中查找 +3. `生成`,稍后将在下方展示查询结果 diff --git a/README_en_US.md b/README_en_US.md index f5db4eb..00538af 100644 --- a/README_en_US.md +++ b/README_en_US.md @@ -2,36 +2,34 @@ [中文版](./README.md) -Siyuan Note Plug-in, similar to Remnote's Table View , uses tags to display note data in a table - -- Each row represents all the 'attributes' of a 'concept' -- Support notes organized in the form of titles, lists, superblocks, etc - -> ❗Table View is not a database, the data displayed in the table comes directly from your notes, and it is forbidden to edit the content in the table +Siyuan Note Plugin, Query View like Plugin, imitates the Table View function of Remnote, and displays note data in a table. + +> ❗ Table View is not a database, the data displayed in the table comes directly from your notes, and it is forbidden to edit the content in the table. + +## Basic Concepts + +- conception + - Generally denotes an object, e.g. `Romance of the Three Kingdoms` + - Appears in column 1 on the left side of the table + - Generally, it is a list item block or a title block + - Concept identity (how the block in which the concept is located) + - Specify the block where the tag is located, such as a block containing `#Book#` + - Directly search and selected block +- attribute + - e.g. `Author`, `Publisher`, etc + - Display in the row of the concept + - ⚠️ The block in which the attribute is located should be the descendant block of the block in which the `concept` is located + - Attribute names are displayed in the header of the table, which supports multi-level headers, such as `Concept 1/Attribute 1/Sub Attribute 2`, ⚠️ but this is not recommended because the content belonging to non-leaf nodes (e.g. `Concept 1/Attribute 1`) will not be rendered in the table + - The rendering effect is the same as in the note, and container blocks such as lists and superblocks are supported, but the attribute identifier needs to be placed in the first line + - Do not search for attribute identifiers in non-paragraph ❗ blocks such as code blocks and math formula blocks, and use them as subblocks of container blocks + - Attribute identification + - Specify the block where the tag is located, e.g. the block containing `#Author#` + - The block where the subtag of the concept tag is located, e.g. the block containing `#Book/Author#` + - Blocks containing the specified delimiter, such as those that start with `Author::` ## How to use -1. Tag blocks with labels: - - Use the 'Category' tag on the 'Concept' block, e.g. the 'Book' tag on the title of 'Romance of the Three Kingdoms' - - In the 'Descendant Block' of 'Concept', use subtags to mark the 'Attributes' block, e.g. use the 'Book/Author' tag in the 'Luo Guanzhong' block, and the 'Luo Guanzhong' block should be in the 'Romance of the Three Kingdoms' sub-block (no hierarchy) -2. Click 'Table Display' in the top bar to open a new tab -3. Enter the label you just marked in the input box, such as 'Books', note that direct input will not trigger any action, you need to click the 'Books' tab in the pop-up autocomplete list -4. Wait for a while, and you will find the following table with the following content: - |name|author| - |---|---| - |Romance of the Three Kingdoms|Luo Guanzhong| - -## Workflow - -Understanding the workflow of the plugin may help to achieve the desired results - -1. The plugin will pull all the tags during initialization, and then they will be reused as long as the window is not closed -2. After selecting a tag (Tag 1), the plugin does the following: - 1. Find all the sub-tags, i.e. the tags that start with 'Tag 1', and use them as headers - 2. Find all the blocks that contain 'Label 1' and fill in their 'content' in the 'Name' column - 3. Find all the descendant blocks of the block found in the previous step - - In the case of a paragraph block, all descendant blocks of its parent block will be found, which means that if the paragraph block is in a superblock, list item block, quote block, all descendant blocks of the superblock, list item block, quote block will be found - 4. Look for subtags in the content of the descendant block - - Use the block closest to the block level with 'Tag 1' (meaning that superblocks, list item blocks, quote blocks are preferred over their subparagraph blocks) - 5. Put the block found in the previous step into the corresponding cell -3. All cells are rendered using the CiSource Editor except for the 'Name' column cell, which means that all its sub-blocks will be rendered +1. Choose how you want to find the block where the `concept` is located +2. `Next`, choose how you want to find the block where `Properties` is located + ⚠️ The block in which the attribute is located is only found in the descendant block of the block where the `concept` is located +3. `Generate`, the results of the query will be displayed below \ No newline at end of file diff --git a/package.json b/package.json index 5dd8f3d..ef9f7e5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "siyuan-plugin-table-view", - "version": "0.2.0", + "version": "0.2.1", "type": "module", "description": "抽取笔记内容生成表格,汇总概念及其属性", "repository": "", diff --git a/plugin.json b/plugin.json index 1c43804..2b09258 100644 --- a/plugin.json +++ b/plugin.json @@ -2,7 +2,7 @@ "name": "siyuan-plugin-table-view", "author": "dualwind", "url": "https://github.com/etchnight/siyuan-plugin-table-view", - "version": "0.2.0", + "version": "0.2.1", "minAppVersion": "2.11.4", "backends": ["windows", "linux", "darwin", "ios", "android"], "frontends": ["desktop", "browser-desktop", "desktop-window"], @@ -19,7 +19,7 @@ "zh_CN": "README.md" }, "funding": { - "custom": [] + "custom": ["https://afdian.net/a/dualwind"] }, - "keywords": ["plugin", "sample", "插件样例"] + "keywords": ["plugin", "table", "表格", "Query View"] } diff --git a/src/VueApp.vue b/src/VueApp.vue index 9b47e9c..51d6a86 100644 --- a/src/VueApp.vue +++ b/src/VueApp.vue @@ -67,7 +67,9 @@ - 上一步 + + 上一步 + {{ nextText }} diff --git a/src/components/TableData.vue b/src/components/TableData.vue index fe0a722..53c5802 100644 --- a/src/components/TableData.vue +++ b/src/components/TableData.vue @@ -80,13 +80,14 @@ const recurList2Tree = (parent: Head, list: { value: string }[]) => { * @description 构建表头 * @returns columnProps="tableHeadRef.children" */ -const buildHead = (props: TagSelectedItem[]) => { +const buildHead = (props: TagSelectedItem[], splitFlag?: string) => { + splitFlag = splitFlag || "/"; for (const item of props) { let head: Head = { children: [], value: item.tag.value, label: item.tag.value, - path: item.tag.value.split("/"), + path: item.tag.value.split(splitFlag), }; recurList2Tree(head, item.children); tableHeadRef.value.children.push(head); @@ -162,6 +163,9 @@ type DescendantBlockTree = { nameBlock: Block; children: DescendantBlockTree[]; }; +/** + * @returns 改变parent: DescendantBlockTree + */ const buildDescendantBlockTree = ( splitFlag: string, blocks: (Block & { @@ -218,7 +222,39 @@ const rebuildChildrenBlocks = ( } return newBlocks; }; -//主程序入口 + +/** + * @param parent Head类型 + * - 通过迭代更改 + * - 应将最终结果的children与tableHeadRef合并 + * - 根对象是虚拟的,对应的是概念块(而非属性块) + * @param props.splitFlag 隐含变量 + * @param data blockTree.nameBlock所在行 + */ +const blockTree2TableData = ( + blockTree: DescendantBlockTree, + parent: Head, + data: Data +) => { + for (let block of blockTree.children) { + const reg = new RegExp(`(${props.splitFlag}).*`); + let prop = block.nameBlock.content.replace(reg, ""); + let propValue = parent.value + prop + props.splitFlag; + let child: Head = { + value: propValue, + label: prop, + path: parent.path.concat(prop), + children: [], + }; + parent.children.push(child); + data[propValue] = block.nameBlock.id; + blockTree2TableData(block, child, data); + } +}; + +/** + * @description 主程序入口 + */ const submit = async () => { loading.value = true; //清空 @@ -229,9 +265,11 @@ const submit = async () => { path: [], }; tableDataRef.value = []; + //构建行 const nameBlocks = await getNameBlocks(); - const childBlocks = await getDescendantBlocks(nameBlocks); + const nameAndChildBlocks = await getDescendantBlocks(nameBlocks); + //构建表头(列) let propList: AutocompleteItem[] = []; if (props.isContainsTagChild) { @@ -245,32 +283,45 @@ const submit = async () => { propList.push(tag.tag); propList = propList.concat(tag.children); } - /*行列对应 + /*构建主体,行列对应 第一列为名称,值为tag所在block的content 其余列根据tag表示的属性,分别从后代block中查找*/ - for (const block of childBlocks) { + for (const nameBlockObj of nameAndChildBlocks) { let data: Data = { - name: block.nameBlock.content, + name: nameBlockObj.nameBlock.content, }; for (let prop of propList) { - let propBlock = getPropBlock(block, prop.value); + let propBlock = getPropBlock(nameBlockObj, prop.value); if (propBlock) { data[prop.value] = propBlock.id; } } - tableDataRef.value.push(data); + //tableDataRef.value.push(data); //*分隔符号属性 if (props.splitFlag) { - const childBlocks = rebuildChildrenBlocks(block.childBlocks); - let root = { - nameBlock: block.nameBlock, + const childBlocks = rebuildChildrenBlocks(nameBlockObj.childBlocks); + let blockRoot: DescendantBlockTree = { + nameBlock: nameBlockObj.nameBlock, + children: [], + }; + let propRoot: Head = { + value: "", + label: "", + path: [], children: [], }; - buildDescendantBlockTree(props.splitFlag, childBlocks, root); - console.log(root); + buildDescendantBlockTree(props.splitFlag, childBlocks, blockRoot); + blockTree2TableData(blockRoot, propRoot, data); + //console.log(propRoot); + tableDataRef.value.push(data); + tableHeadRef.value.children = tableHeadRef.value.children.concat( + propRoot.children + ); } } + //console.log("tableDataRef", tableDataRef); + //console.log("tableHeadRef", tableHeadRef); loading.value = false; }; defineExpose({