mokuji.js 3.2.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/dist/index.d.ts +4 -12
- package/dist/mokuji.js +1 -1
- package/dist/mokuji.js.map +1 -1
- package/dist/mokuji.modern.js +1 -1
- package/dist/mokuji.modern.js.map +1 -1
- package/dist/mokuji.module.js +1 -1
- package/dist/mokuji.module.js.map +1 -1
- package/dist/mokuji.umd.js +1 -1
- package/dist/mokuji.umd.js.map +1 -1
- package/package.json +3 -5
- package/src/index.ts +132 -131
package/README.md
CHANGED
|
@@ -14,11 +14,13 @@ npm install --save mokuji.js
|
|
|
14
14
|
```javascript
|
|
15
15
|
import { Mokuji } from 'mokuji.js';
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
const textElement = document.querySelector('.text');
|
|
18
|
+
const mokujiList = Mokuji(textElement);
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
if (!mokujiList) return;
|
|
21
|
+
|
|
22
|
+
const listElement = document.querySelector('.list');
|
|
23
|
+
listElement?.appendChild(mokujiList);
|
|
22
24
|
```
|
|
23
25
|
|
|
24
26
|
## Options
|
package/dist/index.d.ts
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
|
+
declare type AnchorContainerTagNameProps = 'ul' | 'ol';
|
|
1
2
|
export declare type MokujiOption = {
|
|
2
3
|
anchorType?: boolean;
|
|
3
4
|
anchorLink?: boolean;
|
|
4
5
|
anchorLinkSymbol?: string;
|
|
5
6
|
anchorLinkBefore?: boolean;
|
|
6
7
|
anchorLinkClassName?: string;
|
|
7
|
-
anchorContainerTagName?:
|
|
8
|
+
anchorContainerTagName?: AnchorContainerTagNameProps;
|
|
8
9
|
};
|
|
9
|
-
export declare const
|
|
10
|
-
export
|
|
11
|
-
options: MokujiOption;
|
|
12
|
-
storeIds: string[];
|
|
13
|
-
constructor(element: HTMLElement | null, externalOptions: MokujiOption);
|
|
14
|
-
generateMokuji(headings: NodeListOf<HTMLHeadingElement>): HTMLUListElement | HTMLOListElement;
|
|
15
|
-
generateHierarchyList(headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement): void;
|
|
16
|
-
censorshipId(headings: NodeListOf<HTMLHeadingElement>, textContent: string | null): string;
|
|
17
|
-
generateAnchorText(text: string, type: boolean): string;
|
|
18
|
-
removeDuplicateIds(headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement): void;
|
|
19
|
-
}
|
|
10
|
+
export declare const Mokuji: (element: HTMLElement | null, externalOptions?: MokujiOption | undefined) => HTMLOListElement | undefined;
|
|
11
|
+
export {};
|
package/dist/mokuji.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e=function(e,n){for(;e;){if(e===n)return!0;e=e.parentNode}return!1},n=
|
|
1
|
+
var e=function(e,n){for(;e;){if(e===n)return!0;e=e.parentNode}return!1},n={anchorType:!0,anchorLink:!1,anchorLinkSymbol:"#",anchorLinkBefore:!0,anchorLinkClassName:"",anchorContainerTagName:"ol"},r=[],a=function(e,n){for(var a=n||"",t=1;t<=e.length;){var o=1===t?a:a+"_"+t;if(-1===r.indexOf(o)){r.push(a=o);break}t++}return a};exports.Mokuji=function(r,t){if(r){var o=Object.assign(n,t),i=function(e){return e.querySelectorAll("h1, h2, h3, h4, h5, h6")}(r),c=document.createElement(o.anchorContainerTagName||n.anchorContainerTagName);return function(n,r,t){for(var o=0,i=document.createElement("li"),c=document.createElement("a"),h=0;h<n.length;h++){var l=n[h],f=Number(l.tagName.substring(1));if(0!==o&&o<f){var u=document.createElement("ol");r.lastChild.appendChild(u),r=u}else if(0!==o&&o>f)for(var d=0;d<o-f;d++)e(r,r.parentNode)&&(r=r.parentNode.parentNode);var m=(g=t,C=void 0,C=(v=a(n,l.textContent),C=v.replace(/\s+/g,"_")).replace(/\&+/g,"").replace(/\&+/g,""),!0===g&&(C=function(e){return(e=encodeURIComponent(e)).replace(/\%+/g,".")}(C)),C);l.id=m;var s=c.cloneNode(!1);s.href="#"+m,s.textContent=l.textContent;var p=i.cloneNode(!1);p.appendChild(s),r.appendChild(p),o=f}var v,g,C}(i,c,!!o.anchorType),function(e,n){for(var r=n.getElementsByTagName("a"),a=function(n){var a=r[n].innerText,t=r[n].hash,o=Array.from(e).filter(function(e){return e.id===a});if(1===o.length)return"continue";var i=0;o.forEach(function(e){for(var n=e.id+"-"+i,a=0,o=Array.from(r);a<o.length;a++){var c=o[a];if(c.hash===t){c.href="#"+n;break}}e.id=n,i++})},t=0;t<r.length;t++)a(t)}(i,c),o.anchorLink&&function(e,n,r){if(n){var a=document.createElement("a");r.anchorLinkClassName&&a.classList.add(r.anchorLinkClassName),e.forEach(function(e){for(var t=e.id,o=0;o<n.length;o++){var i=n[o].hash;if(i.replace("#","")===t){var c=a.cloneNode(!1);c.setAttribute("href",i),r.anchorLinkSymbol&&(c.textContent=r.anchorLinkSymbol),r.anchorLinkBefore?e.insertBefore(c,e.firstChild):e.appendChild(c)}}})}}(i,c.querySelectorAll("a"),o),c}};
|
|
2
2
|
//# sourceMappingURL=mokuji.js.map
|
package/dist/mokuji.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mokuji.js","sources":["../src/dom.ts","../src/index.ts","../src/utils.ts"],"sourcesContent":["export const hasParentNode = (element: Node | null, parent: Node | null) => {\n while (element) {\n if (element === parent) {\n return true;\n }\n element = element.parentNode;\n }\n return false;\n};\n\nexport const reverseElement = (element: Node) => {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n return element;\n};\n\nexport const getHeadingsElement = (element: Element): NodeListOf<HTMLHeadingElement> => {\n return element.querySelectorAll(\"h1, h2, h3, h4, h5, h6\");\n};\n","import { hasParentNode, getHeadingsElement } from './dom';\nimport { replaceSpace2Underscore, convert2WikipediaStyleAnchor, getHeadingTagName2Number } from './utils';\n\nexport type MokujiOption = {\n anchorType?: boolean;\n anchorLink?: boolean;\n anchorLinkSymbol?: string;\n anchorLinkBefore?: boolean;\n anchorLinkClassName?: string;\n anchorContainerTagName?: 'ul' | 'ol';\n};\n\nexport const renderAnchorLink = (\n headings: NodeListOf<HTMLHeadingElement>,\n anchors: NodeListOf<HTMLAnchorElement> | undefined,\n options: MokujiOption,\n) => {\n if (!anchors) return;\n\n const a = document.createElement('a');\n\n if (options.anchorLinkClassName) {\n a.classList.add(options.anchorLinkClassName);\n }\n\n headings.forEach((heading) => {\n const { id } = heading;\n\n for (let i = 0; i < anchors.length; i++) {\n const { hash } = anchors[i];\n\n if (hash.replace('#', '') !== id) {\n continue;\n }\n\n // create anchor\n const anchor = a.cloneNode(false) as HTMLAnchorElement;\n anchor.setAttribute('href', hash);\n\n if (options.anchorLinkSymbol) {\n anchor.textContent = options.anchorLinkSymbol;\n }\n\n // insert anchor into headings\n if (options.anchorLinkBefore) {\n // before\n heading.insertBefore(anchor, heading.firstChild);\n } else {\n // after\n heading.appendChild(anchor);\n }\n }\n });\n};\n\nexport class Mokuji {\n options: MokujiOption = {\n anchorType: true,\n anchorLink: false,\n anchorLinkSymbol: '#',\n anchorLinkBefore: true,\n anchorLinkClassName: '',\n anchorContainerTagName: 'ol',\n };\n storeIds: string[] = [];\n\n constructor(element: HTMLElement | null, externalOptions: MokujiOption) {\n if (!element) {\n return;\n }\n\n // Merge the default options with the external options.\n this.options = Object.assign(\n // default options\n this.options,\n externalOptions,\n );\n\n const headings = getHeadingsElement(element);\n\n // mokuji start\n // generate mokuji list\n const mokuji = this.generateMokuji(headings);\n\n // setup anchor link\n if (this.options.anchorLink) {\n const anchors = mokuji.querySelectorAll('a');\n renderAnchorLink(headings, anchors, this.options);\n }\n\n // @ts-ignore\n return mokuji;\n }\n\n generateMokuji(headings: NodeListOf<HTMLHeadingElement>) {\n let elementContainer = document.createElement(this.options.anchorContainerTagName || 'ol');\n\n this.generateHierarchyList(headings, elementContainer);\n\n // remove duplicates by adding suffix\n this.removeDuplicateIds(headings, elementContainer);\n\n return elementContainer;\n }\n\n generateHierarchyList(headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement) {\n let number = 0;\n const elementListClone = document.createElement('li');\n const elementAnchorClone = document.createElement('a');\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const currentNumber = getHeadingTagName2Number(heading.tagName);\n\n // check list hierarchy\n if (number !== 0 && number < currentNumber) {\n // number of the heading is large (small as heading)\n const nextElementOListClone = document.createElement('ol');\n // @ts-ignore\n elementContainer.lastChild.appendChild(nextElementOListClone);\n elementContainer = nextElementOListClone;\n } else if (number !== 0 && number > currentNumber) {\n // number of heading is small (large as heading)\n for (let i = 0; i < number - currentNumber; i++) {\n if (hasParentNode(elementContainer, elementContainer.parentNode)) {\n // @ts-ignore\n elementContainer = elementContainer.parentNode.parentNode;\n }\n }\n }\n\n const textContent = this.censorshipId(headings, heading.textContent);\n\n // headingへidを付与\n const anchorText = this.generateAnchorText(textContent, !!this.options.anchorType);\n heading.id = anchorText;\n\n // add to wrapper\n const elementAnchor = elementAnchorClone.cloneNode(false) as HTMLAnchorElement;\n elementAnchor.href = `#${anchorText}`;\n elementAnchor.textContent = heading.textContent;\n const elementList = elementListClone.cloneNode(false);\n elementList.appendChild(elementAnchor);\n elementContainer.appendChild(elementList);\n\n // upadte current number\n number = currentNumber;\n }\n }\n\n censorshipId(headings: NodeListOf<HTMLHeadingElement>, textContent: string | null) {\n let id = textContent || '';\n let suffix_count = 1;\n\n // IDが重複していた場合はsuffixを付ける\n while (suffix_count <= headings.length) {\n const tmp_id = suffix_count === 1 ? id : `${id}_${suffix_count}`;\n\n if (this.storeIds.indexOf(tmp_id) === -1) {\n id = tmp_id;\n this.storeIds.push(id);\n break;\n }\n\n suffix_count++;\n }\n\n return id;\n }\n\n generateAnchorText(text: string, type: boolean) {\n // convert spaces to _\n let anchor = replaceSpace2Underscore(text);\n\n // remove &\n anchor = anchor.replace(/\\&+/g, '').replace(/\\&+/g, '');\n\n if (type === true) {\n anchor = convert2WikipediaStyleAnchor(anchor);\n }\n\n return anchor;\n }\n\n removeDuplicateIds(headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement) {\n const anchors = elementContainer.getElementsByTagName('a');\n\n for (let i = 0; i < anchors.length; i++) {\n const id = anchors[i].innerText;\n const hash = anchors[i].hash;\n const matchedHeadings = Array.from(headings).filter((heading) => heading.id === id);\n\n if (matchedHeadings.length === 1) {\n continue;\n }\n\n // duplicated id\n let count = 0;\n\n matchedHeadings.forEach((heading) => {\n const heading_id = `${heading.id}-${count}`;\n\n // search duplicate list\n for (const anchor of Array.from(anchors)) {\n if (anchor.hash === hash) {\n // update hash\n anchor.href = `#${heading_id}`;\n break;\n }\n }\n\n // update id\n heading.id = heading_id;\n count++;\n });\n }\n }\n}\n","export const replaceSpace2Underscore = (text: string) => {\n return text.replace(/\\s+/g, '_');\n};\n\nexport const convert2WikipediaStyleAnchor = (anchor: string) => {\n anchor = encodeURIComponent(anchor);\n anchor = anchor.replace(/\\%+/g, '.');\n\n return anchor;\n};\n\nexport const getHeadingTagName2Number = (tagName: string) => {\n return Number(tagName.substring(1));\n};\n"],"names":["hasParentNode","element","parent","parentNode","renderAnchorLink","headings","anchors","options","a","document","createElement","anchorLinkClassName","classList","add","forEach","heading","id","i","length","hash","replace","anchor","cloneNode","setAttribute","anchorLinkSymbol","textContent","anchorLinkBefore","insertBefore","firstChild","appendChild","externalOptions","anchorType","anchorLink","anchorContainerTagName","storeIds","this","Object","assign","querySelectorAll","getHeadingsElement","mokuji","generateMokuji","elementContainer","generateHierarchyList","removeDuplicateIds","number","elementListClone","elementAnchorClone","currentNumber","Number","tagName","substring","nextElementOListClone","lastChild","censorshipId","anchorText","generateAnchorText","elementAnchor","href","elementList","suffix_count","tmp_id","indexOf","push","text","type","replaceSpace2Underscore","encodeURIComponent","convert2WikipediaStyleAnchor","getElementsByTagName","innerText","matchedHeadings","Array","from","filter","count","heading_id"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mokuji.js","sources":["../src/dom.ts","../src/index.ts","../src/utils.ts"],"sourcesContent":["export const hasParentNode = (element: Node | null, parent: Node | null) => {\n while (element) {\n if (element === parent) {\n return true;\n }\n element = element.parentNode;\n }\n return false;\n};\n\nexport const reverseElement = (element: Node) => {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n return element;\n};\n\nexport const getHeadingsElement = (element: Element): NodeListOf<HTMLHeadingElement> => {\n return element.querySelectorAll(\"h1, h2, h3, h4, h5, h6\");\n};\n","import { hasParentNode, getHeadingsElement } from './dom';\nimport { replaceSpace2Underscore, convert2WikipediaStyleAnchor, getHeadingTagName2Number } from './utils';\n\ntype AnchorContainerTagNameProps = 'ul' | 'ol';\n\nexport type MokujiOption = {\n anchorType?: boolean;\n anchorLink?: boolean;\n anchorLinkSymbol?: string;\n anchorLinkBefore?: boolean;\n anchorLinkClassName?: string;\n anchorContainerTagName?: AnchorContainerTagNameProps;\n};\n\nconst defaultOptions = {\n anchorType: true,\n anchorLink: false,\n anchorLinkSymbol: '#',\n anchorLinkBefore: true,\n anchorLinkClassName: '',\n anchorContainerTagName: 'ol',\n} as const;\n\nconst storeIds: string[] = [];\n\nconst renderAnchorLink = (\n headings: NodeListOf<HTMLHeadingElement>,\n anchors: NodeListOf<HTMLAnchorElement> | undefined,\n options: MokujiOption,\n) => {\n if (!anchors) return;\n\n const a = document.createElement('a');\n\n if (options.anchorLinkClassName) {\n a.classList.add(options.anchorLinkClassName);\n }\n\n headings.forEach((heading) => {\n const { id } = heading;\n\n for (let i = 0; i < anchors.length; i++) {\n const { hash } = anchors[i];\n\n if (hash.replace('#', '') !== id) {\n continue;\n }\n\n // create anchor\n const anchor = a.cloneNode(false) as HTMLAnchorElement;\n anchor.setAttribute('href', hash);\n\n if (options.anchorLinkSymbol) {\n anchor.textContent = options.anchorLinkSymbol;\n }\n\n // insert anchor into headings\n if (options.anchorLinkBefore) {\n // before\n heading.insertBefore(anchor, heading.firstChild);\n } else {\n // after\n heading.appendChild(anchor);\n }\n }\n });\n};\n\nconst removeDuplicateIds = (headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement) => {\n const anchors = elementContainer.getElementsByTagName('a');\n\n for (let i = 0; i < anchors.length; i++) {\n const id = anchors[i].innerText;\n const hash = anchors[i].hash;\n const matchedHeadings = Array.from(headings).filter((heading) => heading.id === id);\n\n if (matchedHeadings.length === 1) {\n continue;\n }\n\n // duplicated id\n let count = 0;\n\n matchedHeadings.forEach((heading) => {\n const heading_id = `${heading.id}-${count}`;\n\n // search duplicate list\n for (const anchor of Array.from(anchors)) {\n if (anchor.hash === hash) {\n // update hash\n anchor.href = `#${heading_id}`;\n break;\n }\n }\n\n // update id\n heading.id = heading_id;\n count++;\n });\n }\n};\n\nconst censorshipId = (headings: NodeListOf<HTMLHeadingElement>, textContent: string | null) => {\n let id = textContent || '';\n let suffix_count = 1;\n\n // IDが重複していた場合はsuffixを付ける\n while (suffix_count <= headings.length) {\n const tmp_id = suffix_count === 1 ? id : `${id}_${suffix_count}`;\n\n if (storeIds.indexOf(tmp_id) === -1) {\n id = tmp_id;\n storeIds.push(id);\n break;\n }\n\n suffix_count++;\n }\n\n return id;\n};\n\nconst generateAnchorText = (text: string, type: boolean) => {\n // convert spaces to _\n let anchor = replaceSpace2Underscore(text);\n\n // remove &\n anchor = anchor.replace(/\\&+/g, '').replace(/\\&+/g, '');\n\n if (type === true) {\n anchor = convert2WikipediaStyleAnchor(anchor);\n }\n\n return anchor;\n};\n\nconst generateHierarchyList = (\n headings: NodeListOf<HTMLHeadingElement>,\n elementContainer: HTMLUListElement | HTMLOListElement,\n anchorType: boolean,\n) => {\n let number = 0;\n const elementListClone = document.createElement('li');\n const elementAnchorClone = document.createElement('a');\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const currentNumber = getHeadingTagName2Number(heading.tagName);\n\n // check list hierarchy\n if (number !== 0 && number < currentNumber) {\n // number of the heading is large (small as heading)\n const nextElementOListClone = document.createElement('ol');\n // @ts-ignore\n elementContainer.lastChild.appendChild(nextElementOListClone);\n elementContainer = nextElementOListClone;\n } else if (number !== 0 && number > currentNumber) {\n // number of heading is small (large as heading)\n for (let i = 0; i < number - currentNumber; i++) {\n if (hasParentNode(elementContainer, elementContainer.parentNode)) {\n // @ts-ignore\n elementContainer = elementContainer.parentNode.parentNode;\n }\n }\n }\n\n const textContent = censorshipId(headings, heading.textContent);\n\n // headingへidを付与\n const anchorText = generateAnchorText(textContent, anchorType);\n heading.id = anchorText;\n\n // add to wrapper\n const elementAnchor = elementAnchorClone.cloneNode(false) as HTMLAnchorElement;\n elementAnchor.href = `#${anchorText}`;\n elementAnchor.textContent = heading.textContent;\n const elementList = elementListClone.cloneNode(false) as HTMLLIElement;\n elementList.appendChild(elementAnchor);\n\n elementContainer.appendChild(elementList);\n\n // upadte current number\n number = currentNumber;\n }\n};\n\nexport const Mokuji = (element: HTMLElement | null, externalOptions?: MokujiOption): HTMLOListElement | undefined => {\n if (!element) {\n return;\n }\n\n // Merge the default options with the external options.\n const options = Object.assign(\n // default options\n defaultOptions,\n externalOptions,\n );\n\n const headings = getHeadingsElement(element);\n\n // mokuji start\n const elementContainer = document.createElement(\n options.anchorContainerTagName || defaultOptions.anchorContainerTagName,\n );\n\n // generate mokuji list\n generateHierarchyList(headings, elementContainer, !!options.anchorType);\n\n // remove duplicates by adding suffix\n removeDuplicateIds(headings, elementContainer);\n\n // setup anchor link\n if (options.anchorLink) {\n const anchors = elementContainer.querySelectorAll('a');\n renderAnchorLink(headings, anchors, options);\n }\n\n return elementContainer;\n};\n","export const replaceSpace2Underscore = (text: string) => {\n return text.replace(/\\s+/g, '_');\n};\n\nexport const convert2WikipediaStyleAnchor = (anchor: string) => {\n anchor = encodeURIComponent(anchor);\n anchor = anchor.replace(/\\%+/g, '.');\n\n return anchor;\n};\n\nexport const getHeadingTagName2Number = (tagName: string) => {\n return Number(tagName.substring(1));\n};\n"],"names":["hasParentNode","element","parent","parentNode","defaultOptions","anchorType","anchorLink","anchorLinkSymbol","anchorLinkBefore","anchorLinkClassName","anchorContainerTagName","storeIds","censorshipId","headings","textContent","id","suffix_count","length","tmp_id","indexOf","push","externalOptions","options","Object","assign","querySelectorAll","getHeadingsElement","elementContainer","document","createElement","number","elementListClone","elementAnchorClone","i","heading","currentNumber","Number","tagName","substring","nextElementOListClone","lastChild","appendChild","anchorText","type","anchor","text","replace","encodeURIComponent","convert2WikipediaStyleAnchor","elementAnchor","cloneNode","href","elementList","generateHierarchyList","anchors","getElementsByTagName","innerText","hash","matchedHeadings","Array","from","filter","count","forEach","heading_id","removeDuplicateIds","a","classList","add","setAttribute","insertBefore","firstChild","renderAnchorLink"],"mappings":"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"}
|
package/dist/mokuji.modern.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=(e,
|
|
1
|
+
const e=(e,n)=>{for(;e;){if(e===n)return!0;e=e.parentNode}return!1},n={anchorType:!0,anchorLink:!1,anchorLinkSymbol:"#",anchorLinkBefore:!0,anchorLinkClassName:"",anchorContainerTagName:"ol"},t=[],o=(e,n)=>{let o=n||"",r=1;for(;r<=e.length;){const e=1===r?o:`${o}_${r}`;if(-1===t.indexOf(e)){o=e,t.push(o);break}r++}return o},r=(e,n)=>{let t=(e=>e.replace(/\s+/g,"_"))(e);return t=t.replace(/\&+/g,"").replace(/\&+/g,""),!0===n&&(t=(e=>(e=encodeURIComponent(e)).replace(/\%+/g,"."))(t)),t},a=(t,a)=>{if(!t)return;const c=Object.assign(n,a),l=(e=>e.querySelectorAll("h1, h2, h3, h4, h5, h6"))(t),i=document.createElement(c.anchorContainerTagName||n.anchorContainerTagName);return((n,t,a)=>{let c=0;const l=document.createElement("li"),i=document.createElement("a");for(let h=0;h<n.length;h++){const s=n[h],d=Number(s.tagName.substring(1));if(0!==c&&c<d){const e=document.createElement("ol");t.lastChild.appendChild(e),t=e}else if(0!==c&&c>d)for(let n=0;n<c-d;n++)e(t,t.parentNode)&&(t=t.parentNode.parentNode);const f=o(n,s.textContent),m=r(f,a);s.id=m;const p=i.cloneNode(!1);p.href=`#${m}`,p.textContent=s.textContent;const u=l.cloneNode(!1);u.appendChild(p),t.appendChild(u),c=d}})(l,i,!!c.anchorType),((e,n)=>{const t=n.getElementsByTagName("a");for(let n=0;n<t.length;n++){const o=t[n].innerText,r=t[n].hash,a=Array.from(e).filter(e=>e.id===o);if(1===a.length)continue;let c=0;a.forEach(e=>{const n=`${e.id}-${c}`;for(const e of Array.from(t))if(e.hash===r){e.href=`#${n}`;break}e.id=n,c++})}})(l,i),c.anchorLink&&((e,n,t)=>{if(!n)return;const o=document.createElement("a");t.anchorLinkClassName&&o.classList.add(t.anchorLinkClassName),e.forEach(e=>{const{id:r}=e;for(let a=0;a<n.length;a++){const{hash:c}=n[a];if(c.replace("#","")!==r)continue;const l=o.cloneNode(!1);l.setAttribute("href",c),t.anchorLinkSymbol&&(l.textContent=t.anchorLinkSymbol),t.anchorLinkBefore?e.insertBefore(l,e.firstChild):e.appendChild(l)}})})(l,i.querySelectorAll("a"),c),i};export{a as Mokuji};
|
|
2
2
|
//# sourceMappingURL=mokuji.modern.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mokuji.modern.js","sources":["../src/dom.ts","../src/index.ts","../src/utils.ts"],"sourcesContent":["export const hasParentNode = (element: Node | null, parent: Node | null) => {\n while (element) {\n if (element === parent) {\n return true;\n }\n element = element.parentNode;\n }\n return false;\n};\n\nexport const reverseElement = (element: Node) => {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n return element;\n};\n\nexport const getHeadingsElement = (element: Element): NodeListOf<HTMLHeadingElement> => {\n return element.querySelectorAll(\"h1, h2, h3, h4, h5, h6\");\n};\n","import { hasParentNode, getHeadingsElement } from './dom';\nimport { replaceSpace2Underscore, convert2WikipediaStyleAnchor, getHeadingTagName2Number } from './utils';\n\nexport type MokujiOption = {\n anchorType?: boolean;\n anchorLink?: boolean;\n anchorLinkSymbol?: string;\n anchorLinkBefore?: boolean;\n anchorLinkClassName?: string;\n anchorContainerTagName?: 'ul' | 'ol';\n};\n\nexport const renderAnchorLink = (\n headings: NodeListOf<HTMLHeadingElement>,\n anchors: NodeListOf<HTMLAnchorElement> | undefined,\n options: MokujiOption,\n) => {\n if (!anchors) return;\n\n const a = document.createElement('a');\n\n if (options.anchorLinkClassName) {\n a.classList.add(options.anchorLinkClassName);\n }\n\n headings.forEach((heading) => {\n const { id } = heading;\n\n for (let i = 0; i < anchors.length; i++) {\n const { hash } = anchors[i];\n\n if (hash.replace('#', '') !== id) {\n continue;\n }\n\n // create anchor\n const anchor = a.cloneNode(false) as HTMLAnchorElement;\n anchor.setAttribute('href', hash);\n\n if (options.anchorLinkSymbol) {\n anchor.textContent = options.anchorLinkSymbol;\n }\n\n // insert anchor into headings\n if (options.anchorLinkBefore) {\n // before\n heading.insertBefore(anchor, heading.firstChild);\n } else {\n // after\n heading.appendChild(anchor);\n }\n }\n });\n};\n\nexport class Mokuji {\n options: MokujiOption = {\n anchorType: true,\n anchorLink: false,\n anchorLinkSymbol: '#',\n anchorLinkBefore: true,\n anchorLinkClassName: '',\n anchorContainerTagName: 'ol',\n };\n storeIds: string[] = [];\n\n constructor(element: HTMLElement | null, externalOptions: MokujiOption) {\n if (!element) {\n return;\n }\n\n // Merge the default options with the external options.\n this.options = Object.assign(\n // default options\n this.options,\n externalOptions,\n );\n\n const headings = getHeadingsElement(element);\n\n // mokuji start\n // generate mokuji list\n const mokuji = this.generateMokuji(headings);\n\n // setup anchor link\n if (this.options.anchorLink) {\n const anchors = mokuji.querySelectorAll('a');\n renderAnchorLink(headings, anchors, this.options);\n }\n\n // @ts-ignore\n return mokuji;\n }\n\n generateMokuji(headings: NodeListOf<HTMLHeadingElement>) {\n let elementContainer = document.createElement(this.options.anchorContainerTagName || 'ol');\n\n this.generateHierarchyList(headings, elementContainer);\n\n // remove duplicates by adding suffix\n this.removeDuplicateIds(headings, elementContainer);\n\n return elementContainer;\n }\n\n generateHierarchyList(headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement) {\n let number = 0;\n const elementListClone = document.createElement('li');\n const elementAnchorClone = document.createElement('a');\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const currentNumber = getHeadingTagName2Number(heading.tagName);\n\n // check list hierarchy\n if (number !== 0 && number < currentNumber) {\n // number of the heading is large (small as heading)\n const nextElementOListClone = document.createElement('ol');\n // @ts-ignore\n elementContainer.lastChild.appendChild(nextElementOListClone);\n elementContainer = nextElementOListClone;\n } else if (number !== 0 && number > currentNumber) {\n // number of heading is small (large as heading)\n for (let i = 0; i < number - currentNumber; i++) {\n if (hasParentNode(elementContainer, elementContainer.parentNode)) {\n // @ts-ignore\n elementContainer = elementContainer.parentNode.parentNode;\n }\n }\n }\n\n const textContent = this.censorshipId(headings, heading.textContent);\n\n // headingへidを付与\n const anchorText = this.generateAnchorText(textContent, !!this.options.anchorType);\n heading.id = anchorText;\n\n // add to wrapper\n const elementAnchor = elementAnchorClone.cloneNode(false) as HTMLAnchorElement;\n elementAnchor.href = `#${anchorText}`;\n elementAnchor.textContent = heading.textContent;\n const elementList = elementListClone.cloneNode(false);\n elementList.appendChild(elementAnchor);\n elementContainer.appendChild(elementList);\n\n // upadte current number\n number = currentNumber;\n }\n }\n\n censorshipId(headings: NodeListOf<HTMLHeadingElement>, textContent: string | null) {\n let id = textContent || '';\n let suffix_count = 1;\n\n // IDが重複していた場合はsuffixを付ける\n while (suffix_count <= headings.length) {\n const tmp_id = suffix_count === 1 ? id : `${id}_${suffix_count}`;\n\n if (this.storeIds.indexOf(tmp_id) === -1) {\n id = tmp_id;\n this.storeIds.push(id);\n break;\n }\n\n suffix_count++;\n }\n\n return id;\n }\n\n generateAnchorText(text: string, type: boolean) {\n // convert spaces to _\n let anchor = replaceSpace2Underscore(text);\n\n // remove &\n anchor = anchor.replace(/\\&+/g, '').replace(/\\&+/g, '');\n\n if (type === true) {\n anchor = convert2WikipediaStyleAnchor(anchor);\n }\n\n return anchor;\n }\n\n removeDuplicateIds(headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement) {\n const anchors = elementContainer.getElementsByTagName('a');\n\n for (let i = 0; i < anchors.length; i++) {\n const id = anchors[i].innerText;\n const hash = anchors[i].hash;\n const matchedHeadings = Array.from(headings).filter((heading) => heading.id === id);\n\n if (matchedHeadings.length === 1) {\n continue;\n }\n\n // duplicated id\n let count = 0;\n\n matchedHeadings.forEach((heading) => {\n const heading_id = `${heading.id}-${count}`;\n\n // search duplicate list\n for (const anchor of Array.from(anchors)) {\n if (anchor.hash === hash) {\n // update hash\n anchor.href = `#${heading_id}`;\n break;\n }\n }\n\n // update id\n heading.id = heading_id;\n count++;\n });\n }\n }\n}\n","export const replaceSpace2Underscore = (text: string) => {\n return text.replace(/\\s+/g, '_');\n};\n\nexport const convert2WikipediaStyleAnchor = (anchor: string) => {\n anchor = encodeURIComponent(anchor);\n anchor = anchor.replace(/\\%+/g, '.');\n\n return anchor;\n};\n\nexport const getHeadingTagName2Number = (tagName: string) => {\n return Number(tagName.substring(1));\n};\n"],"names":["hasParentNode","element","parent","parentNode","renderAnchorLink","headings","anchors","options","a","document","createElement","anchorLinkClassName","classList","add","forEach","heading","id","i","length","hash","replace","anchor","cloneNode","setAttribute","anchorLinkSymbol","textContent","anchorLinkBefore","insertBefore","firstChild","appendChild","Mokuji","constructor","externalOptions","anchorType","anchorLink","anchorContainerTagName","storeIds","this","Object","assign","querySelectorAll","getHeadingsElement","mokuji","generateMokuji","elementContainer","generateHierarchyList","removeDuplicateIds","number","elementListClone","elementAnchorClone","currentNumber","Number","tagName","substring","nextElementOListClone","lastChild","censorshipId","anchorText","generateAnchorText","elementAnchor","href","elementList","suffix_count","tmp_id","indexOf","push","text","type","replaceSpace2Underscore","encodeURIComponent","convert2WikipediaStyleAnchor","getElementsByTagName","innerText","matchedHeadings","Array","from","filter","count","heading_id"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mokuji.modern.js","sources":["../src/dom.ts","../src/index.ts","../src/utils.ts"],"sourcesContent":["export const hasParentNode = (element: Node | null, parent: Node | null) => {\n while (element) {\n if (element === parent) {\n return true;\n }\n element = element.parentNode;\n }\n return false;\n};\n\nexport const reverseElement = (element: Node) => {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n return element;\n};\n\nexport const getHeadingsElement = (element: Element): NodeListOf<HTMLHeadingElement> => {\n return element.querySelectorAll(\"h1, h2, h3, h4, h5, h6\");\n};\n","import { hasParentNode, getHeadingsElement } from './dom';\nimport { replaceSpace2Underscore, convert2WikipediaStyleAnchor, getHeadingTagName2Number } from './utils';\n\ntype AnchorContainerTagNameProps = 'ul' | 'ol';\n\nexport type MokujiOption = {\n anchorType?: boolean;\n anchorLink?: boolean;\n anchorLinkSymbol?: string;\n anchorLinkBefore?: boolean;\n anchorLinkClassName?: string;\n anchorContainerTagName?: AnchorContainerTagNameProps;\n};\n\nconst defaultOptions = {\n anchorType: true,\n anchorLink: false,\n anchorLinkSymbol: '#',\n anchorLinkBefore: true,\n anchorLinkClassName: '',\n anchorContainerTagName: 'ol',\n} as const;\n\nconst storeIds: string[] = [];\n\nconst renderAnchorLink = (\n headings: NodeListOf<HTMLHeadingElement>,\n anchors: NodeListOf<HTMLAnchorElement> | undefined,\n options: MokujiOption,\n) => {\n if (!anchors) return;\n\n const a = document.createElement('a');\n\n if (options.anchorLinkClassName) {\n a.classList.add(options.anchorLinkClassName);\n }\n\n headings.forEach((heading) => {\n const { id } = heading;\n\n for (let i = 0; i < anchors.length; i++) {\n const { hash } = anchors[i];\n\n if (hash.replace('#', '') !== id) {\n continue;\n }\n\n // create anchor\n const anchor = a.cloneNode(false) as HTMLAnchorElement;\n anchor.setAttribute('href', hash);\n\n if (options.anchorLinkSymbol) {\n anchor.textContent = options.anchorLinkSymbol;\n }\n\n // insert anchor into headings\n if (options.anchorLinkBefore) {\n // before\n heading.insertBefore(anchor, heading.firstChild);\n } else {\n // after\n heading.appendChild(anchor);\n }\n }\n });\n};\n\nconst removeDuplicateIds = (headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement) => {\n const anchors = elementContainer.getElementsByTagName('a');\n\n for (let i = 0; i < anchors.length; i++) {\n const id = anchors[i].innerText;\n const hash = anchors[i].hash;\n const matchedHeadings = Array.from(headings).filter((heading) => heading.id === id);\n\n if (matchedHeadings.length === 1) {\n continue;\n }\n\n // duplicated id\n let count = 0;\n\n matchedHeadings.forEach((heading) => {\n const heading_id = `${heading.id}-${count}`;\n\n // search duplicate list\n for (const anchor of Array.from(anchors)) {\n if (anchor.hash === hash) {\n // update hash\n anchor.href = `#${heading_id}`;\n break;\n }\n }\n\n // update id\n heading.id = heading_id;\n count++;\n });\n }\n};\n\nconst censorshipId = (headings: NodeListOf<HTMLHeadingElement>, textContent: string | null) => {\n let id = textContent || '';\n let suffix_count = 1;\n\n // IDが重複していた場合はsuffixを付ける\n while (suffix_count <= headings.length) {\n const tmp_id = suffix_count === 1 ? id : `${id}_${suffix_count}`;\n\n if (storeIds.indexOf(tmp_id) === -1) {\n id = tmp_id;\n storeIds.push(id);\n break;\n }\n\n suffix_count++;\n }\n\n return id;\n};\n\nconst generateAnchorText = (text: string, type: boolean) => {\n // convert spaces to _\n let anchor = replaceSpace2Underscore(text);\n\n // remove &\n anchor = anchor.replace(/\\&+/g, '').replace(/\\&+/g, '');\n\n if (type === true) {\n anchor = convert2WikipediaStyleAnchor(anchor);\n }\n\n return anchor;\n};\n\nconst generateHierarchyList = (\n headings: NodeListOf<HTMLHeadingElement>,\n elementContainer: HTMLUListElement | HTMLOListElement,\n anchorType: boolean,\n) => {\n let number = 0;\n const elementListClone = document.createElement('li');\n const elementAnchorClone = document.createElement('a');\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const currentNumber = getHeadingTagName2Number(heading.tagName);\n\n // check list hierarchy\n if (number !== 0 && number < currentNumber) {\n // number of the heading is large (small as heading)\n const nextElementOListClone = document.createElement('ol');\n // @ts-ignore\n elementContainer.lastChild.appendChild(nextElementOListClone);\n elementContainer = nextElementOListClone;\n } else if (number !== 0 && number > currentNumber) {\n // number of heading is small (large as heading)\n for (let i = 0; i < number - currentNumber; i++) {\n if (hasParentNode(elementContainer, elementContainer.parentNode)) {\n // @ts-ignore\n elementContainer = elementContainer.parentNode.parentNode;\n }\n }\n }\n\n const textContent = censorshipId(headings, heading.textContent);\n\n // headingへidを付与\n const anchorText = generateAnchorText(textContent, anchorType);\n heading.id = anchorText;\n\n // add to wrapper\n const elementAnchor = elementAnchorClone.cloneNode(false) as HTMLAnchorElement;\n elementAnchor.href = `#${anchorText}`;\n elementAnchor.textContent = heading.textContent;\n const elementList = elementListClone.cloneNode(false) as HTMLLIElement;\n elementList.appendChild(elementAnchor);\n\n elementContainer.appendChild(elementList);\n\n // upadte current number\n number = currentNumber;\n }\n};\n\nexport const Mokuji = (element: HTMLElement | null, externalOptions?: MokujiOption): HTMLOListElement | undefined => {\n if (!element) {\n return;\n }\n\n // Merge the default options with the external options.\n const options = Object.assign(\n // default options\n defaultOptions,\n externalOptions,\n );\n\n const headings = getHeadingsElement(element);\n\n // mokuji start\n const elementContainer = document.createElement(\n options.anchorContainerTagName || defaultOptions.anchorContainerTagName,\n );\n\n // generate mokuji list\n generateHierarchyList(headings, elementContainer, !!options.anchorType);\n\n // remove duplicates by adding suffix\n removeDuplicateIds(headings, elementContainer);\n\n // setup anchor link\n if (options.anchorLink) {\n const anchors = elementContainer.querySelectorAll('a');\n renderAnchorLink(headings, anchors, options);\n }\n\n return elementContainer;\n};\n","export const replaceSpace2Underscore = (text: string) => {\n return text.replace(/\\s+/g, '_');\n};\n\nexport const convert2WikipediaStyleAnchor = (anchor: string) => {\n anchor = encodeURIComponent(anchor);\n anchor = anchor.replace(/\\%+/g, '.');\n\n return anchor;\n};\n\nexport const getHeadingTagName2Number = (tagName: string) => {\n return Number(tagName.substring(1));\n};\n"],"names":["hasParentNode","element","parent","parentNode","defaultOptions","anchorType","anchorLink","anchorLinkSymbol","anchorLinkBefore","anchorLinkClassName","anchorContainerTagName","storeIds","censorshipId","headings","textContent","id","suffix_count","length","tmp_id","indexOf","push","generateAnchorText","text","type","anchor","replace","replaceSpace2Underscore","encodeURIComponent","convert2WikipediaStyleAnchor","Mokuji","externalOptions","options","Object","assign","querySelectorAll","getHeadingsElement","elementContainer","document","createElement","number","elementListClone","elementAnchorClone","i","heading","currentNumber","Number","tagName","substring","nextElementOListClone","lastChild","appendChild","anchorText","elementAnchor","cloneNode","href","elementList","generateHierarchyList","anchors","getElementsByTagName","innerText","hash","matchedHeadings","Array","from","filter","count","forEach","heading_id","removeDuplicateIds","a","classList","add","setAttribute","insertBefore","firstChild","renderAnchorLink"],"mappings":"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"}
|
package/dist/mokuji.module.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e=function(e,n){for(;e;){if(e===n)return!0;e=e.parentNode}return!1},n=
|
|
1
|
+
var e=function(e,n){for(;e;){if(e===n)return!0;e=e.parentNode}return!1},n={anchorType:!0,anchorLink:!1,anchorLinkSymbol:"#",anchorLinkBefore:!0,anchorLinkClassName:"",anchorContainerTagName:"ol"},r=[],a=function(e,n){for(var a=n||"",t=1;t<=e.length;){var o=1===t?a:a+"_"+t;if(-1===r.indexOf(o)){r.push(a=o);break}t++}return a},t=function(r,t){if(r){var o=Object.assign(n,t),i=function(e){return e.querySelectorAll("h1, h2, h3, h4, h5, h6")}(r),c=document.createElement(o.anchorContainerTagName||n.anchorContainerTagName);return function(n,r,t){for(var o=0,i=document.createElement("li"),c=document.createElement("a"),h=0;h<n.length;h++){var l=n[h],f=Number(l.tagName.substring(1));if(0!==o&&o<f){var d=document.createElement("ol");r.lastChild.appendChild(d),r=d}else if(0!==o&&o>f)for(var u=0;u<o-f;u++)e(r,r.parentNode)&&(r=r.parentNode.parentNode);var m=(g=t,C=void 0,C=(v=a(n,l.textContent),C=v.replace(/\s+/g,"_")).replace(/\&+/g,"").replace(/\&+/g,""),!0===g&&(C=function(e){return(e=encodeURIComponent(e)).replace(/\%+/g,".")}(C)),C);l.id=m;var s=c.cloneNode(!1);s.href="#"+m,s.textContent=l.textContent;var p=i.cloneNode(!1);p.appendChild(s),r.appendChild(p),o=f}var v,g,C}(i,c,!!o.anchorType),function(e,n){for(var r=n.getElementsByTagName("a"),a=function(n){var a=r[n].innerText,t=r[n].hash,o=Array.from(e).filter(function(e){return e.id===a});if(1===o.length)return"continue";var i=0;o.forEach(function(e){for(var n=e.id+"-"+i,a=0,o=Array.from(r);a<o.length;a++){var c=o[a];if(c.hash===t){c.href="#"+n;break}}e.id=n,i++})},t=0;t<r.length;t++)a(t)}(i,c),o.anchorLink&&function(e,n,r){if(n){var a=document.createElement("a");r.anchorLinkClassName&&a.classList.add(r.anchorLinkClassName),e.forEach(function(e){for(var t=e.id,o=0;o<n.length;o++){var i=n[o].hash;if(i.replace("#","")===t){var c=a.cloneNode(!1);c.setAttribute("href",i),r.anchorLinkSymbol&&(c.textContent=r.anchorLinkSymbol),r.anchorLinkBefore?e.insertBefore(c,e.firstChild):e.appendChild(c)}}})}}(i,c.querySelectorAll("a"),o),c}};export{t as Mokuji};
|
|
2
2
|
//# sourceMappingURL=mokuji.module.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mokuji.module.js","sources":["../src/dom.ts","../src/index.ts","../src/utils.ts"],"sourcesContent":["export const hasParentNode = (element: Node | null, parent: Node | null) => {\n while (element) {\n if (element === parent) {\n return true;\n }\n element = element.parentNode;\n }\n return false;\n};\n\nexport const reverseElement = (element: Node) => {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n return element;\n};\n\nexport const getHeadingsElement = (element: Element): NodeListOf<HTMLHeadingElement> => {\n return element.querySelectorAll(\"h1, h2, h3, h4, h5, h6\");\n};\n","import { hasParentNode, getHeadingsElement } from './dom';\nimport { replaceSpace2Underscore, convert2WikipediaStyleAnchor, getHeadingTagName2Number } from './utils';\n\nexport type MokujiOption = {\n anchorType?: boolean;\n anchorLink?: boolean;\n anchorLinkSymbol?: string;\n anchorLinkBefore?: boolean;\n anchorLinkClassName?: string;\n anchorContainerTagName?: 'ul' | 'ol';\n};\n\nexport const renderAnchorLink = (\n headings: NodeListOf<HTMLHeadingElement>,\n anchors: NodeListOf<HTMLAnchorElement> | undefined,\n options: MokujiOption,\n) => {\n if (!anchors) return;\n\n const a = document.createElement('a');\n\n if (options.anchorLinkClassName) {\n a.classList.add(options.anchorLinkClassName);\n }\n\n headings.forEach((heading) => {\n const { id } = heading;\n\n for (let i = 0; i < anchors.length; i++) {\n const { hash } = anchors[i];\n\n if (hash.replace('#', '') !== id) {\n continue;\n }\n\n // create anchor\n const anchor = a.cloneNode(false) as HTMLAnchorElement;\n anchor.setAttribute('href', hash);\n\n if (options.anchorLinkSymbol) {\n anchor.textContent = options.anchorLinkSymbol;\n }\n\n // insert anchor into headings\n if (options.anchorLinkBefore) {\n // before\n heading.insertBefore(anchor, heading.firstChild);\n } else {\n // after\n heading.appendChild(anchor);\n }\n }\n });\n};\n\nexport class Mokuji {\n options: MokujiOption = {\n anchorType: true,\n anchorLink: false,\n anchorLinkSymbol: '#',\n anchorLinkBefore: true,\n anchorLinkClassName: '',\n anchorContainerTagName: 'ol',\n };\n storeIds: string[] = [];\n\n constructor(element: HTMLElement | null, externalOptions: MokujiOption) {\n if (!element) {\n return;\n }\n\n // Merge the default options with the external options.\n this.options = Object.assign(\n // default options\n this.options,\n externalOptions,\n );\n\n const headings = getHeadingsElement(element);\n\n // mokuji start\n // generate mokuji list\n const mokuji = this.generateMokuji(headings);\n\n // setup anchor link\n if (this.options.anchorLink) {\n const anchors = mokuji.querySelectorAll('a');\n renderAnchorLink(headings, anchors, this.options);\n }\n\n // @ts-ignore\n return mokuji;\n }\n\n generateMokuji(headings: NodeListOf<HTMLHeadingElement>) {\n let elementContainer = document.createElement(this.options.anchorContainerTagName || 'ol');\n\n this.generateHierarchyList(headings, elementContainer);\n\n // remove duplicates by adding suffix\n this.removeDuplicateIds(headings, elementContainer);\n\n return elementContainer;\n }\n\n generateHierarchyList(headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement) {\n let number = 0;\n const elementListClone = document.createElement('li');\n const elementAnchorClone = document.createElement('a');\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const currentNumber = getHeadingTagName2Number(heading.tagName);\n\n // check list hierarchy\n if (number !== 0 && number < currentNumber) {\n // number of the heading is large (small as heading)\n const nextElementOListClone = document.createElement('ol');\n // @ts-ignore\n elementContainer.lastChild.appendChild(nextElementOListClone);\n elementContainer = nextElementOListClone;\n } else if (number !== 0 && number > currentNumber) {\n // number of heading is small (large as heading)\n for (let i = 0; i < number - currentNumber; i++) {\n if (hasParentNode(elementContainer, elementContainer.parentNode)) {\n // @ts-ignore\n elementContainer = elementContainer.parentNode.parentNode;\n }\n }\n }\n\n const textContent = this.censorshipId(headings, heading.textContent);\n\n // headingへidを付与\n const anchorText = this.generateAnchorText(textContent, !!this.options.anchorType);\n heading.id = anchorText;\n\n // add to wrapper\n const elementAnchor = elementAnchorClone.cloneNode(false) as HTMLAnchorElement;\n elementAnchor.href = `#${anchorText}`;\n elementAnchor.textContent = heading.textContent;\n const elementList = elementListClone.cloneNode(false);\n elementList.appendChild(elementAnchor);\n elementContainer.appendChild(elementList);\n\n // upadte current number\n number = currentNumber;\n }\n }\n\n censorshipId(headings: NodeListOf<HTMLHeadingElement>, textContent: string | null) {\n let id = textContent || '';\n let suffix_count = 1;\n\n // IDが重複していた場合はsuffixを付ける\n while (suffix_count <= headings.length) {\n const tmp_id = suffix_count === 1 ? id : `${id}_${suffix_count}`;\n\n if (this.storeIds.indexOf(tmp_id) === -1) {\n id = tmp_id;\n this.storeIds.push(id);\n break;\n }\n\n suffix_count++;\n }\n\n return id;\n }\n\n generateAnchorText(text: string, type: boolean) {\n // convert spaces to _\n let anchor = replaceSpace2Underscore(text);\n\n // remove &\n anchor = anchor.replace(/\\&+/g, '').replace(/\\&+/g, '');\n\n if (type === true) {\n anchor = convert2WikipediaStyleAnchor(anchor);\n }\n\n return anchor;\n }\n\n removeDuplicateIds(headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement) {\n const anchors = elementContainer.getElementsByTagName('a');\n\n for (let i = 0; i < anchors.length; i++) {\n const id = anchors[i].innerText;\n const hash = anchors[i].hash;\n const matchedHeadings = Array.from(headings).filter((heading) => heading.id === id);\n\n if (matchedHeadings.length === 1) {\n continue;\n }\n\n // duplicated id\n let count = 0;\n\n matchedHeadings.forEach((heading) => {\n const heading_id = `${heading.id}-${count}`;\n\n // search duplicate list\n for (const anchor of Array.from(anchors)) {\n if (anchor.hash === hash) {\n // update hash\n anchor.href = `#${heading_id}`;\n break;\n }\n }\n\n // update id\n heading.id = heading_id;\n count++;\n });\n }\n }\n}\n","export const replaceSpace2Underscore = (text: string) => {\n return text.replace(/\\s+/g, '_');\n};\n\nexport const convert2WikipediaStyleAnchor = (anchor: string) => {\n anchor = encodeURIComponent(anchor);\n anchor = anchor.replace(/\\%+/g, '.');\n\n return anchor;\n};\n\nexport const getHeadingTagName2Number = (tagName: string) => {\n return Number(tagName.substring(1));\n};\n"],"names":["hasParentNode","element","parent","parentNode","renderAnchorLink","headings","anchors","options","a","document","createElement","anchorLinkClassName","classList","add","forEach","heading","id","i","length","hash","replace","anchor","cloneNode","setAttribute","anchorLinkSymbol","textContent","anchorLinkBefore","insertBefore","firstChild","appendChild","Mokuji","externalOptions","anchorType","anchorLink","anchorContainerTagName","storeIds","this","Object","assign","querySelectorAll","getHeadingsElement","mokuji","generateMokuji","elementContainer","generateHierarchyList","removeDuplicateIds","number","elementListClone","elementAnchorClone","currentNumber","Number","tagName","substring","nextElementOListClone","lastChild","censorshipId","anchorText","generateAnchorText","elementAnchor","href","elementList","suffix_count","tmp_id","indexOf","push","text","type","replaceSpace2Underscore","encodeURIComponent","convert2WikipediaStyleAnchor","getElementsByTagName","innerText","matchedHeadings","Array","from","filter","count","heading_id"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mokuji.module.js","sources":["../src/dom.ts","../src/index.ts","../src/utils.ts"],"sourcesContent":["export const hasParentNode = (element: Node | null, parent: Node | null) => {\n while (element) {\n if (element === parent) {\n return true;\n }\n element = element.parentNode;\n }\n return false;\n};\n\nexport const reverseElement = (element: Node) => {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n return element;\n};\n\nexport const getHeadingsElement = (element: Element): NodeListOf<HTMLHeadingElement> => {\n return element.querySelectorAll(\"h1, h2, h3, h4, h5, h6\");\n};\n","import { hasParentNode, getHeadingsElement } from './dom';\nimport { replaceSpace2Underscore, convert2WikipediaStyleAnchor, getHeadingTagName2Number } from './utils';\n\ntype AnchorContainerTagNameProps = 'ul' | 'ol';\n\nexport type MokujiOption = {\n anchorType?: boolean;\n anchorLink?: boolean;\n anchorLinkSymbol?: string;\n anchorLinkBefore?: boolean;\n anchorLinkClassName?: string;\n anchorContainerTagName?: AnchorContainerTagNameProps;\n};\n\nconst defaultOptions = {\n anchorType: true,\n anchorLink: false,\n anchorLinkSymbol: '#',\n anchorLinkBefore: true,\n anchorLinkClassName: '',\n anchorContainerTagName: 'ol',\n} as const;\n\nconst storeIds: string[] = [];\n\nconst renderAnchorLink = (\n headings: NodeListOf<HTMLHeadingElement>,\n anchors: NodeListOf<HTMLAnchorElement> | undefined,\n options: MokujiOption,\n) => {\n if (!anchors) return;\n\n const a = document.createElement('a');\n\n if (options.anchorLinkClassName) {\n a.classList.add(options.anchorLinkClassName);\n }\n\n headings.forEach((heading) => {\n const { id } = heading;\n\n for (let i = 0; i < anchors.length; i++) {\n const { hash } = anchors[i];\n\n if (hash.replace('#', '') !== id) {\n continue;\n }\n\n // create anchor\n const anchor = a.cloneNode(false) as HTMLAnchorElement;\n anchor.setAttribute('href', hash);\n\n if (options.anchorLinkSymbol) {\n anchor.textContent = options.anchorLinkSymbol;\n }\n\n // insert anchor into headings\n if (options.anchorLinkBefore) {\n // before\n heading.insertBefore(anchor, heading.firstChild);\n } else {\n // after\n heading.appendChild(anchor);\n }\n }\n });\n};\n\nconst removeDuplicateIds = (headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement) => {\n const anchors = elementContainer.getElementsByTagName('a');\n\n for (let i = 0; i < anchors.length; i++) {\n const id = anchors[i].innerText;\n const hash = anchors[i].hash;\n const matchedHeadings = Array.from(headings).filter((heading) => heading.id === id);\n\n if (matchedHeadings.length === 1) {\n continue;\n }\n\n // duplicated id\n let count = 0;\n\n matchedHeadings.forEach((heading) => {\n const heading_id = `${heading.id}-${count}`;\n\n // search duplicate list\n for (const anchor of Array.from(anchors)) {\n if (anchor.hash === hash) {\n // update hash\n anchor.href = `#${heading_id}`;\n break;\n }\n }\n\n // update id\n heading.id = heading_id;\n count++;\n });\n }\n};\n\nconst censorshipId = (headings: NodeListOf<HTMLHeadingElement>, textContent: string | null) => {\n let id = textContent || '';\n let suffix_count = 1;\n\n // IDが重複していた場合はsuffixを付ける\n while (suffix_count <= headings.length) {\n const tmp_id = suffix_count === 1 ? id : `${id}_${suffix_count}`;\n\n if (storeIds.indexOf(tmp_id) === -1) {\n id = tmp_id;\n storeIds.push(id);\n break;\n }\n\n suffix_count++;\n }\n\n return id;\n};\n\nconst generateAnchorText = (text: string, type: boolean) => {\n // convert spaces to _\n let anchor = replaceSpace2Underscore(text);\n\n // remove &\n anchor = anchor.replace(/\\&+/g, '').replace(/\\&+/g, '');\n\n if (type === true) {\n anchor = convert2WikipediaStyleAnchor(anchor);\n }\n\n return anchor;\n};\n\nconst generateHierarchyList = (\n headings: NodeListOf<HTMLHeadingElement>,\n elementContainer: HTMLUListElement | HTMLOListElement,\n anchorType: boolean,\n) => {\n let number = 0;\n const elementListClone = document.createElement('li');\n const elementAnchorClone = document.createElement('a');\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const currentNumber = getHeadingTagName2Number(heading.tagName);\n\n // check list hierarchy\n if (number !== 0 && number < currentNumber) {\n // number of the heading is large (small as heading)\n const nextElementOListClone = document.createElement('ol');\n // @ts-ignore\n elementContainer.lastChild.appendChild(nextElementOListClone);\n elementContainer = nextElementOListClone;\n } else if (number !== 0 && number > currentNumber) {\n // number of heading is small (large as heading)\n for (let i = 0; i < number - currentNumber; i++) {\n if (hasParentNode(elementContainer, elementContainer.parentNode)) {\n // @ts-ignore\n elementContainer = elementContainer.parentNode.parentNode;\n }\n }\n }\n\n const textContent = censorshipId(headings, heading.textContent);\n\n // headingへidを付与\n const anchorText = generateAnchorText(textContent, anchorType);\n heading.id = anchorText;\n\n // add to wrapper\n const elementAnchor = elementAnchorClone.cloneNode(false) as HTMLAnchorElement;\n elementAnchor.href = `#${anchorText}`;\n elementAnchor.textContent = heading.textContent;\n const elementList = elementListClone.cloneNode(false) as HTMLLIElement;\n elementList.appendChild(elementAnchor);\n\n elementContainer.appendChild(elementList);\n\n // upadte current number\n number = currentNumber;\n }\n};\n\nexport const Mokuji = (element: HTMLElement | null, externalOptions?: MokujiOption): HTMLOListElement | undefined => {\n if (!element) {\n return;\n }\n\n // Merge the default options with the external options.\n const options = Object.assign(\n // default options\n defaultOptions,\n externalOptions,\n );\n\n const headings = getHeadingsElement(element);\n\n // mokuji start\n const elementContainer = document.createElement(\n options.anchorContainerTagName || defaultOptions.anchorContainerTagName,\n );\n\n // generate mokuji list\n generateHierarchyList(headings, elementContainer, !!options.anchorType);\n\n // remove duplicates by adding suffix\n removeDuplicateIds(headings, elementContainer);\n\n // setup anchor link\n if (options.anchorLink) {\n const anchors = elementContainer.querySelectorAll('a');\n renderAnchorLink(headings, anchors, options);\n }\n\n return elementContainer;\n};\n","export const replaceSpace2Underscore = (text: string) => {\n return text.replace(/\\s+/g, '_');\n};\n\nexport const convert2WikipediaStyleAnchor = (anchor: string) => {\n anchor = encodeURIComponent(anchor);\n anchor = anchor.replace(/\\%+/g, '.');\n\n return anchor;\n};\n\nexport const getHeadingTagName2Number = (tagName: string) => {\n return Number(tagName.substring(1));\n};\n"],"names":["hasParentNode","element","parent","parentNode","defaultOptions","anchorType","anchorLink","anchorLinkSymbol","anchorLinkBefore","anchorLinkClassName","anchorContainerTagName","storeIds","censorshipId","headings","textContent","id","suffix_count","length","tmp_id","indexOf","push","Mokuji","externalOptions","options","Object","assign","querySelectorAll","getHeadingsElement","elementContainer","document","createElement","number","elementListClone","elementAnchorClone","i","heading","currentNumber","Number","tagName","substring","nextElementOListClone","lastChild","appendChild","anchorText","type","anchor","text","replace","encodeURIComponent","convert2WikipediaStyleAnchor","elementAnchor","cloneNode","href","elementList","generateHierarchyList","anchors","getElementsByTagName","innerText","hash","matchedHeadings","Array","from","filter","count","forEach","heading_id","removeDuplicateIds","a","classList","add","setAttribute","insertBefore","firstChild","renderAnchorLink"],"mappings":"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"}
|
package/dist/mokuji.umd.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((e||self).mokujiJs={})}(this,function(e){var n=function(e,n){for(;e;){if(e===n)return!0;e=e.parentNode}return!1},
|
|
1
|
+
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((e||self).mokujiJs={})}(this,function(e){var n=function(e,n){for(;e;){if(e===n)return!0;e=e.parentNode}return!1},r={anchorType:!0,anchorLink:!1,anchorLinkSymbol:"#",anchorLinkBefore:!0,anchorLinkClassName:"",anchorContainerTagName:"ol"},t=[],a=function(e,n){for(var r=n||"",a=1;a<=e.length;){var o=1===a?r:r+"_"+a;if(-1===t.indexOf(o)){t.push(r=o);break}a++}return r};e.Mokuji=function(e,t){if(e){var o=Object.assign(r,t),i=function(e){return e.querySelectorAll("h1, h2, h3, h4, h5, h6")}(e),c=document.createElement(o.anchorContainerTagName||r.anchorContainerTagName);return function(e,r,t){for(var o=0,i=document.createElement("li"),c=document.createElement("a"),f=0;f<e.length;f++){var l=e[f],h=Number(l.tagName.substring(1));if(0!==o&&o<h){var d=document.createElement("ol");r.lastChild.appendChild(d),r=d}else if(0!==o&&o>h)for(var u=0;u<o-h;u++)n(r,r.parentNode)&&(r=r.parentNode.parentNode);var s=(g=t,C=void 0,C=(v=a(e,l.textContent),C=v.replace(/\s+/g,"_")).replace(/\&+/g,"").replace(/\&+/g,""),!0===g&&(C=function(e){return(e=encodeURIComponent(e)).replace(/\%+/g,".")}(C)),C);l.id=s;var m=c.cloneNode(!1);m.href="#"+s,m.textContent=l.textContent;var p=i.cloneNode(!1);p.appendChild(m),r.appendChild(p),o=h}var v,g,C}(i,c,!!o.anchorType),function(e,n){for(var r=n.getElementsByTagName("a"),t=function(n){var t=r[n].innerText,a=r[n].hash,o=Array.from(e).filter(function(e){return e.id===t});if(1===o.length)return"continue";var i=0;o.forEach(function(e){for(var n=e.id+"-"+i,t=0,o=Array.from(r);t<o.length;t++){var c=o[t];if(c.hash===a){c.href="#"+n;break}}e.id=n,i++})},a=0;a<r.length;a++)t(a)}(i,c),o.anchorLink&&function(e,n,r){if(n){var t=document.createElement("a");r.anchorLinkClassName&&t.classList.add(r.anchorLinkClassName),e.forEach(function(e){for(var a=e.id,o=0;o<n.length;o++){var i=n[o].hash;if(i.replace("#","")===a){var c=t.cloneNode(!1);c.setAttribute("href",i),r.anchorLinkSymbol&&(c.textContent=r.anchorLinkSymbol),r.anchorLinkBefore?e.insertBefore(c,e.firstChild):e.appendChild(c)}}})}}(i,c.querySelectorAll("a"),o),c}}});
|
|
2
2
|
//# sourceMappingURL=mokuji.umd.js.map
|
package/dist/mokuji.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mokuji.umd.js","sources":["../src/dom.ts","../src/index.ts","../src/utils.ts"],"sourcesContent":["export const hasParentNode = (element: Node | null, parent: Node | null) => {\n while (element) {\n if (element === parent) {\n return true;\n }\n element = element.parentNode;\n }\n return false;\n};\n\nexport const reverseElement = (element: Node) => {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n return element;\n};\n\nexport const getHeadingsElement = (element: Element): NodeListOf<HTMLHeadingElement> => {\n return element.querySelectorAll(\"h1, h2, h3, h4, h5, h6\");\n};\n","import { hasParentNode, getHeadingsElement } from './dom';\nimport { replaceSpace2Underscore, convert2WikipediaStyleAnchor, getHeadingTagName2Number } from './utils';\n\nexport type MokujiOption = {\n anchorType?: boolean;\n anchorLink?: boolean;\n anchorLinkSymbol?: string;\n anchorLinkBefore?: boolean;\n anchorLinkClassName?: string;\n anchorContainerTagName?: 'ul' | 'ol';\n};\n\nexport const renderAnchorLink = (\n headings: NodeListOf<HTMLHeadingElement>,\n anchors: NodeListOf<HTMLAnchorElement> | undefined,\n options: MokujiOption,\n) => {\n if (!anchors) return;\n\n const a = document.createElement('a');\n\n if (options.anchorLinkClassName) {\n a.classList.add(options.anchorLinkClassName);\n }\n\n headings.forEach((heading) => {\n const { id } = heading;\n\n for (let i = 0; i < anchors.length; i++) {\n const { hash } = anchors[i];\n\n if (hash.replace('#', '') !== id) {\n continue;\n }\n\n // create anchor\n const anchor = a.cloneNode(false) as HTMLAnchorElement;\n anchor.setAttribute('href', hash);\n\n if (options.anchorLinkSymbol) {\n anchor.textContent = options.anchorLinkSymbol;\n }\n\n // insert anchor into headings\n if (options.anchorLinkBefore) {\n // before\n heading.insertBefore(anchor, heading.firstChild);\n } else {\n // after\n heading.appendChild(anchor);\n }\n }\n });\n};\n\nexport class Mokuji {\n options: MokujiOption = {\n anchorType: true,\n anchorLink: false,\n anchorLinkSymbol: '#',\n anchorLinkBefore: true,\n anchorLinkClassName: '',\n anchorContainerTagName: 'ol',\n };\n storeIds: string[] = [];\n\n constructor(element: HTMLElement | null, externalOptions: MokujiOption) {\n if (!element) {\n return;\n }\n\n // Merge the default options with the external options.\n this.options = Object.assign(\n // default options\n this.options,\n externalOptions,\n );\n\n const headings = getHeadingsElement(element);\n\n // mokuji start\n // generate mokuji list\n const mokuji = this.generateMokuji(headings);\n\n // setup anchor link\n if (this.options.anchorLink) {\n const anchors = mokuji.querySelectorAll('a');\n renderAnchorLink(headings, anchors, this.options);\n }\n\n // @ts-ignore\n return mokuji;\n }\n\n generateMokuji(headings: NodeListOf<HTMLHeadingElement>) {\n let elementContainer = document.createElement(this.options.anchorContainerTagName || 'ol');\n\n this.generateHierarchyList(headings, elementContainer);\n\n // remove duplicates by adding suffix\n this.removeDuplicateIds(headings, elementContainer);\n\n return elementContainer;\n }\n\n generateHierarchyList(headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement) {\n let number = 0;\n const elementListClone = document.createElement('li');\n const elementAnchorClone = document.createElement('a');\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const currentNumber = getHeadingTagName2Number(heading.tagName);\n\n // check list hierarchy\n if (number !== 0 && number < currentNumber) {\n // number of the heading is large (small as heading)\n const nextElementOListClone = document.createElement('ol');\n // @ts-ignore\n elementContainer.lastChild.appendChild(nextElementOListClone);\n elementContainer = nextElementOListClone;\n } else if (number !== 0 && number > currentNumber) {\n // number of heading is small (large as heading)\n for (let i = 0; i < number - currentNumber; i++) {\n if (hasParentNode(elementContainer, elementContainer.parentNode)) {\n // @ts-ignore\n elementContainer = elementContainer.parentNode.parentNode;\n }\n }\n }\n\n const textContent = this.censorshipId(headings, heading.textContent);\n\n // headingへidを付与\n const anchorText = this.generateAnchorText(textContent, !!this.options.anchorType);\n heading.id = anchorText;\n\n // add to wrapper\n const elementAnchor = elementAnchorClone.cloneNode(false) as HTMLAnchorElement;\n elementAnchor.href = `#${anchorText}`;\n elementAnchor.textContent = heading.textContent;\n const elementList = elementListClone.cloneNode(false);\n elementList.appendChild(elementAnchor);\n elementContainer.appendChild(elementList);\n\n // upadte current number\n number = currentNumber;\n }\n }\n\n censorshipId(headings: NodeListOf<HTMLHeadingElement>, textContent: string | null) {\n let id = textContent || '';\n let suffix_count = 1;\n\n // IDが重複していた場合はsuffixを付ける\n while (suffix_count <= headings.length) {\n const tmp_id = suffix_count === 1 ? id : `${id}_${suffix_count}`;\n\n if (this.storeIds.indexOf(tmp_id) === -1) {\n id = tmp_id;\n this.storeIds.push(id);\n break;\n }\n\n suffix_count++;\n }\n\n return id;\n }\n\n generateAnchorText(text: string, type: boolean) {\n // convert spaces to _\n let anchor = replaceSpace2Underscore(text);\n\n // remove &\n anchor = anchor.replace(/\\&+/g, '').replace(/\\&+/g, '');\n\n if (type === true) {\n anchor = convert2WikipediaStyleAnchor(anchor);\n }\n\n return anchor;\n }\n\n removeDuplicateIds(headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement) {\n const anchors = elementContainer.getElementsByTagName('a');\n\n for (let i = 0; i < anchors.length; i++) {\n const id = anchors[i].innerText;\n const hash = anchors[i].hash;\n const matchedHeadings = Array.from(headings).filter((heading) => heading.id === id);\n\n if (matchedHeadings.length === 1) {\n continue;\n }\n\n // duplicated id\n let count = 0;\n\n matchedHeadings.forEach((heading) => {\n const heading_id = `${heading.id}-${count}`;\n\n // search duplicate list\n for (const anchor of Array.from(anchors)) {\n if (anchor.hash === hash) {\n // update hash\n anchor.href = `#${heading_id}`;\n break;\n }\n }\n\n // update id\n heading.id = heading_id;\n count++;\n });\n }\n }\n}\n","export const replaceSpace2Underscore = (text: string) => {\n return text.replace(/\\s+/g, '_');\n};\n\nexport const convert2WikipediaStyleAnchor = (anchor: string) => {\n anchor = encodeURIComponent(anchor);\n anchor = anchor.replace(/\\%+/g, '.');\n\n return anchor;\n};\n\nexport const getHeadingTagName2Number = (tagName: string) => {\n return Number(tagName.substring(1));\n};\n"],"names":["hasParentNode","element","parent","parentNode","renderAnchorLink","headings","anchors","options","a","document","createElement","anchorLinkClassName","classList","add","forEach","heading","id","i","length","hash","replace","anchor","cloneNode","setAttribute","anchorLinkSymbol","textContent","anchorLinkBefore","insertBefore","firstChild","appendChild","externalOptions","anchorType","anchorLink","anchorContainerTagName","storeIds","this","Object","assign","querySelectorAll","getHeadingsElement","mokuji","generateMokuji","elementContainer","generateHierarchyList","removeDuplicateIds","number","elementListClone","elementAnchorClone","currentNumber","Number","tagName","substring","nextElementOListClone","lastChild","censorshipId","anchorText","generateAnchorText","elementAnchor","href","elementList","suffix_count","tmp_id","indexOf","push","text","type","replaceSpace2Underscore","encodeURIComponent","convert2WikipediaStyleAnchor","getElementsByTagName","innerText","matchedHeadings","Array","from","filter","count","heading_id"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mokuji.umd.js","sources":["../src/dom.ts","../src/index.ts","../src/utils.ts"],"sourcesContent":["export const hasParentNode = (element: Node | null, parent: Node | null) => {\n while (element) {\n if (element === parent) {\n return true;\n }\n element = element.parentNode;\n }\n return false;\n};\n\nexport const reverseElement = (element: Node) => {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n return element;\n};\n\nexport const getHeadingsElement = (element: Element): NodeListOf<HTMLHeadingElement> => {\n return element.querySelectorAll(\"h1, h2, h3, h4, h5, h6\");\n};\n","import { hasParentNode, getHeadingsElement } from './dom';\nimport { replaceSpace2Underscore, convert2WikipediaStyleAnchor, getHeadingTagName2Number } from './utils';\n\ntype AnchorContainerTagNameProps = 'ul' | 'ol';\n\nexport type MokujiOption = {\n anchorType?: boolean;\n anchorLink?: boolean;\n anchorLinkSymbol?: string;\n anchorLinkBefore?: boolean;\n anchorLinkClassName?: string;\n anchorContainerTagName?: AnchorContainerTagNameProps;\n};\n\nconst defaultOptions = {\n anchorType: true,\n anchorLink: false,\n anchorLinkSymbol: '#',\n anchorLinkBefore: true,\n anchorLinkClassName: '',\n anchorContainerTagName: 'ol',\n} as const;\n\nconst storeIds: string[] = [];\n\nconst renderAnchorLink = (\n headings: NodeListOf<HTMLHeadingElement>,\n anchors: NodeListOf<HTMLAnchorElement> | undefined,\n options: MokujiOption,\n) => {\n if (!anchors) return;\n\n const a = document.createElement('a');\n\n if (options.anchorLinkClassName) {\n a.classList.add(options.anchorLinkClassName);\n }\n\n headings.forEach((heading) => {\n const { id } = heading;\n\n for (let i = 0; i < anchors.length; i++) {\n const { hash } = anchors[i];\n\n if (hash.replace('#', '') !== id) {\n continue;\n }\n\n // create anchor\n const anchor = a.cloneNode(false) as HTMLAnchorElement;\n anchor.setAttribute('href', hash);\n\n if (options.anchorLinkSymbol) {\n anchor.textContent = options.anchorLinkSymbol;\n }\n\n // insert anchor into headings\n if (options.anchorLinkBefore) {\n // before\n heading.insertBefore(anchor, heading.firstChild);\n } else {\n // after\n heading.appendChild(anchor);\n }\n }\n });\n};\n\nconst removeDuplicateIds = (headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement) => {\n const anchors = elementContainer.getElementsByTagName('a');\n\n for (let i = 0; i < anchors.length; i++) {\n const id = anchors[i].innerText;\n const hash = anchors[i].hash;\n const matchedHeadings = Array.from(headings).filter((heading) => heading.id === id);\n\n if (matchedHeadings.length === 1) {\n continue;\n }\n\n // duplicated id\n let count = 0;\n\n matchedHeadings.forEach((heading) => {\n const heading_id = `${heading.id}-${count}`;\n\n // search duplicate list\n for (const anchor of Array.from(anchors)) {\n if (anchor.hash === hash) {\n // update hash\n anchor.href = `#${heading_id}`;\n break;\n }\n }\n\n // update id\n heading.id = heading_id;\n count++;\n });\n }\n};\n\nconst censorshipId = (headings: NodeListOf<HTMLHeadingElement>, textContent: string | null) => {\n let id = textContent || '';\n let suffix_count = 1;\n\n // IDが重複していた場合はsuffixを付ける\n while (suffix_count <= headings.length) {\n const tmp_id = suffix_count === 1 ? id : `${id}_${suffix_count}`;\n\n if (storeIds.indexOf(tmp_id) === -1) {\n id = tmp_id;\n storeIds.push(id);\n break;\n }\n\n suffix_count++;\n }\n\n return id;\n};\n\nconst generateAnchorText = (text: string, type: boolean) => {\n // convert spaces to _\n let anchor = replaceSpace2Underscore(text);\n\n // remove &\n anchor = anchor.replace(/\\&+/g, '').replace(/\\&+/g, '');\n\n if (type === true) {\n anchor = convert2WikipediaStyleAnchor(anchor);\n }\n\n return anchor;\n};\n\nconst generateHierarchyList = (\n headings: NodeListOf<HTMLHeadingElement>,\n elementContainer: HTMLUListElement | HTMLOListElement,\n anchorType: boolean,\n) => {\n let number = 0;\n const elementListClone = document.createElement('li');\n const elementAnchorClone = document.createElement('a');\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const currentNumber = getHeadingTagName2Number(heading.tagName);\n\n // check list hierarchy\n if (number !== 0 && number < currentNumber) {\n // number of the heading is large (small as heading)\n const nextElementOListClone = document.createElement('ol');\n // @ts-ignore\n elementContainer.lastChild.appendChild(nextElementOListClone);\n elementContainer = nextElementOListClone;\n } else if (number !== 0 && number > currentNumber) {\n // number of heading is small (large as heading)\n for (let i = 0; i < number - currentNumber; i++) {\n if (hasParentNode(elementContainer, elementContainer.parentNode)) {\n // @ts-ignore\n elementContainer = elementContainer.parentNode.parentNode;\n }\n }\n }\n\n const textContent = censorshipId(headings, heading.textContent);\n\n // headingへidを付与\n const anchorText = generateAnchorText(textContent, anchorType);\n heading.id = anchorText;\n\n // add to wrapper\n const elementAnchor = elementAnchorClone.cloneNode(false) as HTMLAnchorElement;\n elementAnchor.href = `#${anchorText}`;\n elementAnchor.textContent = heading.textContent;\n const elementList = elementListClone.cloneNode(false) as HTMLLIElement;\n elementList.appendChild(elementAnchor);\n\n elementContainer.appendChild(elementList);\n\n // upadte current number\n number = currentNumber;\n }\n};\n\nexport const Mokuji = (element: HTMLElement | null, externalOptions?: MokujiOption): HTMLOListElement | undefined => {\n if (!element) {\n return;\n }\n\n // Merge the default options with the external options.\n const options = Object.assign(\n // default options\n defaultOptions,\n externalOptions,\n );\n\n const headings = getHeadingsElement(element);\n\n // mokuji start\n const elementContainer = document.createElement(\n options.anchorContainerTagName || defaultOptions.anchorContainerTagName,\n );\n\n // generate mokuji list\n generateHierarchyList(headings, elementContainer, !!options.anchorType);\n\n // remove duplicates by adding suffix\n removeDuplicateIds(headings, elementContainer);\n\n // setup anchor link\n if (options.anchorLink) {\n const anchors = elementContainer.querySelectorAll('a');\n renderAnchorLink(headings, anchors, options);\n }\n\n return elementContainer;\n};\n","export const replaceSpace2Underscore = (text: string) => {\n return text.replace(/\\s+/g, '_');\n};\n\nexport const convert2WikipediaStyleAnchor = (anchor: string) => {\n anchor = encodeURIComponent(anchor);\n anchor = anchor.replace(/\\%+/g, '.');\n\n return anchor;\n};\n\nexport const getHeadingTagName2Number = (tagName: string) => {\n return Number(tagName.substring(1));\n};\n"],"names":["hasParentNode","element","parent","parentNode","defaultOptions","anchorType","anchorLink","anchorLinkSymbol","anchorLinkBefore","anchorLinkClassName","anchorContainerTagName","storeIds","censorshipId","headings","textContent","id","suffix_count","length","tmp_id","indexOf","push","externalOptions","options","Object","assign","querySelectorAll","getHeadingsElement","elementContainer","document","createElement","number","elementListClone","elementAnchorClone","i","heading","currentNumber","Number","tagName","substring","nextElementOListClone","lastChild","appendChild","anchorText","type","anchor","text","replace","encodeURIComponent","convert2WikipediaStyleAnchor","elementAnchor","cloneNode","href","elementList","generateHierarchyList","anchors","getElementsByTagName","innerText","hash","matchedHeadings","Array","from","filter","count","forEach","heading_id","removeDuplicateIds","a","classList","add","setAttribute","insertBefore","firstChild","renderAnchorLink"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mokuji.js",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "A table of content JavaScript Library",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "microbundle",
|
|
@@ -47,14 +47,12 @@
|
|
|
47
47
|
},
|
|
48
48
|
"homepage": "https://github.com/hiro0218/mokuji.js",
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@babel/plugin-proposal-optional-chaining": "^7.13.12",
|
|
51
50
|
"@types/node": "~17.0.23",
|
|
52
|
-
"cross-env": "^5.2.0",
|
|
53
51
|
"husky": "^7.0.4",
|
|
54
52
|
"lint-staged": "^12.3.7",
|
|
55
53
|
"microbundle": "^0.14.2",
|
|
56
|
-
"prettier": "^2.6.
|
|
54
|
+
"prettier": "^2.6.1",
|
|
57
55
|
"rimraf": "^3.0.2",
|
|
58
|
-
"typescript": "~4.6.
|
|
56
|
+
"typescript": "~4.6.3"
|
|
59
57
|
}
|
|
60
58
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
import { hasParentNode, getHeadingsElement } from './dom';
|
|
2
2
|
import { replaceSpace2Underscore, convert2WikipediaStyleAnchor, getHeadingTagName2Number } from './utils';
|
|
3
3
|
|
|
4
|
+
type AnchorContainerTagNameProps = 'ul' | 'ol';
|
|
5
|
+
|
|
4
6
|
export type MokujiOption = {
|
|
5
7
|
anchorType?: boolean;
|
|
6
8
|
anchorLink?: boolean;
|
|
7
9
|
anchorLinkSymbol?: string;
|
|
8
10
|
anchorLinkBefore?: boolean;
|
|
9
11
|
anchorLinkClassName?: string;
|
|
10
|
-
anchorContainerTagName?:
|
|
12
|
+
anchorContainerTagName?: AnchorContainerTagNameProps;
|
|
11
13
|
};
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
const defaultOptions = {
|
|
16
|
+
anchorType: true,
|
|
17
|
+
anchorLink: false,
|
|
18
|
+
anchorLinkSymbol: '#',
|
|
19
|
+
anchorLinkBefore: true,
|
|
20
|
+
anchorLinkClassName: '',
|
|
21
|
+
anchorContainerTagName: 'ol',
|
|
22
|
+
} as const;
|
|
23
|
+
|
|
24
|
+
const storeIds: string[] = [];
|
|
25
|
+
|
|
26
|
+
const renderAnchorLink = (
|
|
14
27
|
headings: NodeListOf<HTMLHeadingElement>,
|
|
15
28
|
anchors: NodeListOf<HTMLAnchorElement> | undefined,
|
|
16
29
|
options: MokujiOption,
|
|
@@ -53,166 +66,154 @@ export const renderAnchorLink = (
|
|
|
53
66
|
});
|
|
54
67
|
};
|
|
55
68
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
anchorType: true,
|
|
59
|
-
anchorLink: false,
|
|
60
|
-
anchorLinkSymbol: '#',
|
|
61
|
-
anchorLinkBefore: true,
|
|
62
|
-
anchorLinkClassName: '',
|
|
63
|
-
anchorContainerTagName: 'ol',
|
|
64
|
-
};
|
|
65
|
-
storeIds: string[] = [];
|
|
66
|
-
|
|
67
|
-
constructor(element: HTMLElement | null, externalOptions: MokujiOption) {
|
|
68
|
-
if (!element) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
69
|
+
const removeDuplicateIds = (headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement) => {
|
|
70
|
+
const anchors = elementContainer.getElementsByTagName('a');
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
externalOptions,
|
|
77
|
-
);
|
|
72
|
+
for (let i = 0; i < anchors.length; i++) {
|
|
73
|
+
const id = anchors[i].innerText;
|
|
74
|
+
const hash = anchors[i].hash;
|
|
75
|
+
const matchedHeadings = Array.from(headings).filter((heading) => heading.id === id);
|
|
78
76
|
|
|
79
|
-
|
|
77
|
+
if (matchedHeadings.length === 1) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
80
|
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
const mokuji = this.generateMokuji(headings);
|
|
81
|
+
// duplicated id
|
|
82
|
+
let count = 0;
|
|
84
83
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
matchedHeadings.forEach((heading) => {
|
|
85
|
+
const heading_id = `${heading.id}-${count}`;
|
|
86
|
+
|
|
87
|
+
// search duplicate list
|
|
88
|
+
for (const anchor of Array.from(anchors)) {
|
|
89
|
+
if (anchor.hash === hash) {
|
|
90
|
+
// update hash
|
|
91
|
+
anchor.href = `#${heading_id}`;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
90
95
|
|
|
91
|
-
|
|
92
|
-
|
|
96
|
+
// update id
|
|
97
|
+
heading.id = heading_id;
|
|
98
|
+
count++;
|
|
99
|
+
});
|
|
93
100
|
}
|
|
101
|
+
};
|
|
94
102
|
|
|
95
|
-
|
|
96
|
-
|
|
103
|
+
const censorshipId = (headings: NodeListOf<HTMLHeadingElement>, textContent: string | null) => {
|
|
104
|
+
let id = textContent || '';
|
|
105
|
+
let suffix_count = 1;
|
|
97
106
|
|
|
98
|
-
|
|
107
|
+
// IDが重複していた場合はsuffixを付ける
|
|
108
|
+
while (suffix_count <= headings.length) {
|
|
109
|
+
const tmp_id = suffix_count === 1 ? id : `${id}_${suffix_count}`;
|
|
99
110
|
|
|
100
|
-
|
|
101
|
-
|
|
111
|
+
if (storeIds.indexOf(tmp_id) === -1) {
|
|
112
|
+
id = tmp_id;
|
|
113
|
+
storeIds.push(id);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
102
116
|
|
|
103
|
-
|
|
117
|
+
suffix_count++;
|
|
104
118
|
}
|
|
105
119
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const elementListClone = document.createElement('li');
|
|
109
|
-
const elementAnchorClone = document.createElement('a');
|
|
110
|
-
|
|
111
|
-
for (let i = 0; i < headings.length; i++) {
|
|
112
|
-
const heading = headings[i];
|
|
113
|
-
const currentNumber = getHeadingTagName2Number(heading.tagName);
|
|
114
|
-
|
|
115
|
-
// check list hierarchy
|
|
116
|
-
if (number !== 0 && number < currentNumber) {
|
|
117
|
-
// number of the heading is large (small as heading)
|
|
118
|
-
const nextElementOListClone = document.createElement('ol');
|
|
119
|
-
// @ts-ignore
|
|
120
|
-
elementContainer.lastChild.appendChild(nextElementOListClone);
|
|
121
|
-
elementContainer = nextElementOListClone;
|
|
122
|
-
} else if (number !== 0 && number > currentNumber) {
|
|
123
|
-
// number of heading is small (large as heading)
|
|
124
|
-
for (let i = 0; i < number - currentNumber; i++) {
|
|
125
|
-
if (hasParentNode(elementContainer, elementContainer.parentNode)) {
|
|
126
|
-
// @ts-ignore
|
|
127
|
-
elementContainer = elementContainer.parentNode.parentNode;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const textContent = this.censorshipId(headings, heading.textContent);
|
|
120
|
+
return id;
|
|
121
|
+
};
|
|
133
122
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
123
|
+
const generateAnchorText = (text: string, type: boolean) => {
|
|
124
|
+
// convert spaces to _
|
|
125
|
+
let anchor = replaceSpace2Underscore(text);
|
|
137
126
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
elementAnchor.href = `#${anchorText}`;
|
|
141
|
-
elementAnchor.textContent = heading.textContent;
|
|
142
|
-
const elementList = elementListClone.cloneNode(false);
|
|
143
|
-
elementList.appendChild(elementAnchor);
|
|
144
|
-
elementContainer.appendChild(elementList);
|
|
127
|
+
// remove &
|
|
128
|
+
anchor = anchor.replace(/\&+/g, '').replace(/\&+/g, '');
|
|
145
129
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
130
|
+
if (type === true) {
|
|
131
|
+
anchor = convert2WikipediaStyleAnchor(anchor);
|
|
149
132
|
}
|
|
150
133
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
let suffix_count = 1;
|
|
154
|
-
|
|
155
|
-
// IDが重複していた場合はsuffixを付ける
|
|
156
|
-
while (suffix_count <= headings.length) {
|
|
157
|
-
const tmp_id = suffix_count === 1 ? id : `${id}_${suffix_count}`;
|
|
134
|
+
return anchor;
|
|
135
|
+
};
|
|
158
136
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
137
|
+
const generateHierarchyList = (
|
|
138
|
+
headings: NodeListOf<HTMLHeadingElement>,
|
|
139
|
+
elementContainer: HTMLUListElement | HTMLOListElement,
|
|
140
|
+
anchorType: boolean,
|
|
141
|
+
) => {
|
|
142
|
+
let number = 0;
|
|
143
|
+
const elementListClone = document.createElement('li');
|
|
144
|
+
const elementAnchorClone = document.createElement('a');
|
|
145
|
+
|
|
146
|
+
for (let i = 0; i < headings.length; i++) {
|
|
147
|
+
const heading = headings[i];
|
|
148
|
+
const currentNumber = getHeadingTagName2Number(heading.tagName);
|
|
149
|
+
|
|
150
|
+
// check list hierarchy
|
|
151
|
+
if (number !== 0 && number < currentNumber) {
|
|
152
|
+
// number of the heading is large (small as heading)
|
|
153
|
+
const nextElementOListClone = document.createElement('ol');
|
|
154
|
+
// @ts-ignore
|
|
155
|
+
elementContainer.lastChild.appendChild(nextElementOListClone);
|
|
156
|
+
elementContainer = nextElementOListClone;
|
|
157
|
+
} else if (number !== 0 && number > currentNumber) {
|
|
158
|
+
// number of heading is small (large as heading)
|
|
159
|
+
for (let i = 0; i < number - currentNumber; i++) {
|
|
160
|
+
if (hasParentNode(elementContainer, elementContainer.parentNode)) {
|
|
161
|
+
// @ts-ignore
|
|
162
|
+
elementContainer = elementContainer.parentNode.parentNode;
|
|
163
|
+
}
|
|
163
164
|
}
|
|
164
|
-
|
|
165
|
-
suffix_count++;
|
|
166
165
|
}
|
|
167
166
|
|
|
168
|
-
|
|
169
|
-
}
|
|
167
|
+
const textContent = censorshipId(headings, heading.textContent);
|
|
170
168
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
169
|
+
// headingへidを付与
|
|
170
|
+
const anchorText = generateAnchorText(textContent, anchorType);
|
|
171
|
+
heading.id = anchorText;
|
|
174
172
|
|
|
175
|
-
//
|
|
176
|
-
|
|
173
|
+
// add to wrapper
|
|
174
|
+
const elementAnchor = elementAnchorClone.cloneNode(false) as HTMLAnchorElement;
|
|
175
|
+
elementAnchor.href = `#${anchorText}`;
|
|
176
|
+
elementAnchor.textContent = heading.textContent;
|
|
177
|
+
const elementList = elementListClone.cloneNode(false) as HTMLLIElement;
|
|
178
|
+
elementList.appendChild(elementAnchor);
|
|
177
179
|
|
|
178
|
-
|
|
179
|
-
anchor = convert2WikipediaStyleAnchor(anchor);
|
|
180
|
-
}
|
|
180
|
+
elementContainer.appendChild(elementList);
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
// upadte current number
|
|
183
|
+
number = currentNumber;
|
|
183
184
|
}
|
|
185
|
+
};
|
|
184
186
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
+
export const Mokuji = (element: HTMLElement | null, externalOptions?: MokujiOption): HTMLOListElement | undefined => {
|
|
188
|
+
if (!element) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
187
191
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
+
// Merge the default options with the external options.
|
|
193
|
+
const options = Object.assign(
|
|
194
|
+
// default options
|
|
195
|
+
defaultOptions,
|
|
196
|
+
externalOptions,
|
|
197
|
+
);
|
|
192
198
|
|
|
193
|
-
|
|
194
|
-
continue;
|
|
195
|
-
}
|
|
199
|
+
const headings = getHeadingsElement(element);
|
|
196
200
|
|
|
197
|
-
|
|
198
|
-
|
|
201
|
+
// mokuji start
|
|
202
|
+
const elementContainer = document.createElement(
|
|
203
|
+
options.anchorContainerTagName || defaultOptions.anchorContainerTagName,
|
|
204
|
+
);
|
|
199
205
|
|
|
200
|
-
|
|
201
|
-
|
|
206
|
+
// generate mokuji list
|
|
207
|
+
generateHierarchyList(headings, elementContainer, !!options.anchorType);
|
|
202
208
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (anchor.hash === hash) {
|
|
206
|
-
// update hash
|
|
207
|
-
anchor.href = `#${heading_id}`;
|
|
208
|
-
break;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
209
|
+
// remove duplicates by adding suffix
|
|
210
|
+
removeDuplicateIds(headings, elementContainer);
|
|
211
211
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
212
|
+
// setup anchor link
|
|
213
|
+
if (options.anchorLink) {
|
|
214
|
+
const anchors = elementContainer.querySelectorAll('a');
|
|
215
|
+
renderAnchorLink(headings, anchors, options);
|
|
217
216
|
}
|
|
218
|
-
|
|
217
|
+
|
|
218
|
+
return elementContainer;
|
|
219
|
+
};
|