GithubHelp home page GithubHelp logo

Comments (4)

straywriter avatar straywriter commented on August 21, 2024

https://github.com/Gk0Wk/TiddlySeq/blob/master/src/page-toc/PageTOCWidget.ts
L%O9PX@I9(~$ZRQDWWH2J3X

这里根据tiddler标题获取那个tree,但是对于markdown来说,html下还有一层

导致tree返回的列表失败,我就卡在这里不知到怎么改了

from tiddlyseq.

oeyoews avatar oeyoews commented on August 21, 2024

由于ts插件修改调试不是很方便(懒), 所以这里仅给出Chatgpt参考代码, 可用性未知

如果当前标题下多嵌套了一层 <div>,可以在 getTOCInfo 方法中进行相应的调整。以下是可能的修改方案:

  1. 找到以下代码块:

    $tw.utils.each([...contents], node => {
      if (node.type !== 'element') {
        return;
      }
      if (this.includeHeaderMap[(node as any).tag as HeaderTag] !== true) {
        return;
      }
      // Render contents of header
      contents.length = 1;
      contents[0] = node;
      const container = $tw.fakeDocument.createElement('div');
      $tw.wiki.makeWidget({ tree: root }).render(container, null);
      headers.push({
        tag: (node as any).tag,
        count: headersCount[(node as any).tag as HeaderTag]++,
        text: container.textContent || '',
      });
    });
  2. 将该代码块替换为以下代码块:

    const processNode = (node: IWikiASTNode) => {
      if (node.type !== 'element') {
        return;
      }
      if (this.includeHeaderMap[(node as any).tag as HeaderTag] !== true) {
        return;
      }
      // Find text within the header element
      let text = '';
      for (const childNode of node.children || []) {
        if (childNode.type === 'text') {
          text += childNode.text;
        }
      }
      // Recursive processing for nested div elements
      for (const childNode of node.children || []) {
        if (childNode.type === 'element' && childNode.tag === 'div') {
          processNode(childNode);
        }
      }
      headers.push({
        tag: (node as any).tag,
        count: headersCount[(node as any).tag as HeaderTag]++,
        text: text.trim(),
      });
    };
    
    $tw.utils.each([...contents], processNode);

    这个修改会递归地处理标题节点下的子节点,将嵌套在 <div> 中的文本内容添加到标题文本中。

通过以上修改,即可在处理标题时,包括嵌套在一层 <div> 内的文本内容,生成正确的目录列表。

from tiddlyseq.

straywriter avatar straywriter commented on August 21, 2024

发现你改的代码还是有问题,修改了下,目前在markdown中没问题,在tw文档中点击事件注入没做适配( 因为我自己也不使用)

import {
  HTMLTags,
  IParseTreeNode,
  IChangedTiddlers,
  IWidgetInitialiseOptions,
  IWikiASTNode,
} from 'tiddlywiki';
import { widget as Widget } from '$:/core/modules/widgets/widget.js';

type HeaderTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';

class PageTOCWidget extends Widget {
  private tocNodeTag: HTMLTags = 'div';

  private tocHeaderNodeTag: HTMLTags = 'p';

  private tocNodeClass: string = 'gk0wk-tiddlertoc-container';

  private tocHeaderNodeClassPrefix: string = 'gk0wk-tiddlertoc-';

  private tocTitle: string = '';

  private emptyMessage: string = '';

  private scrollMode: 'start' | 'center' | 'end' | 'nearest' = 'center';

  private includeHeaderMap: Record<HeaderTag, boolean> = {
    h1: true,
    h2: true,
    h3: true,
    h4: true,
    h5: true,
    h6: true,
  };

  initialise(parseTreeNode: IParseTreeNode, options: IWidgetInitialiseOptions) {
    super.initialise(parseTreeNode, options);
    this.computeAttributes();
  }

  execute() {
    this.tocTitle = this.getAttribute(
      'tiddler',
      this.getVariable('currentTiddler'),
    );
    this.tocNodeTag = this.getAttribute('tag', 'div') as any;
    if (($tw.config.htmlUnsafeElements as any).includes(this.tocNodeTag)) {
      this.tocNodeTag = 'div';
    }
    this.tocHeaderNodeTag = this.getAttribute('headerTag', 'p') as any;
    if (
      ($tw.config.htmlUnsafeElements as any).includes(this.tocHeaderNodeTag)
    ) {
      this.tocHeaderNodeTag = 'p';
    }
    this.tocNodeClass = this.getAttribute(
      'class',
      'gk0wk-tiddlertoc-container',
    );
    this.tocHeaderNodeClassPrefix = this.getAttribute(
      'headerClassPrefix',
      'gk0wk-tiddlertoc-',
    );
    this.emptyMessage = this.getAttribute('emptyMessage', '');
    this.includeHeaderMap.h1 = this.getAttribute('h1', 'yes') === 'yes';
    this.includeHeaderMap.h2 = this.getAttribute('h2', 'yes') === 'yes';
    this.includeHeaderMap.h3 = this.getAttribute('h3', 'yes') === 'yes';
    this.includeHeaderMap.h4 = this.getAttribute('h4', 'yes') === 'yes';
    this.includeHeaderMap.h5 = this.getAttribute('h5', 'yes') === 'yes';
    this.includeHeaderMap.h6 = this.getAttribute('h6', 'yes') === 'yes';
    this.scrollMode = this.getAttribute('scrollMode', 'center') as any;
    if (!['start', 'center', 'end', 'nearest'].includes(this.scrollMode)) {
      this.scrollMode = 'center';
    }
  }

  render(parent: Node, nextSibling: Node | null) {
    this.parentDomNode = parent;
    this.execute();

    // 递归检测
    if (this.parentWidget!.hasVariable('page-toc-recursion-detection', 'yes')) {
      this.domNodes.push(
        parent.appendChild(this.document.createTextNode('[Page TOC]')),
      );
      return;
    }
    this.setVariable('page-toc-recursion-detection', 'yes');

    // 渲染目录
    const tocNode = $tw.utils.domMaker(this.tocNodeTag, {
      class: this.tocNodeClass,
    });
    this.domNodes.push(tocNode);

    try {
      const toc = this.getTOCInfo();
      if (!toc || toc.headers.length === 0) {
        tocNode.insertBefore(
          $tw.utils.domMaker(this.tocHeaderNodeTag, {
            class: `${this.tocHeaderNodeClassPrefix}empty`,
            text: this.emptyMessage,
          }),
          nextSibling,
        );
      } else {
        for (let i = 0, len = toc.headers.length; i < len; i++) {
          const { tag, text, count } = toc.headers[i];
          const headerNode = $tw.utils.domMaker(this.tocHeaderNodeTag, {
            class: `${this.tocHeaderNodeClassPrefix}${tag}`,
            text,
          });
          if ($tw.browser) {
            // eslint-disable-next-line @typescript-eslint/no-loop-func
            headerNode.addEventListener('click', () => {
              const target = document
                .querySelector(
                  `.tc-tiddler-frame[data-tiddler-title="${toc.title.replace(
                    '"',
                    '\\"',
                  )}"]`,
                )
                ?.querySelectorAll?.(`.tc-tiddler-body > .markdown > ${tag}`)?.[count];
              if (!target) {
                return;
              }
              switch (this.scrollMode) {
                case 'center':
                case 'nearest': {
                  // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
                  target.scrollIntoView({
                    behavior: 'smooth',
                    block: this.scrollMode,
                  });
                  break;
                }
                default: {
                  target.scrollIntoView({
                    behavior: 'auto',
                    block: this.scrollMode,
                  });
                  if (this.scrollMode === 'end') {
                    document.body.scrollTop += 100;
                    if (document.scrollingElement) {
                      document.scrollingElement.scrollTop += 100;
                    }
                  } else {
                    document.body.scrollTop -= 100;
                    if (document.scrollingElement) {
                      document.scrollingElement.scrollTop -= 100;
                    }
                  }
                }
              }
            });
          }
          tocNode.appendChild(headerNode);
        }
      }
    } catch (e) {
      console.error(e);
      tocNode.textContent = String(e);
    }
    parent.insertBefore(tocNode, nextSibling);
  }

  refresh(changedTiddlers: IChangedTiddlers) {
    const changedAttributes = this.computeAttributes();
    if (
      $tw.utils.count(changedAttributes) > 0 ||
      Object.hasOwnProperty.call(changedAttributes, this.tocTitle)
    ) {
      this.refreshSelf();
      this.refreshChildren(changedTiddlers);
      return true;
    }
    return this.refreshChildren(changedTiddlers);
  }

  getTOCInfo() {
    // Check empty
    if (this.tocTitle === '') {
      return undefined;
    }
    const currentTiddler = $tw.wiki.getTiddler(this.tocTitle);
    if (!currentTiddler) {
      return undefined;
    }
    const type = currentTiddler.fields.type || 'text/vnd.tiddlywiki';
    if (type !== 'text/vnd.tiddlywiki' && type !== 'text/x-markdown' && type !== 'text/markdown') {
      return undefined;
    }
    const headers: { tag: HeaderTag; count: number; text: string }[] = [];
    const headersCount: Record<HeaderTag, number> = {
      h1: 0,
      h2: 0,
      h3: 0,
      h4: 0,
      h5: 0,
      h6: 0,
    };
    const root = $tw.wiki.parseTiddler(this.tocTitle).tree;
    if (root.length === 0) {
      return undefined;
    }
    let contents = root;
    // Parse params
    while (['set', 'importvariables'].includes(contents[0]?.type)) {
      contents = (contents[0] as IWikiASTNode).children ?? [];
    }
    const processNode = (node: IWikiASTNode) => {
      if (node.type !== 'element') {
        return;
      }

      // Find text within the header element
      let text = '';
      for (const childNode of node.children || []) {
        if (childNode.type === 'text') {
          text += childNode.text;
        }
      }
      // Recursive processing for nested div elements
      for (const childNode of node.children || []) {
        if (childNode.type === 'element' && childNode.tag.match(/^h[1-6]$/)) {
          processNode(childNode);
        }
      }
      if (node.tag.match(/^h[1-6]$/)){
      headers.push({
        tag: (node as any).tag,
        count: headersCount[(node as any).tag as HeaderTag]++,
        text: text.trim(),
      });
      }
    };
    
    $tw.utils.each([...contents], processNode);
    return {
      title: this.tocTitle,
      headers,
    };
  }
}

exports['page-toc'] = PageTOCWidget;

from tiddlyseq.

Gk0Wk avatar Gk0Wk commented on August 21, 2024

@straywriter 你的这份代码有个问题就是只能识别纯文本的标题,如果其中包含了变量微件等就看不到了。

因此最后的方式是先渲染,渲染之后再找,这样反倒是很简单,写个dfs就可以了。

于是现在tos已经可以支持任意位置的标题了,除了写在外面的、还有引用的等等,和看到的保持一致。

请升级最新版本

from tiddlyseq.

Related Issues (15)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.