【分享】在父文档中快速嵌入下级子文档列表

本贴最后更新于 388 天前,其中的信息可能已经物是人非

简介

基本功能:在当前打开的文档中嵌入下一级子文档(引用块的形式)组成的无序列表。

视频演示

如何使用?

  1. 设置——外观——代码片段(设置)——JS ,添加下文的代码片段并启用。
  2. 在文档树中点击打开一个有子文档的文档(最好是空的),然后点击右上角新添加的 插入子文档列表 按钮,就会在当前打开的文档中嵌入下级子文档(引用块的形式)组成的无序列表。——这里设置的是默认将列表插入到文档最前的位置。
// 请求函数
function request(url, data = null, method = "POST") {
  return new Promise((resolve, reject) => {
    if (method.toUpperCase() == "POST") {
      fetch(url, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(data),
      })
        .then(
          (data) => resolve(data.json()),
          (error) => {
            reject(error);
          }
        )
        .catch((err) => {
          console.error("请求失败:", err);
        });
    }
  });
}
// 弹出提示信息
async function showMessage(msg) {
  await request("/api/notification/pushMsg", { msg, timeout: 2000 });
}

// 获取对应笔记本的ID
// element是文档树上刚刚点击打开文档时点击的那个元素
function getDataURL(element) {
  let noteBookID = element.getAttribute("data-url");
  let parent = element.parentElement;
  while (noteBookID == null) {
    noteBookID = parent.getAttribute("data-url");
    parent = parent.parentElement;
  }
  return noteBookID;
}

// 插入子文档导航
async function insertSubDocList() {
  // 文档树上刚刚点击的那个文档对应的元素
  const navigationFile = document.querySelector(
    '.fn__flex-1.fn__flex-column.file-tree.sy__file li.b3-list-item.b3-list-item--hide-action.b3-list-item--focus[data-type="navigation-file"]'
  );

  // 刚打开的文档的path值,示例:"/20200812220555-lj3enxa/20210808180320-m0ztypq.sy"
  if (!navigationFile) {
    return false;
  }
  let dataPath = navigationFile.getAttribute("data-path");
  let docID = navigationFile.getAttribute("data-node-id");
  let notebookID = getDataURL(navigationFile);

  // 子文档的排序方式
  let sortType = window.siyuan.config.fileTree.sort;

  //发送请求获取子文档数据
  let res = await request("/api/filetree/listDocsByPath", {
    notebook: notebookID,
    path: dataPath,
    sort: sortType,
  });
  if (res.code === 0) {
    let subDocsArr = res.data.files;
    if (subDocsArr.length === 0) {
      showMessage("未发现子文档");
      return false;
    }
    let str = "";
    subDocsArr.forEach((subDoc) => {
      let tempArr = subDoc.path.split("/");
      let ID = tempArr[tempArr.length - 1].split(".sy")[0];
      let name = subDoc.name.split(".sy")[0];
      str += `* ((${ID} '${name}'))\n`;
    });

    // 将子文档列表嵌入当前文档
    let res_insertBlock = await request("/api/block/prependBlock", {
      data: str,
      dataType: "markdown",
      parentID: docID,
    });
    if (res_insertBlock.code === 0) {
      showMessage(`子文档导航嵌入成功`);
    } else {
      showMessage(`嵌入失败!${res}`);
    }
  }
}
// 添加一个按钮
if (!barMode) {
  const barMode = document.getElementById("barMode");
}
barMode.insertAdjacentHTML(
  "beforebegin",
  '<div id="insertSubDocList" class="toolbar__item b3-tooltips b3-tooltips__se" aria-label="插入子文档列表" ></div>'
);
const insertSubDocListBtn = document.getElementById("insertSubDocList");
insertSubDocListBtn.style.width = "auto";
const insertSubDocListBtnIcon = `<svg t="1675499660408" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2740" width="200" height="200"><path d="M913.6 135.2H380.2c-26.7 0-44.4 17.8-44.4 44.4V224c0 26.7 17.8 44.4 44.4 44.4h533.3c26.7 0 44.4-17.8 44.4-44.4v-44.4c0.1-26.6-17.7-44.4-44.3-44.4zM158 135.2h-44.4c-22.2 0-44.4 22.2-44.4 44.4V224c0 22.2 22.2 44.4 44.4 44.4H158c22.2 0 44.4-22.2 44.4-44.4v-44.4c0.1-22.2-22.1-44.4-44.4-44.4zM158 446.3h-44.4c-22.2 0-44.4 22.2-44.4 44.4v44.4c0 22.2 22.2 44.4 44.4 44.4H158c22.2 0 44.4-22.2 44.4-44.4v-44.4c0.1-22.2-22.1-44.4-44.4-44.4zM913.6 446.3H380.2c-26.7 0-44.4 17.8-44.4 44.4v44.4c0 26.7 17.8 44.4 44.4 44.4h533.3c26.7 0 44.4-17.8 44.4-44.4v-44.4c0.1-26.6-17.7-44.4-44.3-44.4zM158 757.4h-44.4c-22.2 0-44.4 22.2-44.4 44.4v44.4c0 22.2 22.2 44.4 44.4 44.4H158c22.2 0 44.4-22.2 44.4-44.4v-44.4c0.1-22.2-22.1-44.4-44.4-44.4zM913.6 757.4H380.2c-26.7 0-44.4 17.8-44.4 44.4v44.4c0 26.7 17.8 44.4 44.4 44.4h533.3c26.7 0 44.4-17.8 44.4-44.4v-44.4c0.1-26.6-17.7-44.4-44.3-44.4z" fill="#91999f" p-id="2741"></path></svg>`;
insertSubDocListBtn.innerHTML = insertSubDocListBtnIcon;
insertSubDocListBtn.addEventListener(
  "click",
  (e) => {
    e.stopPropagation();
    e.preventDefault();
    insertSubDocList();
  },
  true
);
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    17927 引用 • 65761 回帖
4 操作
someone69799 在 2023-02-25 14:15:16 更新了该帖
someone69799 在 2023-02-24 17:46:26 更新了该帖
someone69799 在 2023-02-24 00:04:52 更新了该帖
someone69799 在 2023-02-23 20:24:48 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • yjmsiyuan

    看到贡献代码段就支持

  • RaCyan 1 评论

    希望考虑加入到官方功能,非常感谢

    listChildDocs 总是没法自动保存布局以及样式 @88250

    listChildDocs 不支持自动保存,请双击刷新按钮保存设置,如果还是无法保存的话可以回复我。如果打算继续使用,请考虑阅读一下挂件的 README.md(或集市下载页),谢谢。
    Undii
  • LarryGuan

    优秀,使用中,感谢。

  • i1356

    还可以这样玩,优秀。👍

  • RH

    感谢分享代码 👍

    不知有没办法进一步列出更下级子目录的文档,并以缩进的形式展现在列表里?

    1 回复
  • someone69799
    作者

    这个没试过耶。暂时想到有个比较简单粗暴的方法就是:对要嵌入子文档导航的文档,先在文档树上展开它的所有下级文档,这样页面节点上就会有该文档所有层级子文档的信息(包括文档名、id),然后可以自己解析节点拿到信息去组成需要的列表。

    集市上有个挂件好像可以嵌入多层级的子文档列表,但是我还没看过具体怎么实现的,你可以先去看看。

    1 回复
  • RH

    集市里的“list Child Docs”挂件写得也挺好,可以列出多层级子目录,我也在用。只是采用挂件的形式,有点美中不足,会在文档内留下挂件的操作按钮和图标。这种采用代码块在顶部增加图标的方式,不会在文档中留下额外的信息,看起来会更美观一点。

    1 回复
  • someone69799
    作者

    刚刚试了一下,对要嵌入子文档列表的文档,指定文档名和笔记本 ID 后,可以通过 SQL 查询到各层级信息,解析 hpath 字段的内容就可以得到子文档的层级,子文档的文档名和 ID 等信息也有。

    查询各层级子文档列表.png

    1 回复
  • RH 1 评论

    通过 SQL 查询是一种办法,如果用 API 里的 listDocsByPath,采用递归查询再下一层级是另一种办法。相比而言,前者用 SQL 查询 hpath 会节省查询的次数,但多了处理路径的工作量,后者多了查询的工作量,但可节省处理返回结果的工作量。listChildDocs 是用后一种方法。

    那还是用递归查询合适一点,方便指定排序方式,还原文档在文档树上的顺序。
    someone69799
  • 能否将前面的小图标也显示在子文档的前面哈

    1 回复
  • someone69799
    作者

    这个改一下就行,你将那个

     subDocsArr.forEach((subDoc) => {
          let tempArr = subDoc.path.split("/");
          let ID = tempArr[tempArr.length - 1].split(".sy")[0];
          let name = subDoc.name.split(".sy")[0];
          str += `* ((${ID} '${name}'))\n`;
        });
    

    换成:

    subDocsArr.forEach((subDoc) => {
            // let tempArr = subDoc.path.split("/");
            // let ID = tempArr[tempArr.length - 1].split(".sy")[0];
            let ID = subDoc.id;
            let name = subDoc.name.split(".sy")[0];
            if (subDoc.icon) {
              if (subDoc.icon.includes(".")) {
                // 自定义的图标
                let icon = subDoc.icon.split(".")[0];
                str += `* :${icon}: ((${ID} '${name}'))\n`;
              } else {
                // 其他图标
                str += `* &#x${subDoc.icon}; ((${ID} '${name}'))\n`;
              }
            } else {
              // 默认文档图标
              str += `* 📄 ((${ID} '${name}'))\n`;
            }
          });
    

    嵌入子文档列表带图标.gif

  • 嗯,好的,不过有个别图标好像出不来,我待会看看能不能改下CleanShot20230302at09.47.352x.png

  • xpysgdhr 1 评论

    请问如果该笔记本下添加了新笔记,目录可以实现自动更新吗?

    不可以的,这个是一次性的,更新的话是删掉旧的,然后重新嵌入。
    someone69799
请输入回帖内容 ...