liamfiddler / eleventy-plugin-transformdom

A plugin to process & change the generated HTML output of your Eleventy site.
MIT License
9 stars 2 forks source link

add example: transform custom element / xml to html #1

Open milahu opened 3 years ago

milahu commented 3 years ago
function customElementTransformer(nameCustom, options = {}) {
  const defaultOptions = {
    name: 'div',
    class: nameCustom,
  };
  options = Object.assign(defaultOptions, options);
  const domTransformer = {
    selector: nameCustom,
    transform: ({ elements, document }) => {
      for (let e = 0; e < elements.length; e++) {
        const element = elements[e];
        const elementNew = document.createElement(options.name);
        for (let a = 0; a < element.attributes.length; a++) {
           const attr = element.attributes[a];
           elementNew.setAttribute(attr.name, attr.value); // copy attribute
        }
        elementNew.innerHTML = element.innerHTML; // copy content
        if (options.class) elementNew.classList.add(options.class);
        //element.parentNode.replaceChild(elementNew, element);
        element.replaceWith(elementNew);
      }
    },
  };
  return domTransformer;
}

eleventyConfig.addPlugin(transformDomPlugin, [
  customElementTransformer('page'),
  customElementTransformer('nw', { name: 'span', class: 'nowrap-element' }),
]);

sample input

<page>
  hello world, here are <nw>four non wrapping words</nw>
</page>

sample output

<div class="page">
  hello world, here are <span class="nowrap-element">four non wrapping words</span>
</div>

benefits:

milahu commented 3 years ago

more general

```js function getElementTransformer(selector, options = {}) { const defaultOptions = { name: 'div', attributes: (e => Object.fromEntries(Array.from(e.attributes).map(a => [a.name, a.value]))), class: (e => e.localName), }; options = Object.assign(defaultOptions, options); const getName = (typeof options.name == 'function') ? (e => options.name(e)) : (() => options.name); const getAttributes = ( (typeof options.attributes == 'function') ? (e => options.attributes(e)) : (typeof options.attributes == 'object') ? (() => options.attributes) : (() => false) ); const getExtraClass = ( (typeof options.class == 'function') ? (e => options.class(e)) : (typeof options.class == 'string') ? (() => options.class) : (() => false) ); const domTransformer = { selector, transform: ({ elements, document }) => { for (let e = 0; e < elements.length; e++) { const element = elements[e]; const nameNew = getName(element); if (!nameNew) continue; // no replace const attributesNew = getAttributes(element) || {}; const extraClassNew = getExtraClass(element); const elementNew = document.createElement(nameNew); for (const [name, value] of Object.entries(attributesNew)) { elementNew.setAttribute(name, value); } elementNew.innerHTML = element.innerHTML; if (extraClassNew) elementNew.classList.add(extraClassNew); //element.parentNode.replaceChild(elementNew, element); element.replaceWith(elementNew); } }, }; return domTransformer; } eleventyConfig.addPlugin(transformDomPlugin, [ getElementTransformer('page', { class: 'page-element' }), getElementTransformer('nw', { name: 'span', class: 'nowrap-element' }), ...(['de', 'en']).map(langKey => getElementTransformer(langKey, { name: 'span', attributes: (e => ({ lang: e.localName })), class: false }) ) ]); ```
liamfiddler commented 3 years ago

Wow! I hadn't considered the plugin being used in this way, but it's very cool!

Thanks for the detailed code too! I think this would be a really interesting example of how the plugin can be used 😃

I'm flat out at the moment - any chance you'd be willing to fork the repo, add your example to the "examples" directory (feel free to use one of the existing example directories as a template), and submit a PR?