浏览代码

refactored notebook metadata, images and shared methods

Zuoyuan Huang 6 年之前
父节点
当前提交
a803f211bf
共有 31 个文件被更改,包括 266 次插入275 次删除
  1. 0 8
      packages/toc/build-dev.sh
  2. 1 2
      packages/toc/package.json
  3. 1 1
      packages/toc/src/extension.ts
  4. 12 7
      packages/toc/src/generators/markdowndocgenerator/index.ts
  5. 2 2
      packages/toc/src/generators/markdowndocgenerator/toolbargenerator.tsx
  6. 11 7
      packages/toc/src/generators/notebookgenerator/index.ts
  7. 6 9
      packages/toc/src/generators/notebookgenerator/itemrenderer.tsx
  8. 19 4
      packages/toc/src/generators/notebookgenerator/optionsmanager.ts
  9. 12 12
      packages/toc/src/generators/notebookgenerator/toolbargenerator.tsx
  10. 202 209
      packages/toc/src/generators/shared.ts
  11. 0 14
      packages/toc/src/toc.tsx
  12. 0 0
      packages/toc/style/img/autonumbering_hover.svg
  13. 0 0
      packages/toc/style/img/autonumbering_selected.svg
  14. 0 0
      packages/toc/style/img/autonumbering_unselected.svg
  15. 0 0
      packages/toc/style/img/check.svg
  16. 0 0
      packages/toc/style/img/code_hover.svg
  17. 0 0
      packages/toc/style/img/code_selected.svg
  18. 0 0
      packages/toc/style/img/code_unselected.svg
  19. 0 0
      packages/toc/style/img/downarrow.svg
  20. 0 0
      packages/toc/style/img/eyeball_hidden.svg
  21. 0 0
      packages/toc/style/img/eyeball_hover.svg
  22. 0 0
      packages/toc/style/img/eyeball_view.svg
  23. 0 0
      packages/toc/style/img/markdown_hover.svg
  24. 0 0
      packages/toc/style/img/markdown_selected.svg
  25. 0 0
      packages/toc/style/img/markdown_unselected.svg
  26. 0 0
      packages/toc/style/img/menu_arrow.svg
  27. 0 0
      packages/toc/style/img/numbering.svg
  28. 0 0
      packages/toc/style/img/rightarrow.svg
  29. 0 0
      packages/toc/style/img/tag_hover.svg
  30. 0 0
      packages/toc/style/img/tag_selected.svg
  31. 0 0
      packages/toc/style/img/tag_unselected.svg

+ 0 - 8
packages/toc/build-dev.sh

@@ -1,8 +0,0 @@
-npm i
-npm run build
-cd ../jupyterlab
-jlpm run remove:package jupyterlab-toc
-jlpm run add:sibling ../jupyterlab-toc
-jlpm run build
-cd ../jupyterlab-toc
-

+ 1 - 2
packages/toc/package.json

@@ -16,8 +16,7 @@
   "author": "Ian Rose",
   "files": [
     "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
-    "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}",
-    "static/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}"
+    "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}"
   ],
   "main": "lib/index.js",
   "types": "lib/index.d.ts",

+ 1 - 1
packages/toc/src/extension.ts

@@ -60,7 +60,7 @@ function activateTOC(
   rendermime: IRenderMimeRegistry
 ): ITableOfContentsRegistry {
   // Create the ToC widget.
-  const toc = new TableOfContents({ docmanager, rendermime, notebookTracker });
+  const toc = new TableOfContents({ docmanager, rendermime });
 
   // Create the ToC registry.
   const registry = new TableOfContentsRegistry();

+ 12 - 7
packages/toc/src/generators/markdowndocgenerator/index.ts

@@ -7,7 +7,12 @@ import { FileEditor, IEditorTracker } from '@jupyterlab/fileeditor';
 
 import { TableOfContentsRegistry } from '../../registry';
 
-import { SharedMethods, INotebookHeading } from '../shared';
+import {
+  generateNumbering,
+  getRenderedHTMLHeadings,
+  isMarkdown,
+  INotebookHeading
+} from '../shared';
 
 import { IInstanceTracker, ISanitizer } from '@jupyterlab/apputils';
 
@@ -46,7 +51,7 @@ export function createMarkdownGenerator(
     isEnabled: editor => {
       // Only enable this if the editor mimetype matches
       // one of a few markdown variants.
-      return SharedMethods.isMarkdown(editor.content.model.mimeType);
+      return isMarkdown(editor.content.model.mimeType);
     },
     generate: editor => {
       let numberingDict: { [level: number]: number } = {};
@@ -93,7 +98,7 @@ export function createRenderedMarkdownGenerator(
     isEnabled: widget => {
       // Only enable this if the editor mimetype matches
       // one of a few markdown variants.
-      return SharedMethods.isMarkdown(widget.content.mimeType);
+      return isMarkdown(widget.content.mimeType);
     },
     generate: widget => {
       let numberingDict: { [level: number]: number } = {};
@@ -102,7 +107,7 @@ export function createRenderedMarkdownGenerator(
           el.scrollIntoView();
         };
       };
-      return SharedMethods.getRenderedHTMLHeadings(
+      return getRenderedHTMLHeadings(
         widget.content.node,
         onClickFactory,
         sanitizer,
@@ -138,7 +143,7 @@ namespace Private {
         const level = match[1].length;
         // Take special care to parse markdown links into raw text.
         const text = match[2].replace(/\[(.+)\]\(.+\)/g, '$1');
-        let numbering = SharedMethods.generateNumbering(numberingDict, level);
+        let numbering = generateNumbering(numberingDict, level);
         headings.push({ text, numbering, level, onClick, type: 'header' });
         return;
       }
@@ -149,7 +154,7 @@ namespace Private {
         const level = match[1][0] === '=' ? 1 : 2;
         // Take special care to parse markdown links into raw text.
         const text = lines[idx - 1].replace(/\[(.+)\]\(.+\)/g, '$1');
-        let numbering = SharedMethods.generateNumbering(numberingDict, level);
+        let numbering = generateNumbering(numberingDict, level);
         headings.push({ text, numbering, level, onClick, type: 'header' });
         return;
       }
@@ -161,7 +166,7 @@ namespace Private {
       if (match) {
         const level = parseInt(match[1], 10);
         const text = match[2];
-        let numbering = SharedMethods.generateNumbering(numberingDict, level);
+        let numbering = generateNumbering(numberingDict, level);
         headings.push({ text, numbering, level, onClick, type: 'header' });
         return;
       }

+ 2 - 2
packages/toc/src/generators/markdowndocgenerator/toolbargenerator.tsx

@@ -35,7 +35,7 @@ export function markdownDocGeneratorToolbar(
           <img
             alt="Toggle Auto-Numbering"
             title="Toggle Auto-Numbering"
-            src={require('../../../static/autonumbering_selected.svg')}
+            src={require('../../../style/img/autonumbering_selected.svg')}
             className="toc-toolbar-auto-numbering-icon toc-toolbar-icon"
           />
         </div>
@@ -47,7 +47,7 @@ export function markdownDocGeneratorToolbar(
           <img
             alt="Toggle Auto-Numbering"
             title="Toggle Auto-Numbering"
-            src={require('../../../static/autonumbering_unselected.svg')}
+            src={require('../../../style/img/autonumbering_unselected.svg')}
             className="toc-toolbar-auto-numbering-icon toc-toolbar-icon"
           />
         </div>

+ 11 - 7
packages/toc/src/generators/notebookgenerator/index.ts

@@ -18,7 +18,13 @@ import { TableOfContents } from '../../toc';
 
 import { NotebookGeneratorOptionsManager } from './optionsmanager';
 
-import { SharedMethods, INotebookHeading } from '../shared';
+import {
+  getRenderedHTMLHeadings,
+  getMarkdownHeadings,
+  isDOM,
+  isMarkdown,
+  INotebookHeading
+} from '../shared';
 
 /**
  * Create a TOC generator for notebooks.
@@ -119,9 +125,7 @@ export function createNotebookGenerator(
             // (that is, markdown, vdom, or text/html)
             const outputModel = (model as CodeCellModel).outputs.get(i);
             const dataTypes = Object.keys(outputModel.data);
-            const htmlData = dataTypes.filter(
-              t => SharedMethods.isMarkdown(t) || SharedMethods.isDOM(t)
-            );
+            const htmlData = dataTypes.filter(t => isMarkdown(t) || isDOM(t));
             if (!htmlData.length) {
               continue;
             }
@@ -145,7 +149,7 @@ export function createNotebookGenerator(
             };
             let lastLevel = Private.getLastLevel(headings);
             let numbering = options.numbering;
-            let renderedHeadings = SharedMethods.getRenderedHTMLHeadings(
+            let renderedHeadings = getRenderedHTMLHeadings(
               outputWidget.node,
               onClickFactory,
               sanitizer,
@@ -237,7 +241,7 @@ export function createNotebookGenerator(
             };
             let numbering = options.numbering;
             let lastLevel = Private.getLastLevel(headings);
-            let renderedHeadings = SharedMethods.getRenderedHTMLHeadings(
+            let renderedHeadings = getRenderedHTMLHeadings(
               cell.node,
               onClickFactory,
               sanitizer,
@@ -319,7 +323,7 @@ export function createNotebookGenerator(
               };
             };
             let lastLevel = Private.getLastLevel(headings);
-            let renderedHeadings = SharedMethods.getMarkdownHeadings(
+            let renderedHeadings = getMarkdownHeadings(
               model.value.text,
               onClickFactory,
               numberingDict,

+ 6 - 9
packages/toc/src/generators/notebookgenerator/itemrenderer.tsx

@@ -7,7 +7,7 @@ import { Cell } from '@jupyterlab/cells';
 
 import { NotebookGeneratorOptionsManager } from './optionsmanager';
 
-import { SharedConstants, INotebookHeading } from '../shared';
+import { sanitizerOptions, INotebookHeading } from '../shared';
 
 import * as React from 'react';
 
@@ -45,10 +45,7 @@ export function notebookItemRenderer(
           dangerouslySetInnerHTML={{
             __html:
               numbering +
-              options.sanitizer.sanitize(
-                item.html,
-                SharedConstants.sanitizerOptions
-              )
+              options.sanitizer.sanitize(item.html, sanitizerOptions)
           }}
           className={item.type + '-cell'}
           style={{ fontSize, paddingLeft }}
@@ -70,7 +67,7 @@ export function notebookItemRenderer(
             <div className="toc-twist-placeholder">placeholder</div>
             <img
               className="toc-arrow-img"
-              src={require('../../../static/downarrow.svg')}
+              src={require('../../../style/img/downarrow.svg')}
             />
           </div>
         );
@@ -86,7 +83,7 @@ export function notebookItemRenderer(
               <div className="toc-twist-placeholder">placeholder</div>
               <img
                 className="toc-arrow-img"
-                src={require('../../../static/rightarrow.svg')}
+                src={require('../../../style/img/rightarrow.svg')}
               />
             </div>
           );
@@ -120,7 +117,7 @@ export function notebookItemRenderer(
             <div className="toc-twist-placeholder">placeholder</div>
             <img
               className="toc-arrow-img"
-              src={require('../../../static/downarrow.svg')}
+              src={require('../../../style/img/downarrow.svg')}
             />
           </div>
         );
@@ -136,7 +133,7 @@ export function notebookItemRenderer(
               <div className="toc-twist-placeholder">placeholder</div>
               <img
                 className="toc-arrow-img"
-                src={require('../../../static/rightarrow.svg')}
+                src={require('../../../style/img/rightarrow.svg')}
               />
             </div>
           );

+ 19 - 4
packages/toc/src/generators/notebookgenerator/optionsmanager.ts

@@ -42,10 +42,16 @@ export class NotebookGeneratorOptionsManager extends TableOfContentsRegistry.IGe
     }
   }
 
+  set notebookMetadata(value: [string, any]) {
+    if (this._notebook.currentWidget != null) {
+      this._notebook.currentWidget.model.metadata.set(value[0], value[1]);
+    }
+  }
+
   set numbering(value: boolean) {
     this._numbering = value;
     this._widget.update();
-    this._widget.notebookMetadata = ['toc-autonumbering', this._numbering];
+    this.notebookMetadata = ['toc-autonumbering', this._numbering];
     this.changeNumberingStateForAllCells(this._numbering);
   }
 
@@ -55,7 +61,7 @@ export class NotebookGeneratorOptionsManager extends TableOfContentsRegistry.IGe
 
   set showCode(value: boolean) {
     this._showCode = value;
-    this._widget.notebookMetadata = ['toc-showcode', this._showCode];
+    this.notebookMetadata = ['toc-showcode', this._showCode];
     this._widget.update();
   }
 
@@ -65,7 +71,7 @@ export class NotebookGeneratorOptionsManager extends TableOfContentsRegistry.IGe
 
   set showMarkdown(value: boolean) {
     this._showMarkdown = value;
-    this._widget.notebookMetadata = ['toc-showmarkdowntxt', this._showMarkdown];
+    this.notebookMetadata = ['toc-showmarkdowntxt', this._showMarkdown];
     this._widget.update();
   }
 
@@ -75,7 +81,7 @@ export class NotebookGeneratorOptionsManager extends TableOfContentsRegistry.IGe
 
   set showTags(value: boolean) {
     this._showTags = value;
-    this._widget.notebookMetadata = ['toc-showtags', this._showTags];
+    this.notebookMetadata = ['toc-showtags', this._showTags];
     this._widget.update();
   }
 
@@ -92,6 +98,14 @@ export class NotebookGeneratorOptionsManager extends TableOfContentsRegistry.IGe
     return this._filtered;
   }
 
+  set preRenderedToolbar(value: any) {
+    this._preRenderedToolbar = value;
+  }
+
+  get preRenderedToolbar() {
+    return this._preRenderedToolbar;
+  }
+
   updateWidget() {
     this._widget.update();
   }
@@ -111,6 +125,7 @@ export class NotebookGeneratorOptionsManager extends TableOfContentsRegistry.IGe
   }
 
   sanitizer: ISanitizer;
+  private _preRenderedToolbar: any = null;
   private _filtered: string[] = [];
   private _numbering: boolean;
   private _showCode = false;

+ 12 - 12
packages/toc/src/generators/notebookgenerator/toolbargenerator.tsx

@@ -136,7 +136,7 @@ export function notebookGeneratorToolbar(
           <img
             alt="Toggle Code Cells"
             title="Toggle Code Cells"
-            src={require('../../../static/code_selected.svg')}
+            src={require('../../../style/img/code_selected.svg')}
             className="toc-toolbar-code-icon toc-toolbar-icon"
           />
         </div>
@@ -148,13 +148,13 @@ export function notebookGeneratorToolbar(
           <img
             alt="Toggle Code Cells"
             title="Toggle Code Cells"
-            src={require('../../../static/code_unselected.svg')}
+            src={require('../../../style/img/code_unselected.svg')}
             className="toc-toolbar-code-icon toc-toolbar-icon toc-hover--off"
           />
           <img
             alt="Toggle Code Cells"
             title="Toggle Code Cells"
-            src={require('../../../static/code_hover.svg')}
+            src={require('../../../style/img/code_hover.svg')}
             className="toc-toolbar-code-icon toc-toolbar-icon toc-hover--on"
           />
         </div>
@@ -168,7 +168,7 @@ export function notebookGeneratorToolbar(
           <img
             alt="Toggle Code Cells"
             title="Toggle Code Cells"
-            src={require('../../../static/markdown_selected.svg')}
+            src={require('../../../style/img/markdown_selected.svg')}
             className="toc-toolbar-markdown-icon toc-toolbar-icon"
           />
         </div>
@@ -180,13 +180,13 @@ export function notebookGeneratorToolbar(
           <img
             alt="Toggle Code Cells"
             title="Toggle Code Cells"
-            src={require('../../../static/markdown_unselected.svg')}
+            src={require('../../../style/img/markdown_unselected.svg')}
             className="toc-toolbar-markdown-icon toc-toolbar-icon toc-hover--off"
           />
           <img
             alt="Toggle Code Cells"
             title="Toggle Code Cells"
-            src={require('../../../static/markdown_hover.svg')}
+            src={require('../../../style/img/markdown_hover.svg')}
             className="toc-toolbar-markdown-icon toc-toolbar-icon toc-hover--on"
           />
         </div>
@@ -200,7 +200,7 @@ export function notebookGeneratorToolbar(
           <img
             alt="Toggle Auto-Numbering"
             title="Toggle Auto-Numbering"
-            src={require('../../../static/autonumbering_selected.svg')}
+            src={require('../../../style/img/autonumbering_selected.svg')}
             className="toc-toolbar-auto-numbering-icon toc-toolbar-icon"
           />
         </div>
@@ -212,13 +212,13 @@ export function notebookGeneratorToolbar(
           <img
             alt="Toggle Auto-Numbering"
             title="Toggle Auto-Numbering"
-            src={require('../../../static/autonumbering_unselected.svg')}
+            src={require('../../../style/img/autonumbering_unselected.svg')}
             className="toc-toolbar-auto-numbering-icon toc-toolbar-icon toc-hover--off"
           />
           <img
             alt="Toggle Auto-Numbering"
             title="Toggle Auto-Numbering"
-            src={require('../../../static/autonumbering_hover.svg')}
+            src={require('../../../style/img/autonumbering_hover.svg')}
             className="toc-toolbar-auto-numbering-icon toc-toolbar-icon toc-hover--on"
           />
         </div>
@@ -231,13 +231,13 @@ export function notebookGeneratorToolbar(
             className="toc-hover--off"
             alt="Show Tags Menu"
             title="Show Tags Menu"
-            src={require('../../../static/tag_unselected.svg')}
+            src={require('../../../style/img/tag_unselected.svg')}
           />
           <img
             className="toc-hover--on"
             alt="Show Tags Menu"
             title="Show Tags Menu"
-            src={require('../../../static/tag_hover.svg')}
+            src={require('../../../style/img/tag_hover.svg')}
           />
         </div>
       );
@@ -257,7 +257,7 @@ export function notebookGeneratorToolbar(
           <img
             alt="Hide Tag Dropdown"
             title="Hide Tag Dropdown"
-            src={require('../../../static/tag_selected.svg')}
+            src={require('../../../style/img/tag_selected.svg')}
           />
         );
       }

+ 202 - 209
packages/toc/src/generators/shared.ts

@@ -14,242 +14,235 @@ export interface INotebookHeading extends IHeading {
   hasChild?: boolean;
 }
 
-export class SharedMethods {
-  static incrementNumberingDict(dict: any, level: number) {
-    if (dict[level + 1] != undefined) {
-      dict[level + 1] = undefined;
-    }
-    if (dict[level] === undefined) {
-      dict[level] = 1;
-    } else {
-      dict[level]++;
-    }
+function incrementNumberingDict(dict: any, level: number) {
+  if (dict[level + 1] != undefined) {
+    dict[level + 1] = undefined;
   }
+  if (dict[level] === undefined) {
+    dict[level] = 1;
+  } else {
+    dict[level]++;
+  }
+}
 
-  static generateNumbering(numberingDict: any, level: number) {
-    let numbering = undefined;
-    if (numberingDict != null) {
-      this.incrementNumberingDict(numberingDict, level);
-      numbering = '';
-      for (var j = 1; j <= level; j++) {
-        numbering +=
-          (numberingDict[j] == undefined ? '0' : numberingDict[j]) + '.';
-        if (j == level) {
-          numbering += ' ';
-        }
+export function generateNumbering(numberingDict: any, level: number) {
+  let numbering = undefined;
+  if (numberingDict != null) {
+    incrementNumberingDict(numberingDict, level);
+    numbering = '';
+    for (var j = 1; j <= level; j++) {
+      numbering +=
+        (numberingDict[j] == undefined ? '0' : numberingDict[j]) + '.';
+      if (j == level) {
+        numbering += ' ';
       }
     }
-    return numbering;
   }
+  return numbering;
+}
 
-  /**
-   * Given an HTML element, generate ToC headings
-   * by finding all the headers and making IHeading objects for them.
-   */
-  static getRenderedHTMLHeadings(
-    node: HTMLElement,
-    onClickFactory: (el: Element) => (() => void),
-    sanitizer: ISanitizer,
-    numberingDict: any,
-    lastLevel: number,
-    needNumbering = false,
-    cellRef?: Cell
-  ): INotebookHeading[] {
-    let headings: INotebookHeading[] = [];
-    let headingNodes = node.querySelectorAll('h1, h2, h3, h4, h5, h6, p');
-    if (headingNodes.length > 0) {
-      let markdownCell = headingNodes[0];
-      if (markdownCell.nodeName.toLowerCase() === 'p') {
-        if (markdownCell.innerHTML) {
-          headings.push({
-            level: lastLevel + 1,
-            html: markdownCell.innerHTML,
-            text: markdownCell.textContent,
-            onClick: onClickFactory(markdownCell),
-            type: 'markdown',
-            cellRef: cellRef,
-            hasChild: true
-          });
-        }
-      } else {
-        const heading = headingNodes[0];
-        const level = parseInt(heading.tagName[1]);
-        const text = heading.textContent;
-        let shallHide = !needNumbering;
-        if (heading.getElementsByClassName('numbering-entry').length > 0) {
-          heading.removeChild(
-            heading.getElementsByClassName('numbering-entry')[0]
-          );
-        }
-        let html = sanitizer.sanitize(
-          heading.innerHTML,
-          SharedConstants.sanitizerOptions
-        );
-        html = html.replace('¶', ''); // Remove the anchor symbol.
-        const onClick = onClickFactory(heading);
-        let numbering = SharedMethods.generateNumbering(numberingDict, level);
-        let numberingElement =
-          '<span class="numbering-entry" ' +
-          (shallHide ? ' hidden="true"' : '') +
-          '>' +
-          numbering +
-          '</span>';
-        heading.innerHTML = numberingElement + html;
+/**
+ * Given an HTML element, generate ToC headings
+ * by finding all the headers and making IHeading objects for them.
+ */
+export function getRenderedHTMLHeadings(
+  node: HTMLElement,
+  onClickFactory: (el: Element) => (() => void),
+  sanitizer: ISanitizer,
+  numberingDict: any,
+  lastLevel: number,
+  needNumbering = false,
+  cellRef?: Cell
+): INotebookHeading[] {
+  let headings: INotebookHeading[] = [];
+  let headingNodes = node.querySelectorAll('h1, h2, h3, h4, h5, h6, p');
+  if (headingNodes.length > 0) {
+    let markdownCell = headingNodes[0];
+    if (markdownCell.nodeName.toLowerCase() === 'p') {
+      if (markdownCell.innerHTML) {
         headings.push({
-          level,
-          text,
-          numbering,
-          html,
-          onClick,
-          type: 'header',
+          level: lastLevel + 1,
+          html: markdownCell.innerHTML,
+          text: markdownCell.textContent,
+          onClick: onClickFactory(markdownCell),
+          type: 'markdown',
           cellRef: cellRef,
           hasChild: true
         });
       }
-    }
-    return headings;
-  }
-
-  /**
-   * Given a string of markdown, get the markdown headings
-   * in that string.
-   */
-  static getMarkdownHeadings(
-    text: string,
-    onClickFactory: (line: number) => (() => void),
-    numberingDict: any,
-    lastLevel: number,
-    cellRef: Cell
-  ): INotebookHeading[] {
-    // Split the text into lines.
-    const lines = text.split('\n');
-    let headings: INotebookHeading[] = [];
-    // Iterate over the lines to get the header level and
-    // the text for the line.
-    let line = lines[0];
-    let idx = 0;
-    // Make an onClick handler for this line.
-    const onClick = onClickFactory(idx);
-
-    // First test for '#'-style headers.
-    let match = line.match(/^([#]{1,6}) (.*)/);
-    let match2 = line.match(/^([=]{2,}|[-]{2,})/);
-    let match3 = line.match(/<h([1-6])>(.*)<\/h\1>/i);
-    if (match) {
-      const level = match[1].length;
-      // Take special care to parse markdown links into raw text.
-      const text = match[2].replace(/\[(.+)\]\(.+\)/g, '$1');
-      let numbering = SharedMethods.generateNumbering(numberingDict, level);
+    } else {
+      const heading = headingNodes[0];
+      const level = parseInt(heading.tagName[1]);
+      const text = heading.textContent;
+      let shallHide = !needNumbering;
+      if (heading.getElementsByClassName('numbering-entry').length > 0) {
+        heading.removeChild(
+          heading.getElementsByClassName('numbering-entry')[0]
+        );
+      }
+      let html = sanitizer.sanitize(heading.innerHTML, sanitizerOptions);
+      html = html.replace('¶', ''); // Remove the anchor symbol.
+      const onClick = onClickFactory(heading);
+      let numbering = generateNumbering(numberingDict, level);
+      let numberingElement =
+        '<span class="numbering-entry" ' +
+        (shallHide ? ' hidden="true"' : '') +
+        '>' +
+        numbering +
+        '</span>';
+      heading.innerHTML = numberingElement + html;
       headings.push({
-        text,
         level,
-        numbering,
-        onClick,
-        type: 'header',
-        cellRef: cellRef,
-        hasChild: true
-      });
-    }
-
-    // Next test for '==='-style headers.
-    else if (match2 && idx > 0) {
-      const level = match2[1][0] === '=' ? 1 : 2;
-      // Take special care to parse markdown links into raw text.
-      const text = lines[idx - 1].replace(/\[(.+)\]\(.+\)/g, '$1');
-      let numbering = SharedMethods.generateNumbering(numberingDict, level);
-      headings.push({
         text,
-        level,
         numbering,
+        html,
         onClick,
         type: 'header',
         cellRef: cellRef,
         hasChild: true
       });
     }
+  }
+  return headings;
+}
 
-    // Finally test for HTML headers. This will not catch multiline
-    // headers, nor will it catch multiple headers on the same line.
-    // It should do a decent job of catching many, though.
-    else if (match3) {
-      const level = parseInt(match3[1], 10);
-      const text = match3[2];
-      let numbering = SharedMethods.generateNumbering(numberingDict, level);
-      headings.push({
-        text,
-        level,
-        numbering,
-        onClick,
-        type: 'header',
-        cellRef: cellRef,
-        hasChild: true
-      });
-    } else {
-      headings.push({
-        text: line,
-        level: lastLevel + 1,
-        onClick,
-        type: 'markdown',
-        cellRef: cellRef,
-        hasChild: false
-      });
-    }
-    return headings;
+/**
+ * Given a string of markdown, get the markdown headings
+ * in that string.
+ */
+export function getMarkdownHeadings(
+  text: string,
+  onClickFactory: (line: number) => (() => void),
+  numberingDict: any,
+  lastLevel: number,
+  cellRef: Cell
+): INotebookHeading[] {
+  // Split the text into lines.
+  const lines = text.split('\n');
+  let headings: INotebookHeading[] = [];
+  // Iterate over the lines to get the header level and
+  // the text for the line.
+  let line = lines[0];
+  let idx = 0;
+  // Make an onClick handler for this line.
+  const onClick = onClickFactory(idx);
+
+  // First test for '#'-style headers.
+  let match = line.match(/^([#]{1,6}) (.*)/);
+  let match2 = line.match(/^([=]{2,}|[-]{2,})/);
+  let match3 = line.match(/<h([1-6])>(.*)<\/h\1>/i);
+  if (match) {
+    const level = match[1].length;
+    // Take special care to parse markdown links into raw text.
+    const text = match[2].replace(/\[(.+)\]\(.+\)/g, '$1');
+    let numbering = generateNumbering(numberingDict, level);
+    headings.push({
+      text,
+      level,
+      numbering,
+      onClick,
+      type: 'header',
+      cellRef: cellRef,
+      hasChild: true
+    });
   }
 
-  /**
-   * Return whether the mime type is some flavor of markdown.
-   */
-  static isMarkdown(mime: string): boolean {
-    return (
-      mime === 'text/x-ipythongfm' ||
-      mime === 'text/x-markdown' ||
-      mime === 'text/x-gfm' ||
-      mime === 'text/markdown'
-    );
+  // Next test for '==='-style headers.
+  else if (match2 && idx > 0) {
+    const level = match2[1][0] === '=' ? 1 : 2;
+    // Take special care to parse markdown links into raw text.
+    const text = lines[idx - 1].replace(/\[(.+)\]\(.+\)/g, '$1');
+    let numbering = generateNumbering(numberingDict, level);
+    headings.push({
+      text,
+      level,
+      numbering,
+      onClick,
+      type: 'header',
+      cellRef: cellRef,
+      hasChild: true
+    });
   }
 
-  /**
-   * Return whether the mime type is DOM-ish (html or vdom).
-   */
-  static isDOM(mime: string): boolean {
-    return mime === VDOM_MIME_TYPE || mime === HTML_MIME_TYPE;
+  // Finally test for HTML headers. This will not catch multiline
+  // headers, nor will it catch multiple headers on the same line.
+  // It should do a decent job of catching many, though.
+  else if (match3) {
+    const level = parseInt(match3[1], 10);
+    const text = match3[2];
+    let numbering = generateNumbering(numberingDict, level);
+    headings.push({
+      text,
+      level,
+      numbering,
+      onClick,
+      type: 'header',
+      cellRef: cellRef,
+      hasChild: true
+    });
+  } else {
+    headings.push({
+      text: line,
+      level: lastLevel + 1,
+      onClick,
+      type: 'markdown',
+      cellRef: cellRef,
+      hasChild: false
+    });
   }
+  return headings;
 }
 
-export namespace SharedConstants {
-  /**
-   * Allowed HTML tags for the ToC entries. We use this to
-   * sanitize HTML headings, if they are given. We specifically
-   * disallow anchor tags, since we are adding our own.
-   */
-  export const sanitizerOptions = {
-    allowedTags: [
-      'p',
-      'blockquote',
-      'b',
-      'i',
-      'strong',
-      'em',
-      'strike',
-      'code',
-      'br',
-      'div',
-      'span',
-      'pre',
-      'del'
-    ],
-    allowedAttributes: {
-      // Allow "class" attribute for <code> tags.
-      code: ['class'],
-      // Allow "class" attribute for <span> tags.
-      span: ['class'],
-      // Allow "class" attribute for <div> tags.
-      div: ['class'],
-      // Allow "class" attribute for <p> tags.
-      p: ['class'],
-      // Allow "class" attribute for <pre> tags.
-      pre: ['class']
-    }
-  };
+/**
+ * Return whether the mime type is some flavor of markdown.
+ */
+export function isMarkdown(mime: string): boolean {
+  return (
+    mime === 'text/x-ipythongfm' ||
+    mime === 'text/x-markdown' ||
+    mime === 'text/x-gfm' ||
+    mime === 'text/markdown'
+  );
+}
+
+/**
+ * Return whether the mime type is DOM-ish (html or vdom).
+ */
+export function isDOM(mime: string): boolean {
+  return mime === VDOM_MIME_TYPE || mime === HTML_MIME_TYPE;
 }
+
+/**
+ * Allowed HTML tags for the ToC entries. We use this to
+ * sanitize HTML headings, if they are given. We specifically
+ * disallow anchor tags, since we are adding our own.
+ */
+export const sanitizerOptions = {
+  allowedTags: [
+    'p',
+    'blockquote',
+    'b',
+    'i',
+    'strong',
+    'em',
+    'strike',
+    'code',
+    'br',
+    'div',
+    'span',
+    'pre',
+    'del'
+  ],
+  allowedAttributes: {
+    // Allow "class" attribute for <code> tags.
+    code: ['class'],
+    // Allow "class" attribute for <span> tags.
+    span: ['class'],
+    // Allow "class" attribute for <div> tags.
+    div: ['class'],
+    // Allow "class" attribute for <p> tags.
+    p: ['class'],
+    // Allow "class" attribute for <pre> tags.
+    pre: ['class']
+  }
+};

+ 0 - 14
packages/toc/src/toc.tsx

@@ -15,7 +15,6 @@ import { TableOfContentsRegistry } from './registry';
 
 import * as React from 'react';
 import * as ReactDOM from 'react-dom';
-import { INotebookTracker } from '@jupyterlab/notebook';
 
 /**
  * Timeout for throttling TOC rendering.
@@ -33,13 +32,8 @@ export class TableOfContents extends Widget {
     super();
     this._docmanager = options.docmanager;
     this._rendermime = options.rendermime;
-    this._notebook = options.notebookTracker;
   }
 
-  // filterByTag(name: string) {
-
-  // }
-
   /**
    * The current widget-generator tuple for the ToC.
    */
@@ -157,13 +151,6 @@ export class TableOfContents extends Widget {
     this.update();
   }
 
-  set notebookMetadata(value: [string, any]) {
-    if (this._notebook.currentWidget != null) {
-      this._notebook.currentWidget.model.metadata.set(value[0], value[1]);
-    }
-  }
-
-  private _notebook: INotebookTracker;
   private _rendermime: IRenderMimeRegistry;
   private _docmanager: IDocumentManager;
   private _current: TableOfContents.ICurrentWidget | null;
@@ -187,7 +174,6 @@ export namespace TableOfContents {
      * The rendermime for the application.
      */
     rendermime: IRenderMimeRegistry;
-    notebookTracker: INotebookTracker;
   }
 
   /**

+ 0 - 0
packages/toc/static/autonumbering_hover.svg → packages/toc/style/img/autonumbering_hover.svg


+ 0 - 0
packages/toc/static/autonumbering_selected.svg → packages/toc/style/img/autonumbering_selected.svg


+ 0 - 0
packages/toc/static/autonumbering_unselected.svg → packages/toc/style/img/autonumbering_unselected.svg


+ 0 - 0
packages/toc/static/check.svg → packages/toc/style/img/check.svg


+ 0 - 0
packages/toc/static/code_hover.svg → packages/toc/style/img/code_hover.svg


+ 0 - 0
packages/toc/static/code_selected.svg → packages/toc/style/img/code_selected.svg


+ 0 - 0
packages/toc/static/code_unselected.svg → packages/toc/style/img/code_unselected.svg


+ 0 - 0
packages/toc/static/downarrow.svg → packages/toc/style/img/downarrow.svg


+ 0 - 0
packages/toc/static/eyeball_hidden.svg → packages/toc/style/img/eyeball_hidden.svg


+ 0 - 0
packages/toc/static/eyeball_hover.svg → packages/toc/style/img/eyeball_hover.svg


+ 0 - 0
packages/toc/static/eyeball_view.svg → packages/toc/style/img/eyeball_view.svg


+ 0 - 0
packages/toc/static/markdown_hover.svg → packages/toc/style/img/markdown_hover.svg


+ 0 - 0
packages/toc/static/markdown_selected.svg → packages/toc/style/img/markdown_selected.svg


+ 0 - 0
packages/toc/static/markdown_unselected.svg → packages/toc/style/img/markdown_unselected.svg


+ 0 - 0
packages/toc/static/menu_arrow.svg → packages/toc/style/img/menu_arrow.svg


+ 0 - 0
packages/toc/static/numbering.svg → packages/toc/style/img/numbering.svg


+ 0 - 0
packages/toc/static/rightarrow.svg → packages/toc/style/img/rightarrow.svg


+ 0 - 0
packages/toc/static/tag_hover.svg → packages/toc/style/img/tag_hover.svg


+ 0 - 0
packages/toc/static/tag_selected.svg → packages/toc/style/img/tag_selected.svg


+ 0 - 0
packages/toc/static/tag_unselected.svg → packages/toc/style/img/tag_unselected.svg