import {html, render} from 'lit-html' import {styleMap} from 'lit-html/directives/style-map.js' import grapesjs from 'grapesjs/dist/grapes.min.js' import { onAll } from '../utils' const pluginName = 'template' const templateType = 'templateType' const templateKey = 'template' export const templatePlugin = grapesjs.plugins.add(pluginName, (editor, opts) => { // Add the new trait to all component types editor.DomComponents.getTypes().map(type => { editor.DomComponents.addType(type.id, { model: { defaults: { traits: [ // Keep the type original traits ...editor.DomComponents.getType(type.id).model.prototype.defaults.traits, // Add the new trait { label: false, type: templateType, name: pluginName, }, ] } } }) }) function doRender(el) { const template = editor.getSelected()?.get(templateKey) || {} const taStyle = opts.styles?.textarea ?? styleMap({ backgroundColor: 'var(--darkerPrimaryColor)', }) const sepStyle = opts.styles?.sep ?? styleMap({ height: '10px' }) const labels = { before: html`Before the element`, replace: html`Replace the element's children`, after: html`After the element`, attributes: html`HTML attributes`, classname: html`CSS classes`, style: html`CSS styles`, } render(html`

Template

This will be inserted in the published version

${['classname', 'attributes', 'style'].map(id => html` `)} ${['before', 'replace', 'after'].map(id => html` `)} `, el) } editor.TraitManager.addType(templateType, { createInput({ trait }) { // Create a new element container and add some content const el = document.createElement('div') el.classList.add('gjs-one-bg') // update the UI when a page is added/renamed/removed editor.on('page', () => doRender(el)) doRender(el) // this will be the element passed to onEvent and onUpdate return el }, // Update the component based on UI changes // `elInput` is the result HTMLElement you get from `createInput` onEvent({ elInput, component, event }) { const template = { before: elInput.querySelector('#template-before').value, replace: elInput.querySelector('#template-replace').value, after: elInput.querySelector('#template-after').value, attributes: elInput.querySelector('#template-attributes').value, classname: elInput.querySelector('#template-classname').value, style: elInput.querySelector('#template-style').value, } // Store the new template if(Object.values(template).filter(val => !!val && !!cleanup(val)).length > 0) { component.set(templateKey, template) } else { component.set(templateKey) } }, // Update UI on the component change onUpdate({ elInput, component }) { doRender(elInput) }, }) // Make html attribute // Quote strings, no values for boolean function makeAttribute(key, value) { switch(typeof value) { case 'boolean': return value ? key : '' default: return `${key}="${value}"` } } // Remove empty lines in templates function cleanup(template) { return template // split in lines .split('\n') // remove lines with only spaces .map(line => line.trim()) .filter(line => !!line) // put back together .join('\n') } editor.on(opts.eventStart || 'publish:before', () => { // Insert templates onAll(editor, c => { const template = c.get(templateKey) const toHTML = c.toHTML const classes = c.getClasses() const before = cleanup(template?.before || '') const replace = cleanup(template?.replace || '') const after = cleanup(template?.after || '') const classname = cleanup(template?.classname || '') const style = cleanup(template?.style || '') const attributes = cleanup(template?.attributes || '') // Store the initial method if(!c.has('tmpHtml')) c.set('tmpHtml', toHTML) // Override the method c.toHTML = () => { return ` ${ before } ${ c.get('tagName') ? `<${c.get('tagName')} ${Object.entries(c.get('attributes')).map(([key, value]) => makeAttribute(key, value)).join(' ')} ${classes.length || classname ? `class="${classes.join(' ')} ${classname}"` : ''} ${attributes} ${style ? `style="${style}"` : ''} >` : '' } ${replace || c.getInnerHTML()} ${ c.get('tagName') ? `` : '' } ${ after } ` } }) }) editor.on(opts.eventStop || 'publish:stop', () => { onAll(editor, c => { // Restore the original method c.toHTML = c.get('tmpHtml') }) }) })