html-webpack-c5-theme-plugin
Version:
c5 html-webpack-plugin to generate c5 theme files
371 lines (370 loc) • 15.6 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HtmlWebpackC5ThemePlugin = void 0;
const html_webpack_plugin_1 = __importDefault(require("html-webpack-plugin"));
const parse5_1 = __importDefault(require("parse5"));
const template_1 = __importDefault(require("./template"));
const pluginName = "c5-html-plugin";
class HtmlWebpackC5ThemePlugin {
constructor(_options, _htmlPlugin) {
this._htmlPlugin = _htmlPlugin;
this.hasAreaTag = false;
this.hasElement = false;
this.elements = [];
this.areas = [];
this.generatedTheme = false;
this._options = {
themeHandle: "c5_theme",
themeName: "Concrete5 Theme",
defaultPage: "index.html",
skipIndex: false,
};
if (!_htmlPlugin) {
this._htmlPlugin = html_webpack_plugin_1.default;
}
if (typeof _options === "string") {
this._options.themeHandle = _options.replace(/\s/gi, "_");
this._options.themeName = _options;
}
else {
this._options = Object.assign(Object.assign({}, this._options), _options);
}
}
getConcrete5Output(html) {
const document = (parse5_1.default.parseFragment(html, { sourceCodeLocationInfo: true }));
let newHtml = "";
this.getAreas(document);
let prevPos = 0;
if (this.hasAreaTag) {
this.areas.forEach((c5a) => {
newHtml += html.substring(prevPos, c5a.start) + this.outputAreas(c5a);
prevPos = c5a.end ? c5a.end : 0;
});
this.hasAreaTag = false;
this.areas = [];
}
newHtml += html.substring(prevPos, html.length);
return newHtml;
}
outputAreas(area) {
let areaOutput = "<?php \n";
if (area.global) {
areaOutput +=
"$area = new \\Concrete\\Core\\Area\\GlobalArea('" +
area.name +
"');\n";
}
else {
areaOutput +=
"$area = new \\Concrete\\Core\\Area\\Area('" + area.name + "');\n";
}
if (area.editable === false)
areaOutput += "$area->disableControls();\n";
if (area.useGrid === true)
areaOutput += "$area->enableGridContainer();\n";
areaOutput += "$area->display($c);\n";
areaOutput += "?>";
return areaOutput;
}
getAreas(document) {
if (document.childNodes && document.childNodes.length) {
document.childNodes.forEach((childNode) => {
if (this.isArea(childNode)) {
this.hasAreaTag = true;
this.getC5Area(childNode);
}
else {
return this.getAreas(childNode);
}
});
}
return true;
}
isElement(comment) {
return (comment.nodeName === "#comment" &&
comment.data.match(/^-*C5\s(?:Begin|End)/giu));
}
getElements(document, filename) {
if (document.childNodes && document.childNodes.length) {
document.childNodes.forEach((childNode) => {
if (this.isElement(childNode)) {
this.hasElement = true;
this.getElement(childNode, filename);
}
else {
return this.getElements(childNode, filename);
}
});
return true;
}
else {
return false;
}
}
getElement(comment, filename) {
let element;
const regEx = /^-*C5\s+Begin\s+(.*)-*$/iu;
if (regEx.test(comment.data)) {
const res = comment.data.match(regEx);
if (res) {
element = {
name: res[1].replace("-", ""),
filename: "elements/" + res[1].replace(/\s/, "_"),
content: "",
startCom: comment.sourceCodeLocation
? comment.sourceCodeLocation.startOffset
: 0,
startPos: comment.sourceCodeLocation
? comment.sourceCodeLocation.endOffset
: 0,
endCom: 0,
endPos: 0,
files: [filename],
};
this.elements.push(element);
}
}
else {
const regEx = /^-*C5\s+End\s+(.*)-*$/iu;
if (regEx.test(comment.data)) {
const res = comment.data.match(regEx);
if (res) {
const tempName = res[1].replace("-", "");
const newEle = this.elements.find((ele) => {
return ele.name === tempName;
});
if (!newEle) {
throw new Error("Invalid Element - No Start Tag : " + res[1]);
}
element = newEle;
element.endCom = comment.sourceCodeLocation
? comment.sourceCodeLocation.endOffset
: 0;
element.endPos = comment.sourceCodeLocation
? comment.sourceCodeLocation.startOffset
: 0;
this.elements = this.elements.filter((ele) => {
if (ele.name === element.name && !ele.files.includes(filename)) {
element.files = [...ele.files, filename];
}
return ele.name !== element.name;
});
this.elements.push(element);
}
}
}
}
isArea(area) {
return area.nodeName === "c5-area";
}
getElementHtml(element, html) {
if (element.endPos === element.endCom) {
throw new Error("Invalid Element - No End Tag : " + element.name);
}
element.content = "";
element.content += html.substring(element.startPos, element.endPos);
return (html.substring(0, element.startCom) +
html.substring(element.endCom, html.length));
}
getC5Area(area) {
const c5area = {
name: "",
global: false,
useGrid: false,
editable: true,
start: 0,
end: 0,
};
if (area.attrs.length > 0) {
area.attrs.forEach((attr) => {
if (attr.name === "name")
c5area.name = attr.value.trim();
if (attr.name === "grid")
c5area.useGrid = attr.value === "true";
if (attr.name === "global")
c5area.global = attr.value === "true";
if (attr.name === "editable")
c5area.editable = attr.value === "true";
});
}
if (!c5area.name || c5area.name === "") {
throw new Error("Invalid Area - Missing Name Tag");
}
c5area.start = area.sourceCodeLocation
? area.sourceCodeLocation.startOffset
: 0;
c5area.end = area.sourceCodeLocation
? area.sourceCodeLocation.endOffset
: 0;
this.areas.push(c5area);
}
generateThemeFile(compilation) {
const config = {
name: this._options.themeName,
handle: this._options.themeHandle,
description: this._options.themeDescription,
packageHandle: this._options.packageHandle,
};
const generator = new template_1.default(config);
const content = generator.generate();
const eleSource = { source: () => content, size: () => content.length };
// @ts-ignore
if (compilation.emitAsset) {
// @ts-ignore
compilation.emitAsset("page_theme.php", eleSource);
}
else {
compilation.assets["page_theme.php"] = eleSource;
}
}
outputC5Theme(content, name, compilation) {
const defaultPage = this._options.defaultPage
? this._options.defaultPage
: "index.html";
if (name.toLowerCase() === defaultPage.toLowerCase()) {
this.outputC5Theme(content, "default", compilation);
}
let start = "<?php\n";
start += "defined('C5_EXECUTE') or die('Access Denied.');\n";
start += "/* @var \\Concrete\\Core\\Page\\View\\PageView $view */\n";
start += "$c = \\Concrete\\Core\\Page\\Page::getCurrentPage();?>\n";
content = start + content;
name = name.toLowerCase();
const eleSource = { source: () => content, size: () => content.length };
// @ts-ignore
if (compilation.emitAsset) {
// @ts-ignore
compilation.emitAsset(name.replace(".html", "") + ".php", eleSource);
}
else {
compilation.assets[name.replace(".html", "") + ".php"] = eleSource;
}
}
apply(compiler) {
if (compiler.hooks) {
// webpack 4 support
compiler.hooks.compilation.tap(pluginName, (compilation) => {
if (this._htmlPlugin) {
const hooks = this._htmlPlugin.getHooks(compilation);
hooks.beforeEmit.tapAsync(pluginName, (data, cb) => {
let fileHasEles = false;
if (this._options.skipIndex &&
data.outputName.toLowerCase() === "index.html") {
cb(undefined, data);
}
else {
let html = "";
try {
if (this.getElements(parse5_1.default.parseFragment(data.html, {
sourceCodeLocationInfo: true,
}), data.outputName)) {
this.elements.forEach((ele) => {
if (ele.files.includes(data.outputName)) {
fileHasEles = true;
this.getElementHtml(ele, data.html);
this.outputC5Theme(this.getConcrete5Output(ele.content), ele.filename, compilation);
}
});
}
if (!this.generatedTheme) {
this.generateThemeFile(compilation);
}
if (fileHasEles) {
html = this.removeElements(data.html);
}
else {
html = data.html;
}
if (this._options.deleteHtml === true) {
html = this.getConcrete5Output(html);
let start = "<?php\n";
start += "defined('C5_EXECUTE') or die('Access Denied.');\n";
start +=
"/* @var \\Concrete\\Core\\Page\\View\\PageView $view */\n";
start +=
"$c = \\Concrete\\Core\\Page\\Page::getCurrentPage();?>\n";
if (this._options.defaultPage.toLowerCase() !==
data.outputName.toLowerCase()) {
data.outputName = data.outputName.replace(".html", ".php");
}
else {
data.outputName = "default.php";
}
data.html = start + html;
}
else {
this.outputC5Theme(this.getConcrete5Output(html), data.outputName, compilation);
}
cb(undefined, data);
}
catch (err) {
compilation.errors.push(err);
cb(undefined, data);
}
}
});
hooks.afterEmit.tapAsync(pluginName, (data, cb) => {
if (data.outputName.toLowerCase() === "index.html" &&
this._options.skipIndex) {
delete compilation.assets[data.outputName];
}
else if (this._options.deleteHtml === true) {
const asset = compilation.assets[data.outputName];
let isDefault = false;
delete compilation.assets[data.outputName];
data.outputName = data.outputName.toLowerCase();
if (this._options.defaultPage.toLowerCase() ===
data.outputName.toLowerCase()) {
isDefault = true;
}
data.outputName = data.outputName.replace(".html", ".php");
// @ts-ignore
if (compilation.emitAsset) {
// @ts-ignore
compilation.emitAsset(data.outputName, asset);
if (isDefault) {
// @ts-ignore
compilation.emitAsset("default.php", asset);
}
}
else {
if (isDefault) {
compilation.assets["default.php"] = asset;
}
compilation.assets[data.outputName] = asset;
}
}
cb(undefined, data);
});
}
else {
throw new Error("Cannot find appropriate compilation hook");
}
});
}
else {
throw new Error("Webpack 3 not supported with concrete5 plugin");
}
}
removeElements(html) {
let newHtml = "";
let prevPos = 0;
if (this.hasElement) {
this.elements.forEach((ele) => {
newHtml += html.substring(prevPos, ele.startCom);
newHtml += "<?php $view->inc('" + ele.filename + ".php'); ?>";
prevPos = ele.endCom;
});
newHtml += html.substring(prevPos, html.length);
return newHtml;
}
else {
return html;
}
}
}
exports.HtmlWebpackC5ThemePlugin = HtmlWebpackC5ThemePlugin;
exports.default = HtmlWebpackC5ThemePlugin;