mokuji.js 4.3.0 → 4.4.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/LICENSE +1 -1
- package/dist/index.cjs +8 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/package.json +32 -25
- package/dist/dom.d.ts +0 -3
- package/dist/mokuji.js +0 -2
- package/dist/mokuji.js.map +0 -1
- package/dist/mokuji.modern.js +0 -2
- package/dist/mokuji.modern.js.map +0 -1
- package/dist/mokuji.module.js +0 -2
- package/dist/mokuji.module.js.map +0 -1
- package/dist/mokuji.umd.js +0 -2
- package/dist/mokuji.umd.js.map +0 -1
- package/dist/utils.d.ts +0 -3
- package/src/dom.ts +0 -21
- package/src/index.ts +0 -226
- package/src/utils.ts +0 -11
package/LICENSE
CHANGED
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var g=(t,n)=>!t||!n?!1:n.contains(t),u=t=>t.querySelectorAll("h1, h2, h3, h4, h5, h6"),h=t=>document.createElement(t);var L=new Set,E=t=>t.replaceAll(/\s+/g,"_"),A=t=>encodeURIComponent(t).replaceAll(/%+/g,"."),T=(t,n="")=>{let e=n,o=1;for(;o<=t.length;){let r=o===1?e:`${e}_${o}`;if(!L.has(r)){e=r,L.add(e);break}o++;}return e},M=(t,n)=>{let e=E(t);return e=e.replaceAll(/&+/g,"").replaceAll(/&+/g,""),n&&(e=A(e)),e};var H="data-mokuji-anchor",k={anchorType:!0,anchorLink:!1,anchorLinkSymbol:"#",anchorLinkBefore:!0,anchorLinkClassName:"",anchorContainerTagName:"ol"},N=t=>{let n=new Map;for(let e=0;e<t.length;e++){let o=t[e].hash.replace("#","");n.set(o,t[e]);}return n},x=(t,n,e)=>{let o=h("a");o.setAttribute(H,""),e.anchorLinkClassName&&o.classList.add(e.anchorLinkClassName);for(let r=0;r<t.length;r++){let c=t[r],l=n.get(c.id);if(!l)continue;let s=o.cloneNode(!1);s.setAttribute("href",l.hash),e.anchorLinkSymbol&&(s.textContent=e.anchorLinkSymbol),e.anchorLinkBefore?c.insertBefore(s,c.firstChild):c.append(s);}},y=(t,n)=>{for(let e=0;e<n.length;e++){let o=n[e],r=o.textContent,c=o.hash,l=t.filter(a=>a.id===r);if(l.length===1)continue;let s=0;for(let a=0;a<l.length;a++){let f=l[a],d=`${f.id}-${s}`;for(let i=0;i<n.length;i++){let m=n[i];if(m.hash===c){m.href=`#${d}`;break}}f.id=d,s++;}}},C=(t,n,e)=>{let o=0,r=h("li"),c=h("a");for(let l=0;l<t.length;l++){let s=t[l],a=Number(s.tagName[1]);if(o!==0&&o<a){let p=h("ol");n.lastChild.append(p),n=p;}else if(o!==0&&o>a)for(let p=0;p<o-a;p++)g(n,n.parentNode)&&(n=n.parentNode?.parentNode);let f=T(t,s.textContent||""),d=M(f,e);s.id=d;let i=c.cloneNode(!1);i.href=`#${d}`,i.textContent=s.textContent;let m=r.cloneNode(!1);m.append(i),n.append(m),o=a;}},I=(t,n)=>{if(!t)return;let e={...k,...n},o=[...u(t)];if(o.length===0)return;let r=h(e.anchorContainerTagName);C(o,r,e.anchorType);let c=[...r.querySelectorAll("a")];if(c.length!==0){if(y(o,c),e.anchorLink){let l=N(c);x(o,l,e);}return r}},_=()=>{let t=document.querySelectorAll(`[${H}]`);for(let n=t.length-1;n>=0;n--)t[n].remove();};
|
|
4
|
+
|
|
5
|
+
exports.Mokuji = I;
|
|
6
|
+
exports.destory = _;
|
|
7
|
+
//# sourceMappingURL=out.js.map
|
|
8
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dom.ts","../src/text.ts","../src/index.ts"],"names":["hasParentNode","element","parent","getHeadingsElement","createElement","tagName","storeIds","replaceSpacesWithUnderscores","text","convert2WikipediaStyleAnchor","anchor","censorshipId","headings","textContent","id","suffix_count","tmp_id","generateAnchorText","isConvertToWikipediaStyleAnchor","ANCHOR_DATASET_ATTRIBUTE","defaultOptions","generateAnchorsMap","anchors","anchorMap","i","anchorId","insertAnchorToHeadings","options","a","heading","matchedAnchor","removeDuplicateIds","hash","matchedHeadings","count","j","heading_id","k","generateHierarchyList","elementContainer","number","elementListClone","elementAnchorClone","currentNumber","nextElementOListClone","anchorText","elementAnchor","elementList","Mokuji","externalOptions","anchorsMap","destory","mokujiAnchor"],"mappings":"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","sourcesContent":["/**\n * 親要素内に要素が存在するか判定する\n */\nexport const hasParentNode = (element: Node | null, parent: Node | null) => {\n if (!element || !parent) {\n return false;\n }\n\n return parent.contains(element);\n};\n\n/**\n * 見出し要素をすべて取得する\n */\nexport const getHeadingsElement = (element: Element) => {\n return element.querySelectorAll<HTMLHeadingElement>('h1, h2, h3, h4, h5, h6');\n};\n\n/**\n * 要素を作成する\n */\nexport const createElement = <T extends keyof HTMLElementTagNameMap>(tagName: T): HTMLElementTagNameMap[T] => {\n return document.createElement(tagName);\n};\n","const storeIds = new Set<string>();\n\nconst replaceSpacesWithUnderscores = (text: string) => {\n return text.replaceAll(/\\s+/g, '_');\n};\n\nconst convert2WikipediaStyleAnchor = (anchor: string) => {\n return encodeURIComponent(anchor).replaceAll(/%+/g, '.');\n};\n\nexport const censorshipId = (headings: HTMLHeadingElement[], textContent = '') => {\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.has(tmp_id)) {\n id = tmp_id;\n storeIds.add(id);\n break;\n }\n\n suffix_count++;\n }\n\n return id;\n};\n\nexport const generateAnchorText = (text: string, isConvertToWikipediaStyleAnchor: boolean) => {\n // convert spaces to _\n let anchor = replaceSpacesWithUnderscores(text);\n\n // remove &\n anchor = anchor.replaceAll(/&+/g, '').replaceAll(/&+/g, '');\n\n if (isConvertToWikipediaStyleAnchor) {\n anchor = convert2WikipediaStyleAnchor(anchor);\n }\n\n return anchor;\n};\n","import { hasParentNode, getHeadingsElement, createElement } from './dom';\nimport type { MokujiOption } from './types';\nimport { censorshipId, generateAnchorText } from './text';\n\nexport { MokujiOption };\n\nconst ANCHOR_DATASET_ATTRIBUTE = 'data-mokuji-anchor';\n\nconst defaultOptions = {\n anchorType: true,\n anchorLink: false,\n anchorLinkSymbol: '#',\n anchorLinkBefore: true,\n anchorLinkClassName: '',\n anchorContainerTagName: 'ol',\n} as const;\n\nconst generateAnchorsMap = (anchors: HTMLAnchorElement[]) => {\n const anchorMap = new Map<string, HTMLAnchorElement>();\n\n for (let i = 0; i < anchors.length; i++) {\n const anchorId = anchors[i].hash.replace('#', '');\n anchorMap.set(anchorId, anchors[i]);\n }\n\n return anchorMap;\n};\n\nconst insertAnchorToHeadings = (\n headings: HTMLHeadingElement[],\n anchorMap: Map<string, HTMLAnchorElement>,\n options: MokujiOption,\n) => {\n const a = createElement('a');\n a.setAttribute(ANCHOR_DATASET_ATTRIBUTE, '');\n\n if (options.anchorLinkClassName) {\n a.classList.add(options.anchorLinkClassName);\n }\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const matchedAnchor = anchorMap.get(heading.id);\n\n if (!matchedAnchor) {\n continue;\n }\n\n // create anchor\n const anchor = a.cloneNode(false) as HTMLAnchorElement;\n anchor.setAttribute('href', matchedAnchor.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.append(anchor);\n }\n }\n};\n\nconst removeDuplicateIds = (headings: HTMLHeadingElement[], anchors: HTMLAnchorElement[]) => {\n for (let i = 0; i < anchors.length; i++) {\n const anchor = anchors[i];\n const id = anchor.textContent;\n const hash = anchor.hash;\n const matchedHeadings = 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 for (let j = 0; j < matchedHeadings.length; j++) {\n const heading = matchedHeadings[j];\n const heading_id = `${heading.id}-${count}`;\n\n // search duplicate list\n for (let k = 0; k < anchors.length; k++) {\n const anchor = anchors[k];\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 generateHierarchyList = (\n headings: HTMLHeadingElement[],\n elementContainer: HTMLUListElement | HTMLOListElement,\n isConvertToWikipediaStyleAnchor: boolean,\n) => {\n let number = 0;\n const elementListClone = createElement('li');\n const elementAnchorClone = createElement('a');\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const currentNumber = Number(heading.tagName[1]);\n\n // check list hierarchy\n if (number !== 0 && number < currentNumber) {\n // number of the heading is large (small as heading)\n const nextElementOListClone = createElement('ol');\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n elementContainer.lastChild.append(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 elementContainer = elementContainer.parentNode?.parentNode as HTMLUListElement | HTMLOListElement;\n }\n }\n }\n\n const textContent = censorshipId(headings, heading.textContent || '');\n\n // headingへidを付与\n const anchorText = generateAnchorText(textContent, isConvertToWikipediaStyleAnchor);\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.append(elementAnchor);\n\n elementContainer.append(elementList);\n\n // upadte current number\n number = currentNumber;\n }\n};\n\nexport const Mokuji = (\n element: HTMLElement | null,\n externalOptions?: MokujiOption,\n): HTMLUListElement | HTMLOListElement | undefined => {\n if (!element) {\n return;\n }\n\n // Merge the default options with the external options.\n const options = {\n ...defaultOptions,\n ...externalOptions,\n };\n\n const headings = [...getHeadingsElement(element)];\n\n if (headings.length === 0) {\n return;\n }\n\n // mokuji start\n const elementContainer = createElement(options.anchorContainerTagName);\n\n // generate mokuji list\n generateHierarchyList(headings, elementContainer, options.anchorType);\n\n const anchors = [...elementContainer.querySelectorAll('a')];\n\n if (anchors.length === 0) {\n return;\n }\n\n // remove duplicates by adding suffix\n removeDuplicateIds(headings, anchors);\n\n // setup anchor link\n if (options.anchorLink) {\n const anchorsMap = generateAnchorsMap(anchors);\n insertAnchorToHeadings(headings, anchorsMap, options);\n }\n\n return elementContainer;\n};\n\n// [data-mokuji-anchor]要素をすべて破棄する\nexport const destory = () => {\n const mokujiAnchor = document.querySelectorAll(`[${ANCHOR_DATASET_ATTRIBUTE}]`);\n for (let i = mokujiAnchor.length - 1; i >= 0; i--) {\n const element = mokujiAnchor[i];\n element.remove();\n }\n};\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
type AnchorContainerTagNameProps = 'ul' | 'ol';
|
|
2
|
-
|
|
2
|
+
type MokujiOption = {
|
|
3
3
|
anchorType?: boolean;
|
|
4
4
|
anchorLink?: boolean;
|
|
5
5
|
anchorLinkSymbol?: string;
|
|
@@ -7,5 +7,8 @@ export type MokujiOption = {
|
|
|
7
7
|
anchorLinkClassName?: string;
|
|
8
8
|
anchorContainerTagName?: AnchorContainerTagNameProps;
|
|
9
9
|
};
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
|
|
11
|
+
declare const Mokuji: (element: HTMLElement | null, externalOptions?: MokujiOption) => HTMLUListElement | HTMLOListElement | undefined;
|
|
12
|
+
declare const destory: () => void;
|
|
13
|
+
|
|
14
|
+
export { Mokuji, MokujiOption, destory };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
var g=(t,n)=>!t||!n?!1:n.contains(t),u=t=>t.querySelectorAll("h1, h2, h3, h4, h5, h6"),h=t=>document.createElement(t);var L=new Set,E=t=>t.replaceAll(/\s+/g,"_"),A=t=>encodeURIComponent(t).replaceAll(/%+/g,"."),T=(t,n="")=>{let e=n,o=1;for(;o<=t.length;){let r=o===1?e:`${e}_${o}`;if(!L.has(r)){e=r,L.add(e);break}o++;}return e},M=(t,n)=>{let e=E(t);return e=e.replaceAll(/&+/g,"").replaceAll(/&+/g,""),n&&(e=A(e)),e};var H="data-mokuji-anchor",k={anchorType:!0,anchorLink:!1,anchorLinkSymbol:"#",anchorLinkBefore:!0,anchorLinkClassName:"",anchorContainerTagName:"ol"},N=t=>{let n=new Map;for(let e=0;e<t.length;e++){let o=t[e].hash.replace("#","");n.set(o,t[e]);}return n},x=(t,n,e)=>{let o=h("a");o.setAttribute(H,""),e.anchorLinkClassName&&o.classList.add(e.anchorLinkClassName);for(let r=0;r<t.length;r++){let c=t[r],l=n.get(c.id);if(!l)continue;let s=o.cloneNode(!1);s.setAttribute("href",l.hash),e.anchorLinkSymbol&&(s.textContent=e.anchorLinkSymbol),e.anchorLinkBefore?c.insertBefore(s,c.firstChild):c.append(s);}},y=(t,n)=>{for(let e=0;e<n.length;e++){let o=n[e],r=o.textContent,c=o.hash,l=t.filter(a=>a.id===r);if(l.length===1)continue;let s=0;for(let a=0;a<l.length;a++){let f=l[a],d=`${f.id}-${s}`;for(let i=0;i<n.length;i++){let m=n[i];if(m.hash===c){m.href=`#${d}`;break}}f.id=d,s++;}}},C=(t,n,e)=>{let o=0,r=h("li"),c=h("a");for(let l=0;l<t.length;l++){let s=t[l],a=Number(s.tagName[1]);if(o!==0&&o<a){let p=h("ol");n.lastChild.append(p),n=p;}else if(o!==0&&o>a)for(let p=0;p<o-a;p++)g(n,n.parentNode)&&(n=n.parentNode?.parentNode);let f=T(t,s.textContent||""),d=M(f,e);s.id=d;let i=c.cloneNode(!1);i.href=`#${d}`,i.textContent=s.textContent;let m=r.cloneNode(!1);m.append(i),n.append(m),o=a;}},I=(t,n)=>{if(!t)return;let e={...k,...n},o=[...u(t)];if(o.length===0)return;let r=h(e.anchorContainerTagName);C(o,r,e.anchorType);let c=[...r.querySelectorAll("a")];if(c.length!==0){if(y(o,c),e.anchorLink){let l=N(c);x(o,l,e);}return r}},_=()=>{let t=document.querySelectorAll(`[${H}]`);for(let n=t.length-1;n>=0;n--)t[n].remove();};
|
|
2
|
+
|
|
3
|
+
export { I as Mokuji, _ as destory };
|
|
4
|
+
//# sourceMappingURL=out.js.map
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dom.ts","../src/text.ts","../src/index.ts"],"names":["hasParentNode","element","parent","getHeadingsElement","createElement","tagName","storeIds","replaceSpacesWithUnderscores","text","convert2WikipediaStyleAnchor","anchor","censorshipId","headings","textContent","id","suffix_count","tmp_id","generateAnchorText","isConvertToWikipediaStyleAnchor","ANCHOR_DATASET_ATTRIBUTE","defaultOptions","generateAnchorsMap","anchors","anchorMap","i","anchorId","insertAnchorToHeadings","options","a","heading","matchedAnchor","removeDuplicateIds","hash","matchedHeadings","count","j","heading_id","k","generateHierarchyList","elementContainer","number","elementListClone","elementAnchorClone","currentNumber","nextElementOListClone","anchorText","elementAnchor","elementList","Mokuji","externalOptions","anchorsMap","destory","mokujiAnchor"],"mappings":"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","sourcesContent":["/**\n * 親要素内に要素が存在するか判定する\n */\nexport const hasParentNode = (element: Node | null, parent: Node | null) => {\n if (!element || !parent) {\n return false;\n }\n\n return parent.contains(element);\n};\n\n/**\n * 見出し要素をすべて取得する\n */\nexport const getHeadingsElement = (element: Element) => {\n return element.querySelectorAll<HTMLHeadingElement>('h1, h2, h3, h4, h5, h6');\n};\n\n/**\n * 要素を作成する\n */\nexport const createElement = <T extends keyof HTMLElementTagNameMap>(tagName: T): HTMLElementTagNameMap[T] => {\n return document.createElement(tagName);\n};\n","const storeIds = new Set<string>();\n\nconst replaceSpacesWithUnderscores = (text: string) => {\n return text.replaceAll(/\\s+/g, '_');\n};\n\nconst convert2WikipediaStyleAnchor = (anchor: string) => {\n return encodeURIComponent(anchor).replaceAll(/%+/g, '.');\n};\n\nexport const censorshipId = (headings: HTMLHeadingElement[], textContent = '') => {\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.has(tmp_id)) {\n id = tmp_id;\n storeIds.add(id);\n break;\n }\n\n suffix_count++;\n }\n\n return id;\n};\n\nexport const generateAnchorText = (text: string, isConvertToWikipediaStyleAnchor: boolean) => {\n // convert spaces to _\n let anchor = replaceSpacesWithUnderscores(text);\n\n // remove &\n anchor = anchor.replaceAll(/&+/g, '').replaceAll(/&+/g, '');\n\n if (isConvertToWikipediaStyleAnchor) {\n anchor = convert2WikipediaStyleAnchor(anchor);\n }\n\n return anchor;\n};\n","import { hasParentNode, getHeadingsElement, createElement } from './dom';\nimport type { MokujiOption } from './types';\nimport { censorshipId, generateAnchorText } from './text';\n\nexport { MokujiOption };\n\nconst ANCHOR_DATASET_ATTRIBUTE = 'data-mokuji-anchor';\n\nconst defaultOptions = {\n anchorType: true,\n anchorLink: false,\n anchorLinkSymbol: '#',\n anchorLinkBefore: true,\n anchorLinkClassName: '',\n anchorContainerTagName: 'ol',\n} as const;\n\nconst generateAnchorsMap = (anchors: HTMLAnchorElement[]) => {\n const anchorMap = new Map<string, HTMLAnchorElement>();\n\n for (let i = 0; i < anchors.length; i++) {\n const anchorId = anchors[i].hash.replace('#', '');\n anchorMap.set(anchorId, anchors[i]);\n }\n\n return anchorMap;\n};\n\nconst insertAnchorToHeadings = (\n headings: HTMLHeadingElement[],\n anchorMap: Map<string, HTMLAnchorElement>,\n options: MokujiOption,\n) => {\n const a = createElement('a');\n a.setAttribute(ANCHOR_DATASET_ATTRIBUTE, '');\n\n if (options.anchorLinkClassName) {\n a.classList.add(options.anchorLinkClassName);\n }\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const matchedAnchor = anchorMap.get(heading.id);\n\n if (!matchedAnchor) {\n continue;\n }\n\n // create anchor\n const anchor = a.cloneNode(false) as HTMLAnchorElement;\n anchor.setAttribute('href', matchedAnchor.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.append(anchor);\n }\n }\n};\n\nconst removeDuplicateIds = (headings: HTMLHeadingElement[], anchors: HTMLAnchorElement[]) => {\n for (let i = 0; i < anchors.length; i++) {\n const anchor = anchors[i];\n const id = anchor.textContent;\n const hash = anchor.hash;\n const matchedHeadings = 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 for (let j = 0; j < matchedHeadings.length; j++) {\n const heading = matchedHeadings[j];\n const heading_id = `${heading.id}-${count}`;\n\n // search duplicate list\n for (let k = 0; k < anchors.length; k++) {\n const anchor = anchors[k];\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 generateHierarchyList = (\n headings: HTMLHeadingElement[],\n elementContainer: HTMLUListElement | HTMLOListElement,\n isConvertToWikipediaStyleAnchor: boolean,\n) => {\n let number = 0;\n const elementListClone = createElement('li');\n const elementAnchorClone = createElement('a');\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const currentNumber = Number(heading.tagName[1]);\n\n // check list hierarchy\n if (number !== 0 && number < currentNumber) {\n // number of the heading is large (small as heading)\n const nextElementOListClone = createElement('ol');\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n elementContainer.lastChild.append(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 elementContainer = elementContainer.parentNode?.parentNode as HTMLUListElement | HTMLOListElement;\n }\n }\n }\n\n const textContent = censorshipId(headings, heading.textContent || '');\n\n // headingへidを付与\n const anchorText = generateAnchorText(textContent, isConvertToWikipediaStyleAnchor);\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.append(elementAnchor);\n\n elementContainer.append(elementList);\n\n // upadte current number\n number = currentNumber;\n }\n};\n\nexport const Mokuji = (\n element: HTMLElement | null,\n externalOptions?: MokujiOption,\n): HTMLUListElement | HTMLOListElement | undefined => {\n if (!element) {\n return;\n }\n\n // Merge the default options with the external options.\n const options = {\n ...defaultOptions,\n ...externalOptions,\n };\n\n const headings = [...getHeadingsElement(element)];\n\n if (headings.length === 0) {\n return;\n }\n\n // mokuji start\n const elementContainer = createElement(options.anchorContainerTagName);\n\n // generate mokuji list\n generateHierarchyList(headings, elementContainer, options.anchorType);\n\n const anchors = [...elementContainer.querySelectorAll('a')];\n\n if (anchors.length === 0) {\n return;\n }\n\n // remove duplicates by adding suffix\n removeDuplicateIds(headings, anchors);\n\n // setup anchor link\n if (options.anchorLink) {\n const anchorsMap = generateAnchorsMap(anchors);\n insertAnchorToHeadings(headings, anchorsMap, options);\n }\n\n return elementContainer;\n};\n\n// [data-mokuji-anchor]要素をすべて破棄する\nexport const destory = () => {\n const mokujiAnchor = document.querySelectorAll(`[${ANCHOR_DATASET_ATTRIBUTE}]`);\n for (let i = mokujiAnchor.length - 1; i >= 0; i--) {\n const element = mokujiAnchor[i];\n element.remove();\n }\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,33 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mokuji.js",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.0",
|
|
4
4
|
"description": "A table of content JavaScript Library",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"build": "
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"prepare": "npm run clean && npm run build && husky install"
|
|
6
|
+
"build": "tsup",
|
|
7
|
+
"dev": "tsup --watch",
|
|
8
|
+
"lint": "eslint --cache ./src/**/*.ts",
|
|
9
|
+
"prepare": "npm run build && husky install"
|
|
11
10
|
},
|
|
12
|
-
"
|
|
13
|
-
"main": "dist/
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
"type": "module",
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"exports": {
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"require": "./dist/index.cjs",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
18
19
|
"directories": {
|
|
19
20
|
"lib": "lib"
|
|
20
21
|
},
|
|
21
22
|
"files": [
|
|
22
|
-
"dist
|
|
23
|
-
"lib/",
|
|
24
|
-
"src/",
|
|
23
|
+
"dist",
|
|
25
24
|
"LICENSE",
|
|
25
|
+
"package.json",
|
|
26
26
|
"READNME.md"
|
|
27
27
|
],
|
|
28
28
|
"lint-staged": {
|
|
29
|
-
"*.{js,ts}": [
|
|
30
|
-
"
|
|
29
|
+
"*.{js,ts,tsx}": [
|
|
30
|
+
"eslint --fix --cache",
|
|
31
|
+
"eslint --cache",
|
|
32
|
+
"prettier --write --cache"
|
|
33
|
+
],
|
|
34
|
+
"*.{ts,tsx}": [
|
|
35
|
+
"bash -c 'tsc --noEmit --skipLibCheck'"
|
|
31
36
|
]
|
|
32
37
|
},
|
|
33
38
|
"repository": {
|
|
@@ -47,13 +52,15 @@
|
|
|
47
52
|
},
|
|
48
53
|
"homepage": "https://github.com/hiro0218/mokuji.js",
|
|
49
54
|
"devDependencies": {
|
|
50
|
-
"@types/node": "~
|
|
55
|
+
"@types/node": "~20.2.3",
|
|
56
|
+
"@typescript-eslint/eslint-plugin": "^5.59.7",
|
|
57
|
+
"eslint": "^8.41.0",
|
|
58
|
+
"eslint-config-prettier": "^8.8.0",
|
|
59
|
+
"eslint-plugin-unicorn": "^47.0.0",
|
|
51
60
|
"husky": "^8.0.3",
|
|
52
|
-
"lint-staged": "^13.
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
},
|
|
58
|
-
"dependencies": {}
|
|
61
|
+
"lint-staged": "^13.2.2",
|
|
62
|
+
"prettier": "^2.8.8",
|
|
63
|
+
"tsup": "^6.7.0",
|
|
64
|
+
"typescript": "~5.0.4"
|
|
65
|
+
}
|
|
59
66
|
}
|
package/dist/dom.d.ts
DELETED
package/dist/mokuji.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
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(!r.includes(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 Array.from(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"),l=0;l<n.length;l++){var h=n[l],f=Number(h.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,h.textContent),C=v.replace(/\s+/g,"_")).replace(/\&+/g,"").replace(/\&+/g,""),!0===g&&(C=function(e){return encodeURIComponent(e).replace(/\%+/g,".")}(C)),C);h.id=m;var s=c.cloneNode(!1);s.href="#"+m,s.textContent=h.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=Array.from(n.getElementsByTagName("a")),a=function(n){var a=r[n].textContent,t=r[n].hash,o=e.filter(function(e){return e.id===a});if(1===o.length)return"continue";for(var i=0,c=0;c<o.length;c++){for(var l=o[c],h=l.id+"-"+i,f=0;f<r.length;f++){var u=r[f];if(u.hash===t){u.href="#"+h;break}}l.id=h,i++}},t=0;t<r.length;t++)a(t)}(i,c),o.anchorLink&&function(e,n,r){if(n){var a=document.createElement("a");a.setAttribute("data-mokuji-anchor",""),r.anchorLinkClassName&&a.classList.add(r.anchorLinkClassName);for(var t=0;t<e.length;t++)for(var o=e[t],i=o.id,c=0;c<n.length;c++){var l=n[c].hash;if(l.replace("#","")===i){var h=a.cloneNode(!1);h.setAttribute("href",l),r.anchorLinkSymbol&&(h.textContent=r.anchorLinkSymbol),r.anchorLinkBefore?o.insertBefore(h,o.firstChild):o.appendChild(h)}}}}(i,Array.from(c.querySelectorAll("a")),o),c}};
|
|
2
|
-
//# sourceMappingURL=mokuji.js.map
|
package/dist/mokuji.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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): HTMLHeadingElement[] => {\n return Array.from(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: HTMLHeadingElement[],\n anchors: HTMLAnchorElement[] | undefined,\n options: MokujiOption,\n) => {\n if (!anchors) return;\n\n const a = document.createElement('a');\n a.setAttribute('data-mokuji-anchor', '');\n\n if (options.anchorLinkClassName) {\n a.classList.add(options.anchorLinkClassName);\n }\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const { id } = heading;\n\n for (let j = 0; j < anchors.length; j++) {\n const { hash } = anchors[j];\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: HTMLHeadingElement[], elementContainer: HTMLElement) => {\n const anchors = Array.from(elementContainer.getElementsByTagName('a'));\n\n for (let i = 0; i < anchors.length; i++) {\n const id = anchors[i].textContent;\n const hash = anchors[i].hash;\n const matchedHeadings = 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 for (let j = 0; j < matchedHeadings.length; j++) {\n const heading = matchedHeadings[j];\n const heading_id = `${heading.id}-${count}`;\n\n // search duplicate list\n for (let k = 0; k < anchors.length; k++) {\n const anchor = anchors[k];\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: 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.includes(tmp_id)) {\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: 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 = (\n element: HTMLElement | null,\n externalOptions?: MokujiOption,\n): HTMLUListElement | 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 ) as HTMLUListElement | HTMLOListElement;\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 = Array.from(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 return encodeURIComponent(anchor).replace(/\\%+/g, '.');\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","includes","push","externalOptions","options","Object","assign","Array","from","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","hash","matchedHeadings","filter","count","j","heading_id","k","removeDuplicateIds","a","setAttribute","classList","add","insertBefore","firstChild","renderAnchorLink"],"mappings":"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"}
|
package/dist/mokuji.modern.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=(e,t)=>{for(;e;){if(e===t)return!0;e=e.parentNode}return!1},t={anchorType:!0,anchorLink:!1,anchorLinkSymbol:"#",anchorLinkBefore:!0,anchorLinkClassName:"",anchorContainerTagName:"ol"},n=[],o=(e,t)=>{let o=t||"",r=1;for(;r<=e.length;){const e=1===r?o:`${o}_${r}`;if(!n.includes(e)){o=e,n.push(o);break}r++}return o},r=(e,t)=>{let n=(e=>e.replace(/\s+/g,"_"))(e);return n=n.replace(/\&+/g,"").replace(/\&+/g,""),!0===t&&(n=(e=>encodeURIComponent(e).replace(/\%+/g,"."))(n)),n},a=(n,a)=>{if(!n)return;const c=Object.assign(t,a),l=(e=>Array.from(e.querySelectorAll("h1, h2, h3, h4, h5, h6")))(n),h=document.createElement(c.anchorContainerTagName||t.anchorContainerTagName);return((t,n,a)=>{let c=0;const l=document.createElement("li"),h=document.createElement("a");for(let i=0;i<t.length;i++){const s=t[i],d=Number(s.tagName.substring(1));if(0!==c&&c<d){const e=document.createElement("ol");n.lastChild.appendChild(e),n=e}else if(0!==c&&c>d)for(let t=0;t<c-d;t++)e(n,n.parentNode)&&(n=n.parentNode.parentNode);const f=o(t,s.textContent),m=r(f,a);s.id=m;const p=h.cloneNode(!1);p.href=`#${m}`,p.textContent=s.textContent;const u=l.cloneNode(!1);u.appendChild(p),n.appendChild(u),c=d}})(l,h,!!c.anchorType),((e,t)=>{const n=Array.from(t.getElementsByTagName("a"));for(let t=0;t<n.length;t++){const o=n[t].textContent,r=n[t].hash,a=e.filter(e=>e.id===o);if(1===a.length)continue;let c=0;for(let e=0;e<a.length;e++){const t=a[e],o=`${t.id}-${c}`;for(let e=0;e<n.length;e++){const t=n[e];if(t.hash===r){t.href=`#${o}`;break}}t.id=o,c++}}})(l,h),c.anchorLink&&((e,t,n)=>{if(!t)return;const o=document.createElement("a");o.setAttribute("data-mokuji-anchor",""),n.anchorLinkClassName&&o.classList.add(n.anchorLinkClassName);for(let r=0;r<e.length;r++){const a=e[r],{id:c}=a;for(let e=0;e<t.length;e++){const{hash:r}=t[e];if(r.replace("#","")!==c)continue;const l=o.cloneNode(!1);l.setAttribute("href",r),n.anchorLinkSymbol&&(l.textContent=n.anchorLinkSymbol),n.anchorLinkBefore?a.insertBefore(l,a.firstChild):a.appendChild(l)}}})(l,Array.from(h.querySelectorAll("a")),c),h};export{a as Mokuji};
|
|
2
|
-
//# sourceMappingURL=mokuji.modern.js.map
|
|
@@ -1 +0,0 @@
|
|
|
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): HTMLHeadingElement[] => {\n return Array.from(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: HTMLHeadingElement[],\n anchors: HTMLAnchorElement[] | undefined,\n options: MokujiOption,\n) => {\n if (!anchors) return;\n\n const a = document.createElement('a');\n a.setAttribute('data-mokuji-anchor', '');\n\n if (options.anchorLinkClassName) {\n a.classList.add(options.anchorLinkClassName);\n }\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const { id } = heading;\n\n for (let j = 0; j < anchors.length; j++) {\n const { hash } = anchors[j];\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: HTMLHeadingElement[], elementContainer: HTMLElement) => {\n const anchors = Array.from(elementContainer.getElementsByTagName('a'));\n\n for (let i = 0; i < anchors.length; i++) {\n const id = anchors[i].textContent;\n const hash = anchors[i].hash;\n const matchedHeadings = 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 for (let j = 0; j < matchedHeadings.length; j++) {\n const heading = matchedHeadings[j];\n const heading_id = `${heading.id}-${count}`;\n\n // search duplicate list\n for (let k = 0; k < anchors.length; k++) {\n const anchor = anchors[k];\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: 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.includes(tmp_id)) {\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: 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 = (\n element: HTMLElement | null,\n externalOptions?: MokujiOption,\n): HTMLUListElement | 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 ) as HTMLUListElement | HTMLOListElement;\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 = Array.from(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 return encodeURIComponent(anchor).replace(/\\%+/g, '.');\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","includes","push","generateAnchorText","text","type","anchor","replace","replaceSpace2Underscore","encodeURIComponent","convert2WikipediaStyleAnchor","Mokuji","externalOptions","options","Object","assign","Array","from","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","hash","matchedHeadings","filter","count","j","heading_id","k","removeDuplicateIds","a","setAttribute","classList","add","insertBefore","firstChild","renderAnchorLink"],"mappings":"MAAaA,EAAgB,CAACC,EAAsBC,KAClD,KAAOD,GAAS,CACd,GAAIA,IAAYC,EACd,SAEFD,EAAUA,EAAQE,UACnB,CACD,UCOIC,EAAiB,CACrBC,YAAY,EACZC,YAAY,EACZC,iBAAkB,IAClBC,kBAAkB,EAClBC,oBAAqB,GACrBC,uBAAwB,MAGpBC,EAAqB,GAmFrBC,EAAe,CAACC,EAAgCC,KACpD,IAAIC,EAAKD,GAAe,GACpBE,EAAe,EAGnB,KAAOA,GAAgBH,EAASI,QAAQ,CACtC,MAAMC,EAA0B,IAAjBF,EAAqBD,KAAQA,KAAMC,IAElD,IAAKL,EAASQ,SAASD,GAAS,CAC9BH,EAAKG,EACLP,EAASS,KAAKL,GACd,KACD,CAEDC,GACD,CAED,OAAOD,GAGHM,EAAqB,CAACC,EAAcC,KAExC,IAAIC,EChIkCF,IAC/BA,EAAKG,QAAQ,OAAQ,KD+HfC,CAAwBJ,GASrC,OANAE,EAASA,EAAOC,QAAQ,OAAQ,IAAIA,QAAQ,WAAY,KAE3C,IAATF,IACFC,EClIyCA,IACpCG,mBAAmBH,GAAQC,QAAQ,OAAQ,KDiIvCG,CAA6BJ,IAGjCA,GAqDIK,EAAS,CACpB5B,EACA6B,KAEA,IAAK7B,EACH,OAIF,MAAM8B,EAAUC,OAAOC,OAErB7B,EACA0B,GAGIjB,ED3L2BZ,IAC1BiC,MAAMC,KAAKlC,EAAQmC,iBAAiB,2BC0L1BC,CAAmBpC,GAG9BqC,EAAmBC,SAASC,cAChCT,EAAQrB,wBAA0BN,EAAeM,wBAenD,MApF4B,EAC5BG,EACAyB,EACAjC,KAEA,IAAIoC,EAAS,EACb,MAAMC,EAAmBH,SAASC,cAAc,MAC1CG,EAAqBJ,SAASC,cAAc,KAElD,IAAK,IAAII,EAAI,EAAGA,EAAI/B,EAASI,OAAQ2B,IAAK,CACxC,MAAMC,EAAUhC,EAAS+B,GACnBE,EC9IDC,OD8I0CF,EAAQG,QC9InCC,UAAU,IDiJ9B,GAAe,IAAXR,GAAgBA,EAASK,EAAe,CAE1C,MAAMI,EAAwBX,SAASC,cAAc,MAErDF,EAAiBa,UAAUC,YAAYF,GACvCZ,EAAmBY,CACpB,SAAqB,IAAXT,GAAgBA,EAASK,EAElC,IAAK,IAAIF,EAAI,EAAGA,EAAIH,EAASK,EAAeF,IACtC5C,EAAcsC,EAAkBA,EAAiBnC,cAEnDmC,EAAmBA,EAAiBnC,WAAWA,YAKrD,MAAMW,EAAcF,EAAaC,EAAUgC,EAAQ/B,aAG7CuC,EAAahC,EAAmBP,EAAaT,GACnDwC,EAAQ9B,GAAKsC,EAGb,MAAMC,EAAgBX,EAAmBY,WAAU,GACnDD,EAAcE,SAAWH,IACzBC,EAAcxC,YAAc+B,EAAQ/B,YACpC,MAAM2C,EAAcf,EAAiBa,WAAU,GAC/CE,EAAYL,YAAYE,GAExBhB,EAAiBc,YAAYK,GAG7BhB,EAASK,CACV,GA0BDY,CAAsB7C,EAAUyB,IAAoBP,EAAQ1B,YA/InC,EAACQ,EAAgCyB,KAC1D,MAAMqB,EAAUzB,MAAMC,KAAKG,EAAiBsB,qBAAqB,MAEjE,IAAK,IAAIhB,EAAI,EAAGA,EAAIe,EAAQ1C,OAAQ2B,IAAK,CACvC,MAAM7B,EAAK4C,EAAQf,GAAG9B,YAChB+C,EAAOF,EAAQf,GAAGiB,KAClBC,EAAkBjD,EAASkD,OAAQlB,GAAYA,EAAQ9B,KAAOA,GAEpE,GAA+B,IAA3B+C,EAAgB7C,OAClB,SAIF,IAAI+C,EAAQ,EAEZ,IAAK,IAAIC,EAAI,EAAGA,EAAIH,EAAgB7C,OAAQgD,IAAK,CAC/C,MAAMpB,EAAUiB,EAAgBG,GAC1BC,KAAgBrB,EAAQ9B,MAAMiD,IAGpC,IAAK,IAAIG,EAAI,EAAGA,EAAIR,EAAQ1C,OAAQkD,IAAK,CACvC,MAAM3C,EAASmC,EAAQQ,GACvB,GAAI3C,EAAOqC,OAASA,EAAM,CAExBrC,EAAOgC,SAAWU,IAClB,KACD,CACF,CAGDrB,EAAQ9B,GAAKmD,EACbF,GACD,CACF,GAiHDI,CAAmBvD,EAAUyB,GAGzBP,EAAQzB,YAlMW,EACvBO,EACA8C,EACA5B,KAEA,IAAK4B,EAAS,OAEd,MAAMU,EAAI9B,SAASC,cAAc,KACjC6B,EAAEC,aAAa,qBAAsB,IAEjCvC,EAAQtB,qBACV4D,EAAEE,UAAUC,IAAIzC,EAAQtB,qBAG1B,IAAK,IAAImC,EAAI,EAAGA,EAAI/B,EAASI,OAAQ2B,IAAK,CACxC,MAAMC,EAAUhC,EAAS+B,IACnB7B,GAAEA,GAAO8B,EAEf,IAAK,IAAIoB,EAAI,EAAGA,EAAIN,EAAQ1C,OAAQgD,IAAK,CACvC,MAAMJ,KAAEA,GAASF,EAAQM,GAEzB,GAAIJ,EAAKpC,QAAQ,IAAK,MAAQV,EAC5B,SAIF,MAAMS,EAAS6C,EAAEd,WAAU,GAC3B/B,EAAO8C,aAAa,OAAQT,GAExB9B,EAAQxB,mBACViB,EAAOV,YAAciB,EAAQxB,kBAI3BwB,EAAQvB,iBAEVqC,EAAQ4B,aAAajD,EAAQqB,EAAQ6B,YAGrC7B,EAAQO,YAAY5B,EAEvB,CACF,GA0JCmD,CAAiB9D,EADDqB,MAAMC,KAAKG,EAAiBF,iBAAiB,MACzBL,GAG/BO"}
|
package/dist/mokuji.module.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
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(!r.includes(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 Array.from(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"),l=0;l<n.length;l++){var h=n[l],f=Number(h.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,h.textContent),C=v.replace(/\s+/g,"_")).replace(/\&+/g,"").replace(/\&+/g,""),!0===g&&(C=function(e){return encodeURIComponent(e).replace(/\%+/g,".")}(C)),C);h.id=m;var s=c.cloneNode(!1);s.href="#"+m,s.textContent=h.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=Array.from(n.getElementsByTagName("a")),a=function(n){var a=r[n].textContent,t=r[n].hash,o=e.filter(function(e){return e.id===a});if(1===o.length)return"continue";for(var i=0,c=0;c<o.length;c++){for(var l=o[c],h=l.id+"-"+i,f=0;f<r.length;f++){var d=r[f];if(d.hash===t){d.href="#"+h;break}}l.id=h,i++}},t=0;t<r.length;t++)a(t)}(i,c),o.anchorLink&&function(e,n,r){if(n){var a=document.createElement("a");a.setAttribute("data-mokuji-anchor",""),r.anchorLinkClassName&&a.classList.add(r.anchorLinkClassName);for(var t=0;t<e.length;t++)for(var o=e[t],i=o.id,c=0;c<n.length;c++){var l=n[c].hash;if(l.replace("#","")===i){var h=a.cloneNode(!1);h.setAttribute("href",l),r.anchorLinkSymbol&&(h.textContent=r.anchorLinkSymbol),r.anchorLinkBefore?o.insertBefore(h,o.firstChild):o.appendChild(h)}}}}(i,Array.from(c.querySelectorAll("a")),o),c}};export{t as Mokuji};
|
|
2
|
-
//# sourceMappingURL=mokuji.module.js.map
|
|
@@ -1 +0,0 @@
|
|
|
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): HTMLHeadingElement[] => {\n return Array.from(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: HTMLHeadingElement[],\n anchors: HTMLAnchorElement[] | undefined,\n options: MokujiOption,\n) => {\n if (!anchors) return;\n\n const a = document.createElement('a');\n a.setAttribute('data-mokuji-anchor', '');\n\n if (options.anchorLinkClassName) {\n a.classList.add(options.anchorLinkClassName);\n }\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const { id } = heading;\n\n for (let j = 0; j < anchors.length; j++) {\n const { hash } = anchors[j];\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: HTMLHeadingElement[], elementContainer: HTMLElement) => {\n const anchors = Array.from(elementContainer.getElementsByTagName('a'));\n\n for (let i = 0; i < anchors.length; i++) {\n const id = anchors[i].textContent;\n const hash = anchors[i].hash;\n const matchedHeadings = 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 for (let j = 0; j < matchedHeadings.length; j++) {\n const heading = matchedHeadings[j];\n const heading_id = `${heading.id}-${count}`;\n\n // search duplicate list\n for (let k = 0; k < anchors.length; k++) {\n const anchor = anchors[k];\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: 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.includes(tmp_id)) {\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: 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 = (\n element: HTMLElement | null,\n externalOptions?: MokujiOption,\n): HTMLUListElement | 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 ) as HTMLUListElement | HTMLOListElement;\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 = Array.from(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 return encodeURIComponent(anchor).replace(/\\%+/g, '.');\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","includes","push","Mokuji","externalOptions","options","Object","assign","Array","from","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","hash","matchedHeadings","filter","count","j","heading_id","k","removeDuplicateIds","a","setAttribute","classList","add","insertBefore","firstChild","renderAnchorLink"],"mappings":"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"}
|
package/dist/mokuji.umd.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
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(!t.includes(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 Array.from(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"),l=0;l<e.length;l++){var f=e[l],h=Number(f.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,f.textContent),C=v.replace(/\s+/g,"_")).replace(/\&+/g,"").replace(/\&+/g,""),!0===g&&(C=function(e){return encodeURIComponent(e).replace(/\%+/g,".")}(C)),C);f.id=s;var m=c.cloneNode(!1);m.href="#"+s,m.textContent=f.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=Array.from(n.getElementsByTagName("a")),t=function(n){var t=r[n].textContent,a=r[n].hash,o=e.filter(function(e){return e.id===t});if(1===o.length)return"continue";for(var i=0,c=0;c<o.length;c++){for(var l=o[c],f=l.id+"-"+i,h=0;h<r.length;h++){var d=r[h];if(d.hash===a){d.href="#"+f;break}}l.id=f,i++}},a=0;a<r.length;a++)t(a)}(i,c),o.anchorLink&&function(e,n,r){if(n){var t=document.createElement("a");t.setAttribute("data-mokuji-anchor",""),r.anchorLinkClassName&&t.classList.add(r.anchorLinkClassName);for(var a=0;a<e.length;a++)for(var o=e[a],i=o.id,c=0;c<n.length;c++){var l=n[c].hash;if(l.replace("#","")===i){var f=t.cloneNode(!1);f.setAttribute("href",l),r.anchorLinkSymbol&&(f.textContent=r.anchorLinkSymbol),r.anchorLinkBefore?o.insertBefore(f,o.firstChild):o.appendChild(f)}}}}(i,Array.from(c.querySelectorAll("a")),o),c}}});
|
|
2
|
-
//# sourceMappingURL=mokuji.umd.js.map
|
package/dist/mokuji.umd.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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): HTMLHeadingElement[] => {\n return Array.from(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: HTMLHeadingElement[],\n anchors: HTMLAnchorElement[] | undefined,\n options: MokujiOption,\n) => {\n if (!anchors) return;\n\n const a = document.createElement('a');\n a.setAttribute('data-mokuji-anchor', '');\n\n if (options.anchorLinkClassName) {\n a.classList.add(options.anchorLinkClassName);\n }\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const { id } = heading;\n\n for (let j = 0; j < anchors.length; j++) {\n const { hash } = anchors[j];\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: HTMLHeadingElement[], elementContainer: HTMLElement) => {\n const anchors = Array.from(elementContainer.getElementsByTagName('a'));\n\n for (let i = 0; i < anchors.length; i++) {\n const id = anchors[i].textContent;\n const hash = anchors[i].hash;\n const matchedHeadings = 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 for (let j = 0; j < matchedHeadings.length; j++) {\n const heading = matchedHeadings[j];\n const heading_id = `${heading.id}-${count}`;\n\n // search duplicate list\n for (let k = 0; k < anchors.length; k++) {\n const anchor = anchors[k];\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: 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.includes(tmp_id)) {\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: 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 = (\n element: HTMLElement | null,\n externalOptions?: MokujiOption,\n): HTMLUListElement | 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 ) as HTMLUListElement | HTMLOListElement;\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 = Array.from(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 return encodeURIComponent(anchor).replace(/\\%+/g, '.');\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","includes","push","externalOptions","options","Object","assign","Array","from","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","hash","matchedHeadings","filter","count","j","heading_id","k","removeDuplicateIds","a","setAttribute","classList","add","insertBefore","firstChild","renderAnchorLink"],"mappings":"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"}
|
package/dist/utils.d.ts
DELETED
package/src/dom.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export const hasParentNode = (element: Node | null, parent: Node | null) => {
|
|
2
|
-
while (element) {
|
|
3
|
-
if (element === parent) {
|
|
4
|
-
return true;
|
|
5
|
-
}
|
|
6
|
-
element = element.parentNode;
|
|
7
|
-
}
|
|
8
|
-
return false;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export const reverseElement = (element: Node) => {
|
|
12
|
-
while (element.parentNode) {
|
|
13
|
-
element = element.parentNode;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return element;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export const getHeadingsElement = (element: Element): HTMLHeadingElement[] => {
|
|
20
|
-
return Array.from(element.querySelectorAll('h1, h2, h3, h4, h5, h6'));
|
|
21
|
-
};
|
package/src/index.ts
DELETED
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
import { hasParentNode, getHeadingsElement } from './dom';
|
|
2
|
-
import { replaceSpace2Underscore, convert2WikipediaStyleAnchor, getHeadingTagName2Number } from './utils';
|
|
3
|
-
|
|
4
|
-
type AnchorContainerTagNameProps = 'ul' | 'ol';
|
|
5
|
-
|
|
6
|
-
export type MokujiOption = {
|
|
7
|
-
anchorType?: boolean;
|
|
8
|
-
anchorLink?: boolean;
|
|
9
|
-
anchorLinkSymbol?: string;
|
|
10
|
-
anchorLinkBefore?: boolean;
|
|
11
|
-
anchorLinkClassName?: string;
|
|
12
|
-
anchorContainerTagName?: AnchorContainerTagNameProps;
|
|
13
|
-
};
|
|
14
|
-
|
|
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 = (
|
|
27
|
-
headings: HTMLHeadingElement[],
|
|
28
|
-
anchors: HTMLAnchorElement[] | undefined,
|
|
29
|
-
options: MokujiOption,
|
|
30
|
-
) => {
|
|
31
|
-
if (!anchors) return;
|
|
32
|
-
|
|
33
|
-
const a = document.createElement('a');
|
|
34
|
-
a.setAttribute('data-mokuji-anchor', '');
|
|
35
|
-
|
|
36
|
-
if (options.anchorLinkClassName) {
|
|
37
|
-
a.classList.add(options.anchorLinkClassName);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
for (let i = 0; i < headings.length; i++) {
|
|
41
|
-
const heading = headings[i];
|
|
42
|
-
const { id } = heading;
|
|
43
|
-
|
|
44
|
-
for (let j = 0; j < anchors.length; j++) {
|
|
45
|
-
const { hash } = anchors[j];
|
|
46
|
-
|
|
47
|
-
if (hash.replace('#', '') !== id) {
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// create anchor
|
|
52
|
-
const anchor = a.cloneNode(false) as HTMLAnchorElement;
|
|
53
|
-
anchor.setAttribute('href', hash);
|
|
54
|
-
|
|
55
|
-
if (options.anchorLinkSymbol) {
|
|
56
|
-
anchor.textContent = options.anchorLinkSymbol;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// insert anchor into headings
|
|
60
|
-
if (options.anchorLinkBefore) {
|
|
61
|
-
// before
|
|
62
|
-
heading.insertBefore(anchor, heading.firstChild);
|
|
63
|
-
} else {
|
|
64
|
-
// after
|
|
65
|
-
heading.appendChild(anchor);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const removeDuplicateIds = (headings: HTMLHeadingElement[], elementContainer: HTMLElement) => {
|
|
72
|
-
const anchors = Array.from(elementContainer.getElementsByTagName('a'));
|
|
73
|
-
|
|
74
|
-
for (let i = 0; i < anchors.length; i++) {
|
|
75
|
-
const id = anchors[i].textContent;
|
|
76
|
-
const hash = anchors[i].hash;
|
|
77
|
-
const matchedHeadings = headings.filter((heading) => heading.id === id);
|
|
78
|
-
|
|
79
|
-
if (matchedHeadings.length === 1) {
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// duplicated id
|
|
84
|
-
let count = 0;
|
|
85
|
-
|
|
86
|
-
for (let j = 0; j < matchedHeadings.length; j++) {
|
|
87
|
-
const heading = matchedHeadings[j];
|
|
88
|
-
const heading_id = `${heading.id}-${count}`;
|
|
89
|
-
|
|
90
|
-
// search duplicate list
|
|
91
|
-
for (let k = 0; k < anchors.length; k++) {
|
|
92
|
-
const anchor = anchors[k];
|
|
93
|
-
if (anchor.hash === hash) {
|
|
94
|
-
// update hash
|
|
95
|
-
anchor.href = `#${heading_id}`;
|
|
96
|
-
break;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// update id
|
|
101
|
-
heading.id = heading_id;
|
|
102
|
-
count++;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const censorshipId = (headings: HTMLHeadingElement[], textContent: string | null) => {
|
|
108
|
-
let id = textContent || '';
|
|
109
|
-
let suffix_count = 1;
|
|
110
|
-
|
|
111
|
-
// IDが重複していた場合はsuffixを付ける
|
|
112
|
-
while (suffix_count <= headings.length) {
|
|
113
|
-
const tmp_id = suffix_count === 1 ? id : `${id}_${suffix_count}`;
|
|
114
|
-
|
|
115
|
-
if (!storeIds.includes(tmp_id)) {
|
|
116
|
-
id = tmp_id;
|
|
117
|
-
storeIds.push(id);
|
|
118
|
-
break;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
suffix_count++;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return id;
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const generateAnchorText = (text: string, type: boolean) => {
|
|
128
|
-
// convert spaces to _
|
|
129
|
-
let anchor = replaceSpace2Underscore(text);
|
|
130
|
-
|
|
131
|
-
// remove &
|
|
132
|
-
anchor = anchor.replace(/\&+/g, '').replace(/\&+/g, '');
|
|
133
|
-
|
|
134
|
-
if (type === true) {
|
|
135
|
-
anchor = convert2WikipediaStyleAnchor(anchor);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return anchor;
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const generateHierarchyList = (
|
|
142
|
-
headings: HTMLHeadingElement[],
|
|
143
|
-
elementContainer: HTMLUListElement | HTMLOListElement,
|
|
144
|
-
anchorType: boolean,
|
|
145
|
-
) => {
|
|
146
|
-
let number = 0;
|
|
147
|
-
const elementListClone = document.createElement('li');
|
|
148
|
-
const elementAnchorClone = document.createElement('a');
|
|
149
|
-
|
|
150
|
-
for (let i = 0; i < headings.length; i++) {
|
|
151
|
-
const heading = headings[i];
|
|
152
|
-
const currentNumber = getHeadingTagName2Number(heading.tagName);
|
|
153
|
-
|
|
154
|
-
// check list hierarchy
|
|
155
|
-
if (number !== 0 && number < currentNumber) {
|
|
156
|
-
// number of the heading is large (small as heading)
|
|
157
|
-
const nextElementOListClone = document.createElement('ol');
|
|
158
|
-
// @ts-ignore
|
|
159
|
-
elementContainer.lastChild.appendChild(nextElementOListClone);
|
|
160
|
-
elementContainer = nextElementOListClone;
|
|
161
|
-
} else if (number !== 0 && number > currentNumber) {
|
|
162
|
-
// number of heading is small (large as heading)
|
|
163
|
-
for (let i = 0; i < number - currentNumber; i++) {
|
|
164
|
-
if (hasParentNode(elementContainer, elementContainer.parentNode)) {
|
|
165
|
-
// @ts-ignore
|
|
166
|
-
elementContainer = elementContainer.parentNode.parentNode;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const textContent = censorshipId(headings, heading.textContent);
|
|
172
|
-
|
|
173
|
-
// headingへidを付与
|
|
174
|
-
const anchorText = generateAnchorText(textContent, anchorType);
|
|
175
|
-
heading.id = anchorText;
|
|
176
|
-
|
|
177
|
-
// add to wrapper
|
|
178
|
-
const elementAnchor = elementAnchorClone.cloneNode(false) as HTMLAnchorElement;
|
|
179
|
-
elementAnchor.href = `#${anchorText}`;
|
|
180
|
-
elementAnchor.textContent = heading.textContent;
|
|
181
|
-
const elementList = elementListClone.cloneNode(false) as HTMLLIElement;
|
|
182
|
-
elementList.appendChild(elementAnchor);
|
|
183
|
-
|
|
184
|
-
elementContainer.appendChild(elementList);
|
|
185
|
-
|
|
186
|
-
// upadte current number
|
|
187
|
-
number = currentNumber;
|
|
188
|
-
}
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
export const Mokuji = (
|
|
192
|
-
element: HTMLElement | null,
|
|
193
|
-
externalOptions?: MokujiOption,
|
|
194
|
-
): HTMLUListElement | HTMLOListElement | undefined => {
|
|
195
|
-
if (!element) {
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Merge the default options with the external options.
|
|
200
|
-
const options = Object.assign(
|
|
201
|
-
// default options
|
|
202
|
-
defaultOptions,
|
|
203
|
-
externalOptions,
|
|
204
|
-
);
|
|
205
|
-
|
|
206
|
-
const headings = getHeadingsElement(element);
|
|
207
|
-
|
|
208
|
-
// mokuji start
|
|
209
|
-
const elementContainer = document.createElement(
|
|
210
|
-
options.anchorContainerTagName || defaultOptions.anchorContainerTagName,
|
|
211
|
-
) as HTMLUListElement | HTMLOListElement;
|
|
212
|
-
|
|
213
|
-
// generate mokuji list
|
|
214
|
-
generateHierarchyList(headings, elementContainer, !!options.anchorType);
|
|
215
|
-
|
|
216
|
-
// remove duplicates by adding suffix
|
|
217
|
-
removeDuplicateIds(headings, elementContainer);
|
|
218
|
-
|
|
219
|
-
// setup anchor link
|
|
220
|
-
if (options.anchorLink) {
|
|
221
|
-
const anchors = Array.from(elementContainer.querySelectorAll('a'));
|
|
222
|
-
renderAnchorLink(headings, anchors, options);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return elementContainer;
|
|
226
|
-
};
|
package/src/utils.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export const replaceSpace2Underscore = (text: string) => {
|
|
2
|
-
return text.replace(/\s+/g, '_');
|
|
3
|
-
};
|
|
4
|
-
|
|
5
|
-
export const convert2WikipediaStyleAnchor = (anchor: string) => {
|
|
6
|
-
return encodeURIComponent(anchor).replace(/\%+/g, '.');
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export const getHeadingTagName2Number = (tagName: string) => {
|
|
10
|
-
return Number(tagName.substring(1));
|
|
11
|
-
};
|