mokuji.js 4.1.0 → 4.2.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/dist/dom.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export declare const hasParentNode: (element: Node | null, parent: Node | null) => boolean;
2
2
  export declare const reverseElement: (element: Node) => Node;
3
- export declare const getHeadingsElement: (element: Element) => NodeListOf<HTMLHeadingElement>;
3
+ export declare const getHeadingsElement: (element: Element) => HTMLHeadingElement[];
package/dist/index.d.ts CHANGED
@@ -7,5 +7,5 @@ export declare type MokujiOption = {
7
7
  anchorLinkClassName?: string;
8
8
  anchorContainerTagName?: AnchorContainerTagNameProps;
9
9
  };
10
- export declare const Mokuji: (element: HTMLElement | null, externalOptions?: MokujiOption | undefined) => HTMLOListElement | undefined;
10
+ export declare const Mokuji: (element: HTMLElement | null, externalOptions?: MokujiOption) => HTMLUListElement | HTMLOListElement | undefined;
11
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={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(/\&amp;+/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");a.setAttribute("aria-hidden","true"),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}};
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 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(/\&amp;+/g,""),!0===g&&(C=function(e){return(e=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");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
2
  //# sourceMappingURL=mokuji.js.map
@@ -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\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 a.setAttribute('aria-hidden', 'true');\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(/\\&amp;+/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","setAttribute","classList","add","insertBefore","firstChild","renderAnchorLink"],"mappings":"IAAaA,EAAgB,SAACC,EAAsBC,GAClD,KAAOD,GAAS,CACd,GAAIA,IAAYC,EACd,SAEFD,EAAUA,EAAQE,WAEpB,UCOIC,EAAiB,CACrBC,YAAY,EACZC,YAAY,EACZC,iBAAkB,IAClBC,kBAAkB,EAClBC,oBAAqB,GACrBC,uBAAwB,MAGpBC,EAAqB,GAgFrBC,EAAe,SAACC,EAA0CC,GAK9D,IAJA,IAAIC,EAAKD,GAAe,GACpBE,EAAe,EAGZA,GAAgBH,EAASI,QAAQ,CACtC,IAAMC,EAA0B,IAAjBF,EAAqBD,EAAQA,MAAMC,EAElD,IAAkC,IAA9BL,EAASQ,QAAQD,GAAgB,CAEnCP,EAASS,KADTL,EAAKG,GAEL,MAGFF,IAGF,OAAOD,kBAmEa,SAACd,EAA6BoB,GAClD,GAAKpB,EAAL,CAKA,IAAMqB,EAAUC,OAAOC,OAErBpB,EACAiB,GAGIR,EDrL0B,SAACZ,GACjC,OAAOA,EAAQwB,iBAAiB,0BCoLfC,CAAmBzB,GAG9B0B,EAAmBC,SAASC,cAChCP,EAAQZ,wBAA0BN,EAAeM,wBAenD,OAjF4B,SAC5BG,EACAc,EACAtB,GAMA,IAJA,IAAIyB,EAAS,EACPC,EAAmBH,SAASC,cAAc,MAC1CG,EAAqBJ,SAASC,cAAc,KAEzCI,EAAI,EAAGA,EAAIpB,EAASI,OAAQgB,IAAK,CACxC,IAAMC,EAAUrB,EAASoB,GACnBE,ECxIDC,ODwI0CF,EAAQG,QCxInCC,UAAU,ID2I9B,GAAe,IAAXR,GAAgBA,EAASK,EAAe,CAE1C,IAAMI,EAAwBX,SAASC,cAAc,MAErDF,EAAiBa,UAAUC,YAAYF,GACvCZ,EAAmBY,UACC,IAAXT,GAAgBA,EAASK,EAElC,IAAK,IAAIF,EAAI,EAAGA,EAAIH,EAASK,EAAeF,IACtCjC,EAAc2B,EAAkBA,EAAiBxB,cAEnDwB,EAAmBA,EAAiBxB,WAAWA,YAKrD,IAGMuC,GA/CgCC,EA+CatC,EA7CjDuC,OAAAA,EAGJA,GChIsCC,EDuKhBjC,EAAaC,EAAUqB,EAAQpB,aA1CjD8B,EC5HGC,EAAKC,QAAQ,OAAQ,MD+HZA,QAAQ,OAAQ,IAAIA,QAAQ,WAAY,KAE3C,IAATH,IACFC,EC/HwC,SAACA,GAI3C,OAHAA,EAASG,mBAAmBH,IACZE,QAAQ,OAAQ,KD6HrBE,CAA6BJ,IAGjCA,GAqCLV,EAAQnB,GAAK2B,EAGb,IAAMO,EAAgBjB,EAAmBkB,WAAU,GACnDD,EAAcE,SAAWT,EACzBO,EAAcnC,YAAcoB,EAAQpB,YACpC,IAAMsC,EAAcrB,EAAiBmB,WAAU,GAC/CE,EAAYX,YAAYQ,GAExBtB,EAAiBc,YAAYW,GAG7BtB,EAASK,ECvL0B,IAACU,ED2HEF,EAEpCC,EAkFJS,CAAsBxC,EAAUc,IAAoBL,EAAQjB,YA1InC,SAACQ,EAA0Cc,GAGpE,IAFA,IAAM2B,EAAU3B,EAAiB4B,qBAAqB,gBAE7CtB,GACP,IAAMlB,EAAKuC,EAAQrB,GAAGuB,UAChBC,EAAOH,EAAQrB,GAAGwB,KAClBC,EAAkBC,MAAMC,KAAK/C,GAAUgD,OAAO,SAAC3B,UAAYA,EAAQnB,KAAOA,IAEhF,GAA+B,IAA3B2C,EAAgBzC,OAClB,iBAIF,IAAI6C,EAAQ,EAEZJ,EAAgBK,QAAQ,SAAC7B,GAIvB,IAHA,IAAM8B,EAAgB9B,EAAQnB,OAAM+C,QAGfH,MAAMC,KAAKN,kBAAU,CAArC,IAAMV,OACT,GAAIA,EAAOa,OAASA,EAAM,CAExBb,EAAOO,SAAWa,EAClB,OAKJ9B,EAAQnB,GAAKiD,EACbF,OA1BK7B,EAAI,EAAGA,EAAIqB,EAAQrC,OAAQgB,MAA3BA,GA0ITgC,CAAmBpD,EAAUc,GAGzBL,EAAQhB,YA5LW,SACvBO,EACAyC,EACAhC,GAEA,GAAKgC,EAAL,CAEA,IAAMY,EAAItC,SAASC,cAAc,KACjCqC,EAAEC,aAAa,cAAe,QAE1B7C,EAAQb,qBACVyD,EAAEE,UAAUC,IAAI/C,EAAQb,qBAG1BI,EAASkD,QAAQ,SAAC7B,GAGhB,IAFA,IAAQnB,EAAOmB,EAAPnB,GAECkB,EAAI,EAAGA,EAAIqB,EAAQrC,OAAQgB,IAAK,CACvC,IAAQwB,EAASH,EAAQrB,GAAjBwB,KAER,GAAIA,EAAKX,QAAQ,IAAK,MAAQ/B,EAA9B,CAKA,IAAM6B,EAASsB,EAAEhB,WAAU,GAC3BN,EAAOuB,aAAa,OAAQV,GAExBnC,EAAQf,mBACVqC,EAAO9B,YAAcQ,EAAQf,kBAI3Be,EAAQd,iBAEV0B,EAAQoC,aAAa1B,EAAQV,EAAQqC,YAGrCrC,EAAQO,YAAYG,QAwJxB4B,CAAiB3D,EADDc,EAAiBF,iBAAiB,KACdH,GAG/BK"}
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\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(/\\&amp;+/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 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","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","classList","add","setAttribute","insertBefore","firstChild","renderAnchorLink"],"mappings":"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"}
@@ -1,2 +1,2 @@
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=[],r=(e,n)=>{let r=n||"",o=1;for(;o<=e.length;){const e=1===o?r:`${r}_${o}`;if(-1===t.indexOf(e)){r=e,t.push(r);break}o++}return r},o=(e,n)=>{let t=(e=>e.replace(/\s+/g,"_"))(e);return t=t.replace(/\&+/g,"").replace(/\&amp;+/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=r(n,s.textContent),m=o(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 r=t[n].innerText,o=t[n].hash,a=Array.from(e).filter(e=>e.id===r);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===o){e.href=`#${n}`;break}e.id=n,c++})}})(l,i),c.anchorLink&&((e,n,t)=>{if(!n)return;const r=document.createElement("a");r.setAttribute("aria-hidden","true"),t.anchorLinkClassName&&r.classList.add(t.anchorLinkClassName),e.forEach(e=>{const{id:o}=e;for(let a=0;a<n.length;a++){const{hash:c}=n[a];if(c.replace("#","")!==o)continue;const l=r.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};
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(!t.includes(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(/\&amp;+/g,""),!0===n&&(t=(e=>(e=encodeURIComponent(e)).replace(/\%+/g,"."))(t)),t},a=(t,a)=>{if(!t)return;const l=Object.assign(n,a),c=(e=>Array.from(e.querySelectorAll("h1, h2, h3, h4, h5, h6")))(t),h=document.createElement(l.anchorContainerTagName||n.anchorContainerTagName);return((n,t,a)=>{let l=0;const c=document.createElement("li"),h=document.createElement("a");for(let i=0;i<n.length;i++){const s=n[i],d=Number(s.tagName.substring(1));if(0!==l&&l<d){const e=document.createElement("ol");t.lastChild.appendChild(e),t=e}else if(0!==l&&l>d)for(let n=0;n<l-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=h.cloneNode(!1);p.href=`#${m}`,p.textContent=s.textContent;const u=c.cloneNode(!1);u.appendChild(p),t.appendChild(u),l=d}})(c,h,!!l.anchorType),((e,n)=>{const t=Array.from(n.getElementsByTagName("a"));for(let n=0;n<t.length;n++){const o=t[n].textContent,r=t[n].hash,a=e.filter(e=>e.id===o);if(1===a.length)continue;let l=0;for(let e=0;e<a.length;e++){const n=a[e],o=`${n.id}-${l}`;for(let e=0;e<t.length;e++){const n=t[e];if(n.hash===r){n.href=`#${o}`;break}}n.id=o,l++}}})(c,h),l.anchorLink&&((e,n,t)=>{if(!n)return;const o=document.createElement("a");t.anchorLinkClassName&&o.classList.add(t.anchorLinkClassName);for(let r=0;r<e.length;r++){const a=e[r],{id:l}=a;for(let e=0;e<n.length;e++){const{hash:r}=n[e];if(r.replace("#","")!==l)continue;const c=o.cloneNode(!1);c.setAttribute("href",r),t.anchorLinkSymbol&&(c.textContent=t.anchorLinkSymbol),t.anchorLinkBefore?a.insertBefore(c,a.firstChild):a.appendChild(c)}}})(c,Array.from(h.querySelectorAll("a")),l),h};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\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 a.setAttribute('aria-hidden', 'true');\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(/\\&amp;+/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","setAttribute","classList","add","insertBefore","firstChild","renderAnchorLink"],"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): 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\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(/\\&amp;+/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 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","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","classList","add","setAttribute","insertBefore","firstChild","renderAnchorLink"],"mappings":"MAAaA,EAAgB,CAACC,EAAsBC,KAClD,KAAOD,GAAS,CACd,GAAIA,IAAYC,EACd,SAEFD,EAAUA,EAAQE,WAEpB,UCOIC,EAAiB,CACrBC,YAAY,EACZC,YAAY,EACZC,iBAAkB,IAClBC,kBAAkB,EAClBC,oBAAqB,GACrBC,uBAAwB,MAGpBC,EAAqB,GAkFrBC,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,MAGFC,IAGF,OAAOD,GAGHM,EAAqB,CAACC,EAAcC,KAExC,IAAIC,EC/HkCF,CAAAA,GAC/BA,EAAKG,QAAQ,OAAQ,KD8HfC,CAAwBJ,GASrC,OANAE,EAASA,EAAOC,QAAQ,OAAQ,IAAIA,QAAQ,WAAY,KAE3C,IAATF,IACFC,ECjIyCA,CAAAA,IAC3CA,EAASG,mBAAmBH,IACZC,QAAQ,OAAQ,KD+HrBG,CAA6BJ,IAGjCA,GAqDIK,EAAS,CACpB5B,EACA6B,KAEA,IAAK7B,EACH,OAIF,MAAM8B,EAAUC,OAAOC,OAErB7B,EACA0B,GAGIjB,ED1L2BZ,CAAAA,GAC1BiC,MAAMC,KAAKlC,EAAQmC,iBAAiB,2BCyL1BC,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,EC1IDC,OD0I0CF,EAAQG,QC1InCC,UAAU,ID6I9B,GAAe,IAAXR,GAAgBA,EAASK,EAAe,CAE1C,MAAMI,EAAwBX,SAASC,cAAc,MAErDF,EAAiBa,UAAUC,YAAYF,GACvCZ,EAAmBY,UACC,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,IA2BXY,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,OAKJrB,EAAQ9B,GAAKmD,EACbF,OAmHJI,CAAmBvD,EAAUyB,GAGzBP,EAAQzB,YAjMW,EACvBO,EACA8C,EACA5B,KAEA,IAAK4B,EAAS,OAEd,MAAMU,EAAI9B,SAASC,cAAc,KAE7BT,EAAQtB,qBACV4D,EAAEC,UAAUC,IAAIxC,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,EAAOgD,aAAa,OAAQX,GAExB9B,EAAQxB,mBACViB,EAAOV,YAAciB,EAAQxB,kBAI3BwB,EAAQvB,iBAEVqC,EAAQ4B,aAAajD,EAAQqB,EAAQ6B,YAGrC7B,EAAQO,YAAY5B,MA6JxBmD,CAAiB9D,EADDqB,MAAMC,KAAKG,EAAiBF,iBAAiB,MACzBL,GAG/BO"}
@@ -1,2 +1,2 @@
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(/\&amp;+/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");a.setAttribute("aria-hidden","true"),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};
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(/\&amp;+/g,""),!0===g&&(C=function(e){return(e=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");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
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\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 a.setAttribute('aria-hidden', 'true');\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(/\\&amp;+/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","setAttribute","classList","add","insertBefore","firstChild","renderAnchorLink"],"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): 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\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(/\\&amp;+/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 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","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","classList","add","setAttribute","insertBefore","firstChild","renderAnchorLink"],"mappings":"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"}
@@ -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},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(/\&amp;+/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");t.setAttribute("aria-hidden","true"),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}}});
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(/\&amp;+/g,""),!0===g&&(C=function(e){return(e=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");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
2
  //# sourceMappingURL=mokuji.umd.js.map
@@ -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\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 a.setAttribute('aria-hidden', 'true');\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(/\\&amp;+/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","setAttribute","classList","add","insertBefore","firstChild","renderAnchorLink"],"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): 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\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(/\\&amp;+/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 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","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","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": "4.1.0",
3
+ "version": "4.2.0",
4
4
  "description": "A table of content JavaScript Library",
5
5
  "scripts": {
6
6
  "build": "microbundle",
@@ -48,11 +48,11 @@
48
48
  "homepage": "https://github.com/hiro0218/mokuji.js",
49
49
  "devDependencies": {
50
50
  "@types/node": "~17.0.23",
51
- "husky": "^7.0.4",
52
- "lint-staged": "^12.3.7",
53
- "microbundle": "^0.14.2",
51
+ "husky": "^8.0.1",
52
+ "lint-staged": "^13.0.3",
53
+ "microbundle": "^0.15.0",
54
54
  "prettier": "^2.6.1",
55
55
  "rimraf": "^3.0.2",
56
- "typescript": "~4.6.3"
56
+ "typescript": "~4.7.4"
57
57
  }
58
58
  }
package/src/dom.ts CHANGED
@@ -16,6 +16,6 @@ export const reverseElement = (element: Node) => {
16
16
  return element;
17
17
  };
18
18
 
19
- export const getHeadingsElement = (element: Element): NodeListOf<HTMLHeadingElement> => {
20
- return element.querySelectorAll("h1, h2, h3, h4, h5, h6");
19
+ export const getHeadingsElement = (element: Element): HTMLHeadingElement[] => {
20
+ return Array.from(element.querySelectorAll('h1, h2, h3, h4, h5, h6'));
21
21
  };
package/src/index.ts CHANGED
@@ -24,24 +24,24 @@ const defaultOptions = {
24
24
  const storeIds: string[] = [];
25
25
 
26
26
  const renderAnchorLink = (
27
- headings: NodeListOf<HTMLHeadingElement>,
28
- anchors: NodeListOf<HTMLAnchorElement> | undefined,
27
+ headings: HTMLHeadingElement[],
28
+ anchors: HTMLAnchorElement[] | undefined,
29
29
  options: MokujiOption,
30
30
  ) => {
31
31
  if (!anchors) return;
32
32
 
33
33
  const a = document.createElement('a');
34
- a.setAttribute('aria-hidden', 'true');
35
34
 
36
35
  if (options.anchorLinkClassName) {
37
36
  a.classList.add(options.anchorLinkClassName);
38
37
  }
39
38
 
40
- headings.forEach((heading) => {
39
+ for (let i = 0; i < headings.length; i++) {
40
+ const heading = headings[i];
41
41
  const { id } = heading;
42
42
 
43
- for (let i = 0; i < anchors.length; i++) {
44
- const { hash } = anchors[i];
43
+ for (let j = 0; j < anchors.length; j++) {
44
+ const { hash } = anchors[j];
45
45
 
46
46
  if (hash.replace('#', '') !== id) {
47
47
  continue;
@@ -64,16 +64,16 @@ const renderAnchorLink = (
64
64
  heading.appendChild(anchor);
65
65
  }
66
66
  }
67
- });
67
+ }
68
68
  };
69
69
 
70
- const removeDuplicateIds = (headings: NodeListOf<HTMLHeadingElement>, elementContainer: HTMLElement) => {
71
- const anchors = elementContainer.getElementsByTagName('a');
70
+ const removeDuplicateIds = (headings: HTMLHeadingElement[], elementContainer: HTMLElement) => {
71
+ const anchors = Array.from(elementContainer.getElementsByTagName('a'));
72
72
 
73
73
  for (let i = 0; i < anchors.length; i++) {
74
- const id = anchors[i].innerText;
74
+ const id = anchors[i].textContent;
75
75
  const hash = anchors[i].hash;
76
- const matchedHeadings = Array.from(headings).filter((heading) => heading.id === id);
76
+ const matchedHeadings = headings.filter((heading) => heading.id === id);
77
77
 
78
78
  if (matchedHeadings.length === 1) {
79
79
  continue;
@@ -82,11 +82,13 @@ const removeDuplicateIds = (headings: NodeListOf<HTMLHeadingElement>, elementCon
82
82
  // duplicated id
83
83
  let count = 0;
84
84
 
85
- matchedHeadings.forEach((heading) => {
85
+ for (let j = 0; j < matchedHeadings.length; j++) {
86
+ const heading = matchedHeadings[j];
86
87
  const heading_id = `${heading.id}-${count}`;
87
88
 
88
89
  // search duplicate list
89
- for (const anchor of Array.from(anchors)) {
90
+ for (let k = 0; k < anchors.length; k++) {
91
+ const anchor = anchors[k];
90
92
  if (anchor.hash === hash) {
91
93
  // update hash
92
94
  anchor.href = `#${heading_id}`;
@@ -97,11 +99,11 @@ const removeDuplicateIds = (headings: NodeListOf<HTMLHeadingElement>, elementCon
97
99
  // update id
98
100
  heading.id = heading_id;
99
101
  count++;
100
- });
102
+ }
101
103
  }
102
104
  };
103
105
 
104
- const censorshipId = (headings: NodeListOf<HTMLHeadingElement>, textContent: string | null) => {
106
+ const censorshipId = (headings: HTMLHeadingElement[], textContent: string | null) => {
105
107
  let id = textContent || '';
106
108
  let suffix_count = 1;
107
109
 
@@ -109,7 +111,7 @@ const censorshipId = (headings: NodeListOf<HTMLHeadingElement>, textContent: str
109
111
  while (suffix_count <= headings.length) {
110
112
  const tmp_id = suffix_count === 1 ? id : `${id}_${suffix_count}`;
111
113
 
112
- if (storeIds.indexOf(tmp_id) === -1) {
114
+ if (!storeIds.includes(tmp_id)) {
113
115
  id = tmp_id;
114
116
  storeIds.push(id);
115
117
  break;
@@ -136,7 +138,7 @@ const generateAnchorText = (text: string, type: boolean) => {
136
138
  };
137
139
 
138
140
  const generateHierarchyList = (
139
- headings: NodeListOf<HTMLHeadingElement>,
141
+ headings: HTMLHeadingElement[],
140
142
  elementContainer: HTMLUListElement | HTMLOListElement,
141
143
  anchorType: boolean,
142
144
  ) => {
@@ -185,7 +187,10 @@ const generateHierarchyList = (
185
187
  }
186
188
  };
187
189
 
188
- export const Mokuji = (element: HTMLElement | null, externalOptions?: MokujiOption): HTMLOListElement | undefined => {
190
+ export const Mokuji = (
191
+ element: HTMLElement | null,
192
+ externalOptions?: MokujiOption,
193
+ ): HTMLUListElement | HTMLOListElement | undefined => {
189
194
  if (!element) {
190
195
  return;
191
196
  }
@@ -202,7 +207,7 @@ export const Mokuji = (element: HTMLElement | null, externalOptions?: MokujiOpti
202
207
  // mokuji start
203
208
  const elementContainer = document.createElement(
204
209
  options.anchorContainerTagName || defaultOptions.anchorContainerTagName,
205
- );
210
+ ) as HTMLUListElement | HTMLOListElement;
206
211
 
207
212
  // generate mokuji list
208
213
  generateHierarchyList(headings, elementContainer, !!options.anchorType);
@@ -212,7 +217,7 @@ export const Mokuji = (element: HTMLElement | null, externalOptions?: MokujiOpti
212
217
 
213
218
  // setup anchor link
214
219
  if (options.anchorLink) {
215
- const anchors = elementContainer.querySelectorAll('a');
220
+ const anchors = Array.from(elementContainer.querySelectorAll('a'));
216
221
  renderAnchorLink(headings, anchors, options);
217
222
  }
218
223