Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow wrapper to take a function #35

Open
bennypowers opened this issue Mar 14, 2022 · 6 comments · May be fixed by #37
Open

Allow wrapper to take a function #35

bennypowers opened this issue Mar 14, 2022 · 6 comments · May be fixed by #37

Comments

@bennypowers
Copy link

Hi! 👋

Firstly, thanks for your work on this project! 🙂

Today I used patch-package to patch [email protected] for the project I'm working on.

Users may need finer control over the wrapping element. In this patch, I allow wrapper to be a binary function taking content and label, which returns HTML. the wrapping element must apply aria-label="${label}"

Here is the diff that solved my problem:

diff --git a/node_modules/eleventy-plugin-toc/.eleventy.js b/node_modules/eleventy-plugin-toc/.eleventy.js
index 6a926b8..f87651d 100644
--- a/node_modules/eleventy-plugin-toc/.eleventy.js
+++ b/node_modules/eleventy-plugin-toc/.eleventy.js
@@ -4,7 +4,7 @@ const parseOptions = require('./src/ParseOptions')
 module.exports = (eleventyConfig, globalOpts) => {
   globalOpts = globalOpts || {}
   eleventyConfig.namespace(globalOpts, () => {
-    eleventyConfig.addFilter('toc', (content, localOpts) => {
+    eleventyConfig.addFilter('toc', function (content, localOpts) {
       return buildTOC(content, parseOptions(localOpts, globalOpts))
     })
   })
diff --git a/node_modules/eleventy-plugin-toc/src/BuildTOC.js b/node_modules/eleventy-plugin-toc/src/BuildTOC.js
index 50ced4a..00e3e60 100644
--- a/node_modules/eleventy-plugin-toc/src/BuildTOC.js
+++ b/node_modules/eleventy-plugin-toc/src/BuildTOC.js
@@ -29,11 +29,12 @@ const BuildTOC = (text, opts) => {
 
   const label = wrapperLabel ? `aria-label="${wrapperLabel}"` : ''
 
-  return wrapper
-    ? `<${wrapper} class="${wrapperClass}" ${label}>
-        ${BuildList(headings, ul, flat)}
-      </${wrapper}>`
-    : BuildList(headings, ul, flat)
+  const content = BuildList(headings, ul, flat);
+  return (
+      typeof wrapper === 'function' ? wrapper(content, label)
+    : wrapper ? `<${wrapper} class="${wrapperClass}" ${label}>${content}</${wrapper}>`
+    : content
+  );
 }
 
 module.exports = BuildTOC

This issue body was partially generated by patch-package.

@behoppe
Copy link

behoppe commented Oct 6, 2022

@bennypowers I echo your appreciation for this plugin. I wonder if you could say a bit more about how one might use the changes that you made. I am a JavaScript newbie, but I am certainly looking for finer control of the wrapper classes, and I think you're solving my problem (?).

I am hoping to use this plugin to generate HTML that looks like the following, with specific classes for not only the nav wrapper but also the ul, li, and a selectors:

<nav id="bd-toc-nav" class="page-toc">
    <ul class="visible nav section-nav flex-column">
        <li class="toc-h2 nav-item toc-entry">
            <a class="reference internal nav-link" href="#lorem-ipsum">
                 Lorem ipsum
            </a>
       </li>
       <li class="toc-h2 nav-item toc-entry">
           <a class="reference internal nav-link" href="#morbi-tincidunt">
                Morbi tincidunt
           </a>
       </li>
    </ul>
</nav>

@bennypowers can I use your comment plus some new JS function (from selector to the appropriate class-string) to do this? Thank you for any tips.

@bennypowers
Copy link
Author

What you can do is copy the contents of that snippet to a file called patches/eleventy-toc-plugin+1.1.5, then add patch-package to your postinstall script in package.json to apply the patch every time you run npm i or npm ci

"scripts": "npx patch-package"

@bennypowers bennypowers linked a pull request Oct 7, 2022 that will close this issue
@behoppe
Copy link

behoppe commented Oct 7, 2022

Thank you @bennypowers that is very helpful. I am still a bit confused about how to pass values from my site to the updated TOC plugin (probably because I am new to JavaScript). Would you mind sharing a small example? With the current TOC plugin, my site adds it like so, which I think needs to change after wrapper becomes a function, right? Thank you very much for your help.

  eleventyConfig.addPlugin(pluginTOC, {
    tags: ['h1', 'h2'],
    wrapper: 'nav',
    wrapperClass: 'visible nav section-nav flex-column',
    ul: true
  });

@bennypowers
Copy link
Author

I think that with my patch you could do this:

eleventyConfig.addPlugin(pluginTOC, {
  tags: ['h1', 'h2'],
  wrapper(content, label) {
    return `<nav id="bd-toc-nav" class="page-toc" aria-label="Site navigation">
  ${content.replaceAll('<ul>', '<ul class="visible nav section-nav flex-column">').replaceAll('<li>', '<li class="toc-h2 nav-item toc-entry">')}
  </nav>`
  },
  wrapperClass: 'visible nav section-nav flex-column',
  ul: true
});

If you wanted to get more complicated, you consider parsing the content html with something like cheerio or parse5 and alter the syntax tree. That would be a challenge, but rewarding, considering how you've described your level of comfort with js and web technologies.

@behoppe
Copy link

behoppe commented Oct 7, 2022

Thank you @bennypowers I got my TOC to work. Yeah! I had to name the file patches/eleventy-plugin-toc+1.1.5 (moving toc to end) and I added a replaceAll for the a selector like so:

  eleventyConfig.addPlugin(pluginTOC, {
    tags: ['h1', 'h2'],
    wrapper(content, label) {
      return `<nav id="bd-toc-nav" class="page-toc" aria-label="Site navigation">
    ${content.replaceAll('<ul>', '<ul class="visible nav section-nav flex-column">').replaceAll('<li>', '<li class="toc-h2 nav-item toc-entry">').replaceAll('<a href', '<a class="reference internal nav-link" href')}
    </nav>`
    },
    wrapperClass: 'visible nav section-nav flex-column',
    ul: true
  });

I confess I am still hazy on when exactly my scripts get executed. It seems like I need to run npx patch-package manually, probably because my scripts is wrong. I wonder if you see something amiss below? Thanks again for your help!

 "scripts": {
    "build": "npx @11ty/eleventy",
    "bench": "DEBUG=Eleventy:Benchmark* npx @11ty/eleventy",
    "watch": "npx @11ty/eleventy --watch",
    "serve": "npx @11ty/eleventy --serve",
    "start": "npx @11ty/eleventy --serve",
    "debug": "DEBUG=* npx @11ty/eleventy",
    "postinstall": "patch-package"
  },

behoppe added a commit to behoppe/www.opencilk.org that referenced this issue Oct 7, 2022
@behoppe
Copy link

behoppe commented Oct 7, 2022

Just wanted to confirm that it works! (Despite my confusion about script execution.) Thanks again for this patch.

behoppe added a commit to OpenCilk/www.opencilk.org that referenced this issue Mar 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants