From edcb92d22302ed71bba8a5a2a81186e8a0ee3a25 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 27 Jan 2018 11:45:46 -0800 Subject: [PATCH] Updated to only add numbering to slugified heading anchors when absolutely neccessary --- app/components/Editor/components/Contents.js | 6 +++-- app/components/Editor/components/Heading.js | 17 ++----------- app/components/Editor/headingToSlug.js | 25 ++++++++++++++++---- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/app/components/Editor/components/Contents.js b/app/components/Editor/components/Contents.js index c09d04fb7..0215bb7fb 100644 --- a/app/components/Editor/components/Contents.js +++ b/app/components/Editor/components/Contents.js @@ -64,14 +64,16 @@ class Contents extends Component { } render() { + const { editor } = this.props; + // If there are one or less headings in the document no need for a minimap if (this.headings.size <= 1) return null; return ( - {this.headings.map((heading, index) => { - const slug = headingToSlug(heading, index); + {this.headings.map(heading => { + const slug = headingToSlug(editor.value.document, heading); const active = this.activeHeading === slug; return ( diff --git a/app/components/Editor/components/Heading.js b/app/components/Editor/components/Heading.js index cc710d52e..32f38d6b1 100644 --- a/app/components/Editor/components/Heading.js +++ b/app/components/Editor/components/Heading.js @@ -1,8 +1,7 @@ // @flow import React from 'react'; -import { Document, Block } from 'slate'; +import { Document } from 'slate'; import type { SlateNodeProps } from '../types'; -import { List } from 'immutable'; import styled from 'styled-components'; import headingToSlug from '../headingToSlug'; import Placeholder from './Placeholder'; @@ -13,15 +12,6 @@ type Props = SlateNodeProps & { placeholder: string, }; -function indexInDocument(document, heading) { - const headings = document.nodes.filter((node: Block) => { - if (!node.text) return false; - return node.type.match(/^heading/); - }); - - return headings.indexOf(heading); -} - function Heading(props: Props) { const { parent, @@ -37,10 +27,7 @@ function Heading(props: Props) { const parentIsDocument = parent instanceof Document; const firstHeading = parentIsDocument && parent.nodes.first() === node; const showPlaceholder = placeholder && firstHeading && !node.text; - const slugish = headingToSlug( - node, - indexInDocument(editor.value.document, node) - ); + const slugish = headingToSlug(editor.value.document, node); const showHash = readOnly && !!slugish; const Component = component; const emoji = editor.props.emoji || ''; diff --git a/app/components/Editor/headingToSlug.js b/app/components/Editor/headingToSlug.js index 4617127be..59f3fdbba 100644 --- a/app/components/Editor/headingToSlug.js +++ b/app/components/Editor/headingToSlug.js @@ -1,10 +1,25 @@ // @flow import { escape } from 'lodash'; -import { Node } from 'slate'; +import { Document, Block, Node } from 'slate'; import slug from 'slug'; -export default function headingToSlug(node: Node, index: number = 0) { - const slugified = escape(slug(node.text)); - if (index === 0) return slugified; - return `${index}-${slugified}`; +// finds the index of this heading in the document compared to other headings +// with the same slugified text +function indexOfType(document, heading) { + const slugified = escape(slug(heading.text)); + const headings = document.nodes.filter((node: Block) => { + if (!node.text) return false; + return node.type.match(/^heading/) && slugified === escape(slug(node.text)); + }); + + return headings.indexOf(heading); +} + +// calculates a unique slug for this heading based on it's text and position +// in the document that is as stable as possible +export default function headingToSlug(document: Document, node: Node) { + const slugified = escape(slug(node.text)); + const index = indexOfType(document, node); + if (index === 0) return slugified; + return `${slugified}-${index}`; }