@mindfiredigital/page-builder
Version:
196 lines (195 loc) • 5.78 kB
JavaScript
export class HTMLGenerator {
constructor(canvas) {
this.canvas = canvas;
this.styleElement = document.createElement('style');
document.head.appendChild(this.styleElement);
}
generateHTML() {
const canvasElement = document.getElementById('canvas');
if (!canvasElement) {
console.warn('Canvas element not found!');
return this.getBaseHTML(); // Return base HTML if canvas is not found
}
// Clone the canvas element to avoid modifying the original
const cleanCanvas = canvasElement.cloneNode(true);
// Remove unwanted attributes and elements from all children
this.cleanupElements(cleanCanvas);
// Create a full HTML document
// Use the canvas's outerHTML to include the element itself
return this.getBaseHTML(cleanCanvas.innerHTML);
}
getBaseHTML(bodyContent = 'children') {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Page Builder</title>
<style>
${this.generateCSS()}
</style>
</head>
<body>
<div id="page" class="home">
${bodyContent}
</div>
</body>
</html>`;
}
cleanupElements(element) {
const attributesToRemove = ['contenteditable', 'draggable', 'style'];
const classesToRemove = [
'component-controls',
'delete-icon',
'component-label',
'column-label',
'editable-component',
'resizers',
'resizer',
'upload-btn',
'component-resizer',
'drop-preview',
'edit-link-form',
'edit-link',
];
Array.from(element.children).forEach(child => {
const childElement = child;
// Remove specified attributes
attributesToRemove.forEach(attr => {
childElement.removeAttribute(attr);
});
// Remove specified classes
classesToRemove.forEach(classToRemove => {
childElement.classList.remove(classToRemove);
});
// Remove input elements
const inputElements = element.querySelectorAll('input');
inputElements.forEach(input => input.remove());
// Remove specific child elements
const elementsToRemove = childElement.querySelectorAll(
'.component-controls, .delete-icon, .component-label,.column-label, .resizers, .resizer, .drop-preview, .upload-btn, component-resizer,.edit-link, .edit-link-form'
);
elementsToRemove.forEach(el => el.remove());
// Recursively clean up nested elements
if (childElement.children.length > 0) {
this.cleanupElements(childElement);
}
});
}
generateCSS() {
const canvasElement = document.getElementById('canvas');
if (!canvasElement) return '';
const backgroundColor = canvasElement
? window
.getComputedStyle(canvasElement)
.getPropertyValue('background-color')
: 'rgb(255, 255, 255)'; // Fallback to white if canvas is not found
const styles = [];
// Global and .home styles
styles.push(`
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
box-sizing: border-box;
}
.home {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
min-height:100vh;
background-color: ${backgroundColor};
margin: 0;
}
`);
const elements = canvasElement.querySelectorAll('*');
const stylesToCapture = [
'position',
'top',
'left',
'right',
'bottom',
'width',
'height',
'min-width',
'min-height',
'max-width',
'max-height',
'margin',
'padding',
'background-color',
'background-image',
'border',
'border-radius',
'transform',
'opacity',
'z-index',
'display',
'flex-direction',
'justify-content',
'align-items',
'flex-wrap',
'font-size',
'font-weight',
'color',
'text-align',
'line-height',
'font-family',
];
const classesToExclude = [
'component-controls',
'delete-icon',
'component-label',
'resizers',
'resizer',
'upload-btn',
'edit-link-form',
'edit-link',
];
elements.forEach(component => {
// Skip excluded elements
if (classesToExclude.some(cls => component.classList.contains(cls))) {
return;
}
const computedStyles = window.getComputedStyle(component);
const componentStyles = [];
stylesToCapture.forEach(prop => {
const value = computedStyles.getPropertyValue(prop);
if (value && value !== 'none' && value !== '') {
// Exclude "resize" property with any value
if (prop === 'resize') return;
componentStyles.push(`${prop}: ${value};`);
}
});
const selector = this.generateUniqueSelector(component);
if (componentStyles.length > 0) {
styles.push(`
${selector} {
${componentStyles.join('\n ')}
}`);
}
});
return styles.join('\n');
}
generateUniqueSelector(element) {
if (element.id) {
return `#${element.id}`;
}
if (element.className) {
return `.${element.className.split(' ').join('.')}`;
}
// Create a tag-based selector with index for uniqueness
const parent = element.parentElement;
if (parent) {
const siblings = Array.from(parent.children);
const index = siblings.indexOf(element);
return `${element.tagName.toLowerCase()}:nth-child(${index + 1})`;
}
return element.tagName.toLowerCase();
}
applyCSS(css) {
this.styleElement.textContent = css;
}
}