43 Commits

Author SHA1 Message Date
roman 25862c4b1c 1.0.22 2022-12-08 05:00:43 +02:00
roman a61510f136 Updated build process of ACF Block.
Added initBlock function.
2022-12-08 04:56:45 +02:00
roman 0d3ae8f03e Added "scroll" layout for scrolling tests.
Added swiperjs rules that fix the height/vertical-scrolling issues of sliders.
2022-12-07 06:38:54 +02:00
roman b58ef27f1e Fix scrolling issues of iFrame. 2022-12-06 11:32:14 +02:00
roman 161e34e8ee 1.0.21 2022-12-05 14:26:08 +02:00
roman 8eb7bea2e8 Fix resizing issue. 2022-12-05 14:26:01 +02:00
roman d9543bb22c Provide option to rewrite project/module paths. 2022-12-03 21:58:34 +02:00
roman 02abf4652e Update enqueue asset names. 2022-12-01 09:49:19 +02:00
roman 1ed038ff02 Update build of ACF blocks. 2022-11-30 21:01:02 +02:00
roman 0bb705ccdc Update build of ACF blocks. 2022-11-30 17:44:46 +02:00
roman 9d25bdcb88 Update path to assets. 2022-11-25 19:48:14 +02:00
roman 4d1d2337bf Added Basic Elementor widget logic. 2022-11-25 19:42:28 +02:00
roman 00866a8115 Update WordPress Basic Template 2022-11-25 19:25:33 +02:00
roman 1d733fb952 Fix right side icons/buttons. 2022-11-25 15:40:29 +02:00
roman 295c6f82af Added Elementor option in build process.
Elementor build still not ready.
2022-11-25 11:48:41 +02:00
roman f0af682a43 Include jpg,png,svg of toolbar in prod package. 2022-11-24 07:50:53 +02:00
roman ad35540111 1.0.20 2022-11-24 07:39:40 +02:00
roman 5cb6343184 Include layouts/partials in prod package. 2022-11-24 07:36:05 +02:00
roman 502326fd8d Add "info" command to get information about the local env. 2022-11-24 07:31:29 +02:00
roman 38a2d60f2c Merge pull request 'hubspot-pages' (#5) from hubspot-pages into master
Reviewed-on: #5
2022-11-24 05:25:58 +00:00
roman 15c5286905 Merge pull request 'windows-watch' (#4) from windows-watch into master
Reviewed-on: #4
2022-11-24 05:25:33 +00:00
roman f3e5b92318 Fix vertical scrolling issues. 2022-11-24 07:24:56 +02:00
roman c42c9fecba remove unnecessary code. 2022-11-23 23:59:13 +02:00
roman 6ebd37190a Pass {base} argument to gulp bundler. 2022-11-23 23:36:02 +02:00
roman 37ecce6290 Fix windows paths in Gulp scripts. 2022-11-23 22:15:27 +02:00
roman e0ae4d3d69 Print log. 2022-11-17 11:21:43 +02:00
roman 70d4630971 Add basic Handlebars to Hubl converter. 2022-11-17 00:32:11 +02:00
roman a2f8c7ebc1 Make sure options field exists on select field. 2022-11-16 22:33:29 +02:00
roman 1ae643b306 Remove duplicated code. 2022-11-16 22:28:17 +02:00
roman 52109f5010 Support Hubspot pages. 2022-11-16 22:12:02 +02:00
roman e0fb681d3b Merge pull request 'Fix handlebars path issue on Windows OS.' (#3) from window-path into master
Reviewed-on: #3
2022-11-15 14:43:10 +00:00
roman 840f73d739 Fix handlebars path issue on Windows OS. 2022-11-15 16:33:22 +02:00
roman 702cd6e226 Added StyleGuideUrl to top panel. 2022-11-15 07:59:05 +02:00
roman eabe411b7a Update Production registry URL. 2022-11-14 17:37:49 +02:00
roman 7bf571e0fb Merge pull request 'excluding_yeo' (#2) from excluding_yeo into master
Reviewed-on: #2
2022-11-13 09:23:58 +00:00
roman 73a10d9d55 Added namespace to "Basic Template" WordPress file. 2022-11-12 23:39:02 +02:00
roman 527416c63d Added exec-php to prod dependencies. 2022-11-12 23:36:30 +02:00
roman ac70e7eb9a Generate Template_Defaults file. 2022-11-12 23:32:01 +02:00
roman 05660eb4e4 Exclude YeoMan from the project.
Make the npm-install process faster.
2022-11-12 20:13:52 +02:00
roman 499c5b8163 Move sync command to create-block package. 2022-11-05 12:58:22 +02:00
roman 16f65254da Added sync command to project. 2022-11-05 12:52:30 +02:00
roman 812ea6d2c5 1.0.19 2022-11-04 11:56:07 +02:00
roman 28ad7f1571 1.0.18 2022-11-04 11:55:47 +02:00
41 changed files with 2024 additions and 15858 deletions
+57 -58
View File
@@ -1,74 +1,73 @@
#!/usr/bin/env node #!/usr/bin/env node
// For development purposes - run `npm run build-platform`.
import {exec} from 'child_process';
import config from 'config'; import config from 'config';
import Generator from "yeoman-generator"; import prompts from "prompts";
import yeoman from 'yeoman-environment'; import {buildHubspotEmail} from "./platforms/hubspot/hubspot-email-adapter.js";
import {buildHubspot} from "./platforms/hubspot/hubspot-adapter.js";
import {getConfigs} from "./helpers.js"; import {getConfigs} from "./helpers.js";
import {buildWordPress} from "./platforms/wordpress/wordpress-adapter.js"; import {buildWordPress} from "./platforms/wordpress/wordpress-adapter.js";
import path from "path"; import {buildHubspotPage} from "./platforms/hubspot/hubspot-page-adapter.js";
const {modulesPath, projectPath} = getConfigs(); const {isDev, developmentBlockName} = getConfigs();
const blockName = !isDev && config.has('blockName') ? config.get('blockName') : developmentBlockName;
const blockName = config.has('blockName') ? config.get('blockName') : 'development'; export const PLATFORM_OPTIONS = [{
name: 'wordpress',
title: 'WordPress'
}, {
name: 'wordpress-blocks',
title: 'WordPress Block'
}, {
name: 'wordpress-elementor',
title: 'WordPress Elementor'
}, {
name: 'hubspot',
title: 'Hubspot'
}, {
name: 'hubspot-email',
title: 'Hubspot Email'
}, {
name: 'javascript',
title: 'JavaScript'
}, {
name: 'php',
title: 'PHP'
}];
class buildGenerator extends Generator { const data = await getExportData();
async prompting() { const selectedPlatform = PLATFORM_OPTIONS[data['platform']];
this.data = await this.prompt([ await buildExportFiles(selectedPlatform);
{
type: "list",
name: "platform",
message: "Choose Platform",
choices: ['WordPress', 'WordPress Block', 'Hubspot', 'Hubspot Email', 'JavaScript', 'PHP'],
default: 'WordPress'
}
])
}
writing() { console.log('--------------------\nDone!');
new Promise((resolve => {
if (['WordPress', 'PHP'].includes(this.data.platform)) {
const backPath = modulesPath ? modulesPath.split('/').map(() => '..').join('/') : '';
return new Promise((resolve, reject) => { //
const phpGeneratorPath = path.join(modulesPath, 'platforms', 'php'); // Functions
exec(`cd ${phpGeneratorPath} && composer install && php build.php '${blockName}' '${backPath}' '${projectPath}'`, function (error, stdout) { //
if (error) {
console.log('Error:', error)
reject(error);
}
console.log(stdout); export async function buildExportFiles(platform) {
resolve(); if (platform.name.startsWith('wordpress')) {
}); if (platform.name === 'wordpress-blocks') {
}).then(() => { await buildWordPress(blockName, true);
if (this.data.platform === 'WordPress') { } else if (platform.name === 'wordpress-elementor') {
return buildWordPress(); await buildWordPress(blockName, false, true);
}
if (this.data.platform === 'WordPress Block') {
return buildWordPress(true);
}
});
} else if (this.data.platform === 'Hubspot Email') {
buildHubspot(blockName)
.then(() => {
resolve();
});
} else if (this.data.platform === 'Hubspot') {
console.log('"Hubspot" Coming soon...');
resolve();
} else { } else {
resolve(); await buildWordPress(blockName);
} }
})) } else if (platform.name === 'hubspot-email') {
.then(() => { await buildHubspotEmail(blockName)
console.log('--------------------\nDone!'); } else if (platform.name === 'hubspot') {
}); await buildHubspotPage(blockName)
} }
} }
const build = new buildGenerator([], {env: yeoman.createEnv()}, {}); function getExportData() {
build.run().then(() => null); return prompts([
{
type: "select",
name: "platform",
message: "Choose Platform",
choices: PLATFORM_OPTIONS.map(item => item.title),
default: 'WordPress'
}
]);
}
Executable
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env node
import {getConfigs} from "./helpers.js";
const {isDev, modulesPath, projectPath, developmentBlockName} = getConfigs();
console.log('----------------------------------\n')
console.log('Local Details', process.versions, '\n');
console.log('Configs', {
isDev,
modulesPath,
projectPath,
developmentBlockName
});
console.log('\n----------------------------------\n')
+49 -4
View File
@@ -3,6 +3,8 @@ import config from 'config';
import {fileURLToPath} from 'url'; import {fileURLToPath} from 'url';
import memFs from 'mem-fs'; import memFs from 'mem-fs';
import editor from 'mem-fs-editor'; import editor from 'mem-fs-editor';
import fsExtra from "fs-extra";
import archiver from "archiver";
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
@@ -14,13 +16,11 @@ export function getConfigs() {
return { return {
isDev, isDev,
developmentBlockName, developmentBlockName,
modulesPath: isDev ? '' : 'node_modules/block-dev-tool', modulesPath: process.env.MODULE_PATH ?? (isDev ? '' : 'node_modules/block-dev-tool'),
projectPath: isDev ? path.join('blocks', developmentBlockName) : '', projectPath: process.env.PROJECT_PATH ?? (isDev ? path.join('blocks', developmentBlockName) : ''),
}; };
} }
import fsExtra from "fs-extra";
export async function readJSONFile(jsonFile) { export async function readJSONFile(jsonFile) {
let data = {}; let data = {};
@@ -107,3 +107,48 @@ export function capitalize(str) {
}) })
.join(' '); .join(' ');
} }
export async function zipProject(srcDir, outputFileName = 'dist.zip') {
// create a file to stream archive data to.
const output = await fsExtra.createWriteStream(outputFileName);
const archive = archiver('zip', {});
// listen for all archive data to be written
// 'close' event is fired only when a file descriptor is involved
output.on('close', function () {
console.log(archive.pointer() + ' total bytes');
console.log('archiver has been finalized and the output file descriptor has closed.');
});
// This event is fired when the data source is drained no matter what was the data source.
// It is not part of this library but rather from the NodeJS Stream API.
// @see: https://nodejs.org/api/stream.html#stream_event_end
output.on('end', function () {
console.log('Data has been drained');
});
// good practice to catch warnings (ie stat failures and other non-blocking errors)
archive.on('warning', function (err) {
if (err.code === 'ENOENT') {
// log warning
} else {
// throw error
throw err;
}
});
// good practice to catch this error explicitly
archive.on('error', function (err) {
throw err;
});
// pipe archive data to the file
archive.pipe(output);
// append files from a subdirectory, putting its contents at the root of archive
archive.directory(srcDir, false);
// finalize the archive (ie we are done appending files but streams have to finish yet)
// 'close', 'end' or 'finish' may be fired right after calling this method so register to them beforehand
await archive.finalize();
}
+1 -1
View File
@@ -2,7 +2,7 @@
{{> (include_partial "layouts/partials/head") }} {{> (include_partial "layouts/partials/head") }}
<body> <body class="{{#if iframeMode}}body--iframe{{/if}}">
<main> <main>
{{> (include_block_template) }} {{> (include_block_template) }}
+1 -1
View File
@@ -2,7 +2,7 @@
{{> (include_partial "layouts/partials/head") }} {{> (include_partial "layouts/partials/head") }}
<body> <body class="{{#if iframeMode}}body--iframe{{/if}}">
<main> <main>
<div class="container"> <div class="container">
+1 -1
View File
@@ -18,7 +18,7 @@
</script> </script>
<div class="preview"> <div class="preview">
<iframe id="preview_frame" src="{{ previewFrameUrl }}" class="breakpoint"></iframe> <iframe id="preview_frame" src="{{ previewFrameUrl }}?iframe=true" class="breakpoint"></iframe>
</div> </div>
<script src="/scripts/dist/index.min.js"></script> <script src="/scripts/dist/index.min.js"></script>
+1 -1
View File
@@ -1,4 +1,4 @@
<script src="/scripts/frame-index.js"></script> <script src="/scripts/dist/frame-index.min.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://unpkg.com/swiper@8/swiper-bundle.min.js"></script>{{#if config.jsUrl }} <script src="https://unpkg.com/swiper@8/swiper-bundle.min.js"></script>{{#if config.jsUrl }}
{{#each config.jsUrl }}<script src="{{ this }}"></script> {{#each config.jsUrl }}<script src="{{ this }}"></script>
+4 -1
View File
@@ -9,6 +9,9 @@
</div> </div>
<div class="page_toolbar__right"> <div class="page_toolbar__right">
<a href="{{ previewFrameUrl }}" target="_blank" class="open_in_new_tab"></a> {{#if config.styleGuideUrl}}
<a href="{{ config.styleGuideUrl }}" target="_blank" class="palette" title="Open Style Guide"></a>
{{/if}}
<a href="{{ previewFrameUrl }}" target="_blank" class="open_in_new_tab" title="Open in New Window"></a>
</div> </div>
</header> </header>
+1
View File
@@ -0,0 +1 @@
!function(){let e;function n(n){const t=document.querySelector("body > main").scrollHeight;if(e===t)return;e=t,window.parent.postMessage("resize:"+JSON.stringify({height:e}),"*")}n(),new ResizeObserver(n).observe(document.body)}();
+15 -9821
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+4
View File
@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" fill="#21252d">
<path
d="M24 45.25q-4.35 0-8.225-1.675T9 39q-2.9-2.9-4.575-6.775Q2.75 28.35 2.75 24q0-4.5 1.675-8.375t4.625-6.75Q12 6 15.95 4.35q3.95-1.65 8.4-1.65 4.2 0 8 1.425t6.675 3.95Q41.9 10.6 43.6 14.05q1.7 3.45 1.7 7.5 0 5.7-3.2 9.35-3.2 3.65-8.9 3.65h-2.9q-.8 0-1.4.65-.6.65-.6 1.45 0 1.25.5 1.75t.5 1.55q0 2.2-1.5 3.75-1.5 1.55-3.8 1.55ZM24 24Zm-11.2 1.3q1 0 1.75-.75t.75-1.75q0-1-.75-1.75t-1.75-.75q-1 0-1.75.75t-.75 1.75q0 1 .75 1.75t1.75.75Zm6.1-8.15q1 0 1.75-.75t.75-1.75q0-1.05-.75-1.775-.75-.725-1.75-.725-1.05 0-1.775.725-.725.725-.725 1.725 0 1.05.725 1.8t1.775.75Zm10.25 0q1 0 1.75-.75t.75-1.75q0-1.05-.75-1.775-.75-.725-1.75-.725-1.05 0-1.775.725-.725.725-.725 1.725 0 1.05.725 1.8t1.775.75Zm6.2 8.15q1 0 1.75-.75t.75-1.75q0-1-.75-1.75t-1.75-.75q-1.05 0-1.775.75-.725.75-.725 1.75t.725 1.75q.725.75 1.775.75ZM23.8 40.55q.4 0 .6-.175.2-.175.2-.625 0-.7-.75-1.175-.75-.475-.75-2.375 0-2.45 1.65-4.4 1.65-1.95 4.1-1.95h4.35q3.7 0 5.525-2.2 1.825-2.2 1.825-5.8 0-6.6-4.925-10.5Q30.7 7.45 24.4 7.45q-7.1 0-12.025 4.825Q7.45 17.1 7.45 24q0 6.9 4.8 11.725 4.8 4.825 11.55 4.825Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

-27
View File
@@ -1,27 +0,0 @@
'use strict';
const heightLimit = window.outerHeight * 2;
let height = getCurrentHeight();
setupResizeListener();
///
function setupResizeListener() {
const resizeObserver = new ResizeObserver(handleHeightChange);
resizeObserver.observe(document.body);
}
function handleHeightChange(entries) {
const updatedHeight = getCurrentHeight();
if (height === updatedHeight || updatedHeight > heightLimit) {
return;
}
const RESIZE_CODE = 'resize:';
window.parent.postMessage(RESIZE_CODE + JSON.stringify({height}), '*');
height = updatedHeight;
}
function getCurrentHeight() {
return document.querySelector('body > main').scrollHeight;
}
+17
View File
@@ -0,0 +1,17 @@
export function setupFrameResizeListener() {
const previewFrame = getPreviewFrame();
window.addEventListener('message', function (e) {
const RESIZE_CODE = 'resize:';
if (typeof e.data !== 'string' || !e.data.startsWith(RESIZE_CODE)) {
return;
}
const data = JSON.parse(e.data.substring(RESIZE_CODE.length))
previewFrame.style.height = data.height + 'px'
});
}
export function getPreviewFrame() {
return document.getElementById('preview_frame');
}
+46
View File
@@ -0,0 +1,46 @@
'use strict';
// Blocks Initialization.
function initBlock(blockName = '', selector = '', cb) {
document.querySelectorAll(selector).forEach((el) => cb(el));
}
// Scrollbars / Frame resizes notifications.
(function () {
let height;
const debug = false;
handleHeightChange(); // Initial frame's height setup.
setupResizeListener(); // Listen to frame's height changes.
///
function setupResizeListener() {
const resizeObserver = new ResizeObserver(handleHeightChange);
resizeObserver.observe(document.body);
}
function handleHeightChange(entries) {
const updatedHeight = getCurrentHeight();
if (debug) {
console.log('Height Updates', 'Old vs New: ' + height, updatedHeight);
}
if (height === updatedHeight) {
return;
}
const RESIZE_CODE = 'resize:';
height = updatedHeight;
window.parent.postMessage(RESIZE_CODE + JSON.stringify({height}), '*');
if (debug) {
console.log('Resize message sent: ', height)
}
}
function getCurrentHeight() {
return document.querySelector('body > main').scrollHeight;
}
})();
+5 -14
View File
@@ -3,22 +3,13 @@
import {setupResponsiveness} from './toolbar/responsive.jsx'; import {setupResponsiveness} from './toolbar/responsive.jsx';
import {setupPublish} from "./toolbar/publish.jsx"; import {setupPublish} from "./toolbar/publish.jsx";
import {setupDataOptions} from "./toolbar/data-options/DataOptions.jsx"; import {setupDataOptions} from "./toolbar/data-options/DataOptions.jsx";
import {getPreviewFrame, setupFrameResizeListener} from "./frame/editor.js";
const previewFrame = document.getElementById('preview_frame');
const rootAttributes = { const rootAttributes = {
previewFrame, previewFrame: getPreviewFrame(),
} };
setupFrameResizeListener();
setupResponsiveness(rootAttributes); setupResponsiveness(rootAttributes);
setupDataOptions(rootAttributes); setupDataOptions(rootAttributes);
setupPublish(rootAttributes) setupPublish(rootAttributes);
window.addEventListener('message', function (e) {
const RESIZE_CODE = 'resize:';
if (typeof e.data !== 'string' || !e.data.startsWith(RESIZE_CODE)) {
return;
}
const data = JSON.parse(e.data.substring(RESIZE_CODE.length))
previewFrame.style.height = data.height + 'px';
});
@@ -98,7 +98,12 @@ function DataOptions(props = {}) {
async function changeDataOption(e) { async function changeDataOption(e) {
const dataName = e.target.value; const dataName = e.target.value;
props.rootAttributes.previewFrame.src = window.devTool.previewFrameUrl + '?data=' + dataName;
const previewFrameUrl = new URL(window.devTool.previewFrameUrl);
previewFrameUrl.searchParams.set('data', dataName);
previewFrameUrl.searchParams.set('iframe', 'true');
props.rootAttributes.previewFrame.src = previewFrameUrl.href;
const dataOption = await fetchDataOptions(dataName); const dataOption = await fetchDataOptions(dataName);
updateState(Object.assign({}, dataOption, {dataName})); updateState(Object.assign({}, dataOption, {dataName}));
@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" fill="#21252d">
<path
d="M24 45.25q-4.35 0-8.225-1.675T9 39q-2.9-2.9-4.575-6.775Q2.75 28.35 2.75 24q0-4.5 1.675-8.375t4.625-6.75Q12 6 15.95 4.35q3.95-1.65 8.4-1.65 4.2 0 8 1.425t6.675 3.95Q41.9 10.6 43.6 14.05q1.7 3.45 1.7 7.5 0 5.7-3.2 9.35-3.2 3.65-8.9 3.65h-2.9q-.8 0-1.4.65-.6.65-.6 1.45 0 1.25.5 1.75t.5 1.55q0 2.2-1.5 3.75-1.5 1.55-3.8 1.55ZM24 24Zm-11.2 1.3q1 0 1.75-.75t.75-1.75q0-1-.75-1.75t-1.75-.75q-1 0-1.75.75t-.75 1.75q0 1 .75 1.75t1.75.75Zm6.1-8.15q1 0 1.75-.75t.75-1.75q0-1.05-.75-1.775-.75-.725-1.75-.725-1.05 0-1.775.725-.725.725-.725 1.725 0 1.05.725 1.8t1.775.75Zm10.25 0q1 0 1.75-.75t.75-1.75q0-1.05-.75-1.775-.75-.725-1.75-.725-1.05 0-1.775.725-.725.725-.725 1.725 0 1.05.725 1.8t1.775.75Zm6.2 8.15q1 0 1.75-.75t.75-1.75q0-1-.75-1.75t-1.75-.75q-1.05 0-1.775.75-.725.75-.725 1.75t.725 1.75q.725.75 1.775.75ZM23.8 40.55q.4 0 .6-.175.2-.175.2-.625 0-.7-.75-1.175-.75-.475-.75-2.375 0-2.45 1.65-4.4 1.65-1.95 4.1-1.95h4.35q3.7 0 5.525-2.2 1.825-2.2 1.825-5.8 0-6.6-4.925-10.5Q30.7 7.45 24.4 7.45q-7.1 0-12.025 4.825Q7.45 17.1 7.45 24q0 6.9 4.8 11.725 4.8 4.825 11.55 4.825Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+1 -1
View File
@@ -1,4 +1,4 @@
import React, {useEffect, useState} from 'react'; import React, {useState} from 'react';
import * as ReactDOM from 'react-dom/client'; import * as ReactDOM from 'react-dom/client';
function Publish(props = {}) { function Publish(props = {}) {
+16
View File
@@ -0,0 +1,16 @@
<html lang="en">
{{> (include_partial "layouts/partials/head") }}
<body class="{{#if iframeMode}}body--iframe{{/if}}">
<main>
<section class="fullscreen_layout"></section>
{{> (include_block_template) }}
<section class="fullscreen_layout"></section>
</main>
{{> (include_partial "layouts/partials/scripts") }}
</body>
</html>
+9
View File
@@ -0,0 +1,9 @@
.swiper {
&-slide {
width: initial;
}
&-wrapper {
height: initial;
}
}
+6 -2
View File
@@ -139,11 +139,11 @@ body {
max-width: var(--breakpoint); max-width: var(--breakpoint);
} }
.open_in_new_tab { .open_in_new_tab, .palette {
--size: 1.5rem; --size: 1.5rem;
width: var(--size); width: var(--size);
height: var(--size); height: var(--size);
background-image: url("/scripts/toolbar/images/icon-open-new-tab.svg"); background-image: url("/scripts/dist/toolbar/images/icon-open-new-tab.svg");
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: calc(var(--size) - 0.15rem); background-size: calc(var(--size) - 0.15rem);
background-position: center center; background-position: center center;
@@ -158,4 +158,8 @@ body {
outline: none; outline: none;
} }
.palette {
background-image: url("/scripts/dist/toolbar/images/icon-palette.svg");
}
/*# sourceMappingURL=page--main.css.map */ /*# sourceMappingURL=page--main.css.map */
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sourceRoot":"","sources":["page--main.scss","_buttons.scss","_overlay.scss","_page--preview.scss"],"names":[],"mappings":"AAAA;EACE;EACA;;;AAGF;EACE;EACA;EAEA;;;ACTF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;;;AC5BJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AFIF;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EAEA;EACA;EACA;EAEA;EACA;;AAEA;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAEA;EAHF;IAII;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAKF;EADF;IAEI;;;AAKN;EAEE;EACA;EACA;EACA;;AAGF;EACE;;;AGlFJ;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EACA;EAEA;EACA;EAEA;;AAEA;EACE;EAEA;EACA;;;AH6DJ;EACE;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA","file":"page--main.css"} {"version":3,"sourceRoot":"","sources":["page--main.scss","_buttons.scss","_overlay.scss","_page--preview.scss"],"names":[],"mappings":"AAAA;EACE;EACA;;;AAGF;EACE;EACA;EAEA;;;ACTF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;;;AC5BJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AFIF;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EAEA;EACA;EACA;EAEA;EACA;;AAEA;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAEA;EAHF;IAII;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAKF;EADF;IAEI;;;AAKN;EAEE;EACA;EACA;EACA;;AAGF;EACE;;;AGlFJ;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EACA;EAEA;EACA;EAEA;;AAEA;EACE;EAEA;EACA;;;AH6DJ;EACE;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EAEE","file":"page--main.css"}
+6 -1
View File
@@ -92,7 +92,7 @@ body {
width: var(--size); width: var(--size);
height: var(--size); height: var(--size);
background-image: url("/scripts/toolbar/images/icon-open-new-tab.svg"); background-image: url("/scripts/dist/toolbar/images/icon-open-new-tab.svg");
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: calc(var(--size) - 0.15rem); background-size: calc(var(--size) - 0.15rem);
background-position: center center; background-position: center center;
@@ -107,3 +107,8 @@ body {
border-radius: 0.25rem; border-radius: 0.25rem;
outline: none; outline: none;
} }
.palette {
@extend .open_in_new_tab;
background-image: url("/scripts/dist/toolbar/images/icon-palette.svg");
}
+22 -1
View File
@@ -1,11 +1,32 @@
body { body {
margin: 0; margin: 0;
overflow-y: hidden;
} }
main { main {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
min-height: 100%;
overflow-x: hidden;
}
main .swiper-slide {
width: initial;
}
main .swiper-wrapper {
height: initial;
}
.body--iframe {
overflow-y: hidden;
}
.body--iframe main {
overflow-y: auto;
}
.fullscreen_layout {
background-color: #9cc3ff;
min-height: 100%;
background-image: url("https://i.ibb.co/pjwL8D1/shapelined-JBKdviwe-XI-unsplash.jpg");
background-size: cover;
} }
/*# sourceMappingURL=page--view.css.map */ /*# sourceMappingURL=page--view.css.map */
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sourceRoot":"","sources":["page--view.scss"],"names":[],"mappings":"AAAA;EACE;EACA;;;AAGF;EACE;EACA","file":"page--view.css"} {"version":3,"sourceRoot":"","sources":["page--view.scss","_page--view-swiper.scss"],"names":[],"mappings":"AAAA;EACE;;;AAGF;EACE;EACA;EACA;EACA;;ACPA;EACE;;AAGF;EACE;;;ADSJ;EACE;;AAEA;EAGE;;;AAIJ;EACE;EACA;EACA;EACA","file":"page--view.css"}
+23 -9
View File
@@ -1,18 +1,32 @@
body { body {
margin: 0; margin: 0;
overflow-y: hidden;
} }
main { main {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
min-height: 100%;
overflow-x: hidden;
// Fixes scrolling issues of swiperJS. Should be included in all projects.
@import "page--view-swiper";
}
// iFrame mode
.body--iframe {
overflow-y: hidden;
main {
// If you change to "overflow: initial", the margin-top/bottom of first/last element will be not included.
// Test on fresh block setup where heading has margin-top.
overflow-y: auto;
}
}
.fullscreen_layout {
background-color: #9cc3ff;
min-height: 100%;
background-image: url('https://i.ibb.co/pjwL8D1/shapelined-JBKdviwe-XI-unsplash.jpg');
background-size: cover;
} }
// Container rules must be provided by the projectStyles (theme).
//.container {
// max-width: 1200px;
// margin-left: auto;
// margin-right: auto;
// padding-left: 15px;
// padding-right: 15px;
//}
+1181 -5697
View File
File diff suppressed because it is too large Load Diff
+16 -8
View File
@@ -1,6 +1,6 @@
{ {
"name": "@axe-web/block-dev-tool", "name": "@axe-web/block-dev-tool",
"version": "1.0.18", "version": "1.0.22",
"author": { "author": {
"name": "AXE-WEB", "name": "AXE-WEB",
"email": "office@axe-web.com", "email": "office@axe-web.com",
@@ -8,11 +8,12 @@
}, },
"scripts": { "scripts": {
"start": "component-dev", "start": "component-dev",
"dev": "NODE_ENV=development NODE_CONFIG_DIR=blocks/team/config BLOCK_NAME=team node server.js", "info": "node debug.js",
"dev": "NODE_ENV=development NODE_CONFIG_DIR=blocks/text-block/config BLOCK_NAME=text-block node server.js",
"build": "rollup --config rollup.config.js", "build": "rollup --config rollup.config.js",
"build-platform": "NODE_ENV=development NODE_CONFIG_DIR=blocks/team/config BLOCK_NAME=team node ./build.js", "build-platform": "NODE_ENV=development NODE_CONFIG_DIR=blocks/text-block/config BLOCK_NAME=text-block node ./build.js",
"build-platform-cli": "component-build", "build-platform-cli": "component-build",
"dev-js": "rollup --config rollup.config.js --watch" "dev-js": "NODE_ENV=development rollup --config rollup.config.js --watch"
}, },
"license": "ISC", "license": "ISC",
"type": "module", "type": "module",
@@ -22,6 +23,7 @@
"browser-sync": "^2.27.9", "browser-sync": "^2.27.9",
"config": "^3.3.7", "config": "^3.3.7",
"escape-html": "^1.0.3", "escape-html": "^1.0.3",
"exec-php": "^0.0.6",
"express": "^4.17.3", "express": "^4.17.3",
"express-handlebars": "^6.0.4", "express-handlebars": "^6.0.4",
"fs-extra": "^10.0.1", "fs-extra": "^10.0.1",
@@ -37,10 +39,9 @@
"node-fetch": "^3.2.10", "node-fetch": "^3.2.10",
"open": "^8.4.0", "open": "^8.4.0",
"plugin-error": "^2.0.0", "plugin-error": "^2.0.0",
"prompts": "^2.4.2",
"sanitize-html": "^2.7.1", "sanitize-html": "^2.7.1",
"sass": "^1.50.1", "sass": "^1.50.1"
"yeoman-environment": "^3.10.0",
"yeoman-generator": "^5.6.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/preset-react": "^7.18.6", "@babel/preset-react": "^7.18.6",
@@ -54,6 +55,7 @@
"rollup": "^2.77.2", "rollup": "^2.77.2",
"rollup-plugin-copy": "^3.4.0", "rollup-plugin-copy": "^3.4.0",
"rollup-plugin-jsx": "^1.0.3", "rollup-plugin-jsx": "^1.0.3",
"rollup-plugin-terser": "^7.0.2",
"styled-components": "^5.3.5" "styled-components": "^5.3.5"
}, },
"bin": { "bin": {
@@ -62,7 +64,13 @@
}, },
"files": [ "files": [
"helpers.js", "helpers.js",
"layouts/**/*", "debug.js",
"layouts/**/*.hbs",
"layouts/styles/*.css*",
"layouts/scripts/dist/*.js*",
"layouts/scripts/dist/**/*.jpg",
"layouts/scripts/dist/**/*.png",
"layouts/scripts/dist/**/*.svg",
"platforms/**/*" "platforms/**/*"
] ]
} }
@@ -1,47 +1,31 @@
import path from "path";
import {readFile, writeFile, mkdir, copyFile} from "fs/promises"; import {readFile, writeFile, mkdir, copyFile} from "fs/promises";
import {capitalize, getConfigs} from "../../helpers.js";
export async function buildHubspot(blockName) { export async function buildHubspotEmail(blockName) {
const distPath = `./exports/hubspot/${blockName}.module`; const distPath = await createDistFolder(blockName);
await mkdir(distPath, {recursive: true})
await copyFile(`./src/${blockName}.template.hbs`, `${distPath}/module.html`)
const metaData = { // Template
let handlebars = await readFile(path.join(srcPath, `${blockName}.template.hbs`), "utf8");
await writeFile(path.join(distPath, 'module.html'), handlebarsToHubl(handlebars));
// JSON
await buildHubspotJSONFiles(distPath, {
global: false, global: false,
host_template_types: ["EMAIL"], host_template_types: ["EMAIL"],
label: capitalize(blockName), label: capitalize(blockName),
is_available_for_new_content: true is_available_for_new_content: true
}
await writeFile(`${distPath}/meta.json`, JSON.stringify(metaData, null, 4));
const blockJSON = await readFile(`./block.json`, "utf8");
const block = JSON.parse(blockJSON);
const fields = getBlockFields(block, 'content');
// Styling TAB.
const stylingFields = getBlockFields(block, 'styling');
if (stylingFields.length) {
const stylingFieldsByName = {};
stylingFields.forEach(field => stylingFieldsByName[field.name] = field);
const stylingGroup = convertToHubspotField({
type: 'group',
name: 'style',
label: "Style",
sub_fields: stylingFieldsByName,
}); });
stylingGroup.tab = "STYLE";
fields.push(stylingGroup);
}
// Export JSON file.
await writeFile(`${distPath}/fields.json`, JSON.stringify(fields, null, 4));
} }
function getBlockFields(block = {}, type = 'content') { export async function createDistFolder(blockName) {
const distPath = path.join('exports', 'hubspot', `${blockName}.module`);
await mkdir(distPath, {recursive: true})
return distPath;
}
export function getBlockFields(block = {}, type = 'content') {
const fields_group = block['field_groups'].find((group) => group.name === type); const fields_group = block['field_groups'].find((group) => group.name === type);
const fields = []; const fields = [];
@@ -61,7 +45,7 @@ function getBlockFields(block = {}, type = 'content') {
}); });
} }
function convertToHubspotField(field = {}) { export function convertToHubspotField(field = {}) {
const data = { const data = {
id: field.name, id: field.name,
name: field.name, name: field.name,
@@ -70,9 +54,12 @@ function convertToHubspotField(field = {}) {
validation_regex: "", validation_regex: "",
required: false, required: false,
locked: false, locked: false,
default: field.default
}; };
if (field.default) {
data.default = field.default;
}
let sub_fields = []; let sub_fields = [];
switch (field.type) { switch (field.type) {
@@ -111,12 +98,14 @@ function convertToHubspotField(field = {}) {
display: "checkbox", display: "checkbox",
}); });
case 'select': case 'select':
const choices = []; const options = [];
Object.keys(data.choices).forEach(value => choices.push([value, data.choices[value]])); if (field.options) {
Object.keys(field.options).forEach(value => options.push([value, field.options[value]]));
}
return Object.assign({}, data, { return Object.assign({}, data, {
type: "select", type: "choice",
choices: [choices] choices: options
}); });
case 'link': case 'link':
return Object.assign({}, data, { return Object.assign({}, data, {
@@ -225,17 +214,54 @@ function convertToHubspotField(field = {}) {
} }
} }
export function capitalize(str) { export async function buildHubspotJSONFiles(distPath, metaData) {
if (typeof str !== 'string') { const {modulesPath, projectPath} = getConfigs();
return ''; await writeFile(path.join(distPath, 'meta.json'), JSON.stringify(metaData, null, 4));
const blockJSON = await readFile(path.join(projectPath, 'block.json'), "utf8");
const block = JSON.parse(blockJSON);
const fields = getBlockFields(block, 'content');
// Styling TAB.
const stylingFields = getBlockFields(block, 'styling');
if (stylingFields.length) {
const stylingFieldsByName = {};
stylingFields.forEach(field => stylingFieldsByName[field.name] = field);
const stylingGroup = convertToHubspotField({
type: 'group',
name: 'style',
label: "Style",
});
stylingGroup.children = Object.values(stylingFieldsByName);
stylingGroup.tab = "STYLE";
fields.push(stylingGroup);
} }
return str // Export JSON file.
.toLowerCase() await writeFile(path.join(distPath, 'fields.json'), JSON.stringify(fields, null, 4));
.split(/[ -_]/g) }
.filter((word) => !!word)
.map((word) => {
return word.charAt(0).toUpperCase() + word.slice(1); export function handlebarsToHubl(handlebars) {
}) handlebars = handlebars.replace(/{{#if /g, '{% if module.');
.join(' '); handlebars = handlebars.replace(/{{\/if}}/g, '{% endif %}');
handlebars = handlebars.replace(/{{#each /g, '{% for module.');
handlebars = handlebars.replace(/{{\/each}}/g, '{% endfor %}');
handlebars = handlebars.replace(/{{base_url}}/g, '');
handlebars = handlebars.replace(/{esc_attr /g, '{');
handlebars = handlebars.replace(/{esc_url /g, '{');
handlebars = handlebars.replace(/{esc_html /g, '{');
handlebars = handlebars.replace(/{{{ /g, '{{');
handlebars = handlebars.replace(/ }}}/g, '}}');
handlebars = handlebars.replace(/{{{/g, '{{');
handlebars = handlebars.replace(/}}}/g, '}}');
handlebars = handlebars.replace(/{{/g, '{{module.');
handlebars = handlebars.replace(/{{module. /g, '{{ module.');
return handlebars;
} }
+28
View File
@@ -0,0 +1,28 @@
import path from "path";
import {copyFile, readFile, writeFile} from "fs/promises";
import {capitalize, getConfigs} from "../../helpers.js";
import {buildHubspotJSONFiles, createDistFolder, handlebarsToHubl,} from "./hubspot-email-adapter.js";
export async function buildHubspotPage(blockName) {
const {modulesPath, projectPath} = getConfigs();
const distPath = await createDistFolder(blockName);
const srcPath = path.join(projectPath, 'src');
// Template
let handlebars = await readFile(path.join(srcPath, `${blockName}.template.hbs`), "utf8");
await writeFile(path.join(distPath, 'module.html'), handlebarsToHubl(handlebars));
// Assets
await copyFile(path.join(srcPath, 'styles', `${blockName}.min.css`), path.join(distPath, 'module.css'));
await copyFile(path.join(srcPath, 'scripts', `${blockName}.min.js`), path.join(distPath, 'module.js'));
// await copy(path.join(projectPath, 'src', 'images'), path.join(distPath, 'images'));
// JSON
await buildHubspotJSONFiles(distPath, {
global: false,
host_template_types: ["PAGE"],
label: capitalize(blockName),
is_available_for_new_content: true
});
}
+21 -14
View File
@@ -3,8 +3,10 @@
// Composer - Autoloader // Composer - Autoloader
require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/vendor/autoload.php';
use Brick\VarExporter\ExportException;
use LightnCandy\Flags; use LightnCandy\Flags;
use LightnCandy\LightnCandy; use LightnCandy\LightnCandy;
use Brick\VarExporter\VarExporter;
trait Custom_Handlebars { trait Custom_Handlebars {
public array $custom_handlebars = []; public array $custom_handlebars = [];
@@ -52,7 +54,8 @@ class Component_Builder {
use Custom_Handlebars; use Custom_Handlebars;
public string $component_name = ''; public string $component_name = '';
private string $module_path = ''; public string $module_path = '';
public string $project_path = '';
function __construct( $component_name, $module_path, $project_path ) { function __construct( $component_name, $module_path, $project_path ) {
$this->module_path = $module_path; $this->module_path = $module_path;
@@ -63,22 +66,15 @@ class Component_Builder {
function build(): void { function build(): void {
$root_path = __DIR__ . '/' . $this->module_path . '/../../' . $this->project_path; $root_path = __DIR__ . '/' . $this->module_path . '/../../' . $this->project_path;
$this->buildTemplatePhpFile( $root_path );
}
private function buildTemplatePhpFile( $root_path ) {
$file_name = $this->get_handlebars_template( "$root_path/src/$this->component_name.template.hbs" ); $file_name = $this->get_handlebars_template( "$root_path/src/$this->component_name.template.hbs" );
$output_folder = $root_path . '/exports/wordpress/templates'; $output_folder = $root_path . '/exports/wordpress/templates';
foreach ( [ 'styles', 'scripts', 'images' ] as $dir ) {
$output_dir = "$output_folder/$dir";
if ( is_dir( $output_dir ) === false ) {
mkdir( $output_dir, 0777, true );
}
}
rename( $file_name, "$output_folder/$this->component_name.template.php" ); rename( $file_name, "$output_folder/$this->component_name.template.php" );
copy( "$root_path/src/styles/$this->component_name.min.css", "$output_folder/styles/$this->component_name.min.css" );
copy( "$root_path/src/scripts/$this->component_name.min.js", "$output_folder/scripts/$this->component_name.min.js" );
shell_exec( "cp -r $root_path/src/images $output_folder" );
echo "Generated '$file_name'.";
} }
private function get_handlebars_template( $path = '' ): string { private function get_handlebars_template( $path = '' ): string {
@@ -123,4 +119,15 @@ class Component_Builder {
} }
} }
( new Component_Builder( $argv[1], $argv[2], $argv[3] ) )->build(); function build( $args = [] ) {
( new Component_Builder( $args['blockName'], $args['backPath'], $args['projectPath'] ) )->build();
}
/**
* @throws ExportException
*/
function jsonToPhp( $args = [] ): ?string {
$json = $args['json'] ?? [];
return VarExporter::export( $json );
}
+2 -1
View File
@@ -6,6 +6,7 @@
}, },
"require": { "require": {
"php": ">=8.0", "php": ">=8.0",
"zordius/lightncandy": "^1.2.6" "zordius/lightncandy": "^1.2.6",
"brick/varexporter": "^0.3.7"
} }
} }
+106 -1
View File
@@ -4,8 +4,113 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "1d9b4e7a02be366b48383c185193727f", "content-hash": "6731e0a19d488ee457b6682e62ef9018",
"packages": [ "packages": [
{
"name": "brick/varexporter",
"version": "0.3.7",
"source": {
"type": "git",
"url": "https://github.com/brick/varexporter.git",
"reference": "3e263cd718d242594c52963760fee2059fd5833c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/brick/varexporter/zipball/3e263cd718d242594c52963760fee2059fd5833c",
"reference": "3e263cd718d242594c52963760fee2059fd5833c",
"shasum": ""
},
"require": {
"nikic/php-parser": "^4.0",
"php": "^7.2 || ^8.0"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.2",
"phpunit/phpunit": "^8.5 || ^9.0",
"vimeo/psalm": "4.23.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Brick\\VarExporter\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A powerful alternative to var_export(), which can export closures and objects without __set_state()",
"keywords": [
"var_export"
],
"support": {
"issues": "https://github.com/brick/varexporter/issues",
"source": "https://github.com/brick/varexporter/tree/0.3.7"
},
"funding": [
{
"url": "https://github.com/BenMorel",
"type": "github"
}
],
"time": "2022-06-29T23:37:57+00:00"
},
{
"name": "nikic/php-parser",
"version": "v4.15.2",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc",
"reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": ">=7.0"
},
"require-dev": {
"ircmaxell/php-yacc": "^0.0.7",
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
},
"bin": [
"bin/php-parse"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.9-dev"
}
},
"autoload": {
"psr-4": {
"PhpParser\\": "lib/PhpParser"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Nikita Popov"
}
],
"description": "A PHP parser written in PHP",
"keywords": [
"parser",
"php"
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.2"
},
"time": "2022-11-12T15:38:23+00:00"
},
{ {
"name": "zordius/lightncandy", "name": "zordius/lightncandy",
"version": "v1.2.6", "version": "v1.2.6",
@@ -1,31 +1,49 @@
<?php <?php
use Core\Global_Functions; namespace AXEWEB_Blocks\Blocks\<%= ownerClass %>\<%= blockClassModel %>;
class <%= blockClassModel %>_Component { class <%= blockClassModel %>_Component {
public function __construct() { public function __construct() {
add_action( 'wp_enqueue_scripts', [ $this, 'register_assets' ] ); // add_action( 'wp_enqueue_scripts', [ $this, 'register_assets' ] );
add_action( 'after_setup_theme', [ $this, 'register_assets' ] );
} }
function register_assets(): void { function register_assets(): void {
wp_enqueue_style( '<%= blockFilename %>', // $version = get_plugin_data( __DIR__ . "/../../scytale-custom-blocks.php" )['Version']; // In Plugins
get_template_directory_uri() . '/components/partials/<%= blockFilename %>/templates/styles/<%= blockFilename %>.min.css', $version = \Core\Global_Functions::get_current_version_number(); // In Theme
[ 'style-wp' ],
Global_Functions::get_current_version_number()
);
wp_enqueue_script( '<%= blockFilename %>', // $base_path = plugin_dir_url( __FILE__ ); // In Plugins
get_template_directory_uri() . '/components/partials/<%= blockFilename %>/templates/scripts/<%= blockFilename %>.min.js', $base_path = get_template_directory_uri() . '/components/partials/<%= blockFilename %>/';
wp_register_style( '<%= blockFilename %>',
$base_path . 'templates/styles/<%= blockFilename %>.min.css',
[ 'style-wp' ],
$version
);
wp_enqueue_style( '<%= blockFilename %>' );
wp_register_script( 'script-<%= blockFilename %>',
$base_path . 'templates/scripts/<%= blockFilename %>.min.js',
[ 'jquery', 'swiper' ], [ 'jquery', 'swiper' ],
Global_Functions::get_current_version_number(), $version,
true true
); );
wp_enqueue_script( 'script-<%= blockFilename %>' );
} }
public function render( $args = [] ): void { public function render( $args = [] ): void {
$output = ( include( __DIR__ . '/templates/<%= blockFilename %>.template.php' ) )( array_merge( [], $args ), self::class ); $args = array_merge( [], Helpers\<%= blockClassModel %>_Defaults::default_args( $args ), $args);
$output = ( include( __DIR__ . '/templates/<%= blockFilename %>.template.php' ) )( $args, self::class );
echo apply_filters( 'the_content', wpautop( $output ) ); echo apply_filters( 'the_content', wpautop( $output ) );
} }
<% if (isElementor) { %>function register_elementor_widget( $widgets_manager ): void {
require_once "helpers/<%= blockClassModel %>_Elementor_Widget.php";
$widgets_manager->register_widget_type( new Helpers\<%= blockClassModel %>_Elementor_Widget() );
}<% } %>
} }
// ( new <%= blockClassModel %>_Component() ); // Initialization
@@ -5,23 +5,27 @@ namespace AXEWEB_Blocks\Blocks\<%= ownerClass %>\<%= blockClassModel %>;
class <%= blockClassModel %>_Component extends \Core\Component { class <%= blockClassModel %>_Component extends \Core\Component {
public function get_content( $args = [] ): string { public function get_content( $args = [] ): string {
$args = array_merge( Helpers\<%= blockClassModel %>_Defaults::default_args(), $args ); $default_args = apply_filters( 'axeweb_blocks/<%= ownerFilename %>/<%= blockFilename %>::default_args', [] ); // Not really practical.
$args = Helpers\<%= blockClassModel %>_API::prepare_args( $args );
<% if (templateFormat === 'hbs') { %>return $this->get_component_template( __DIR__ . '/templates/<%= blockFilename %>.template.hbs', $args );<% } %> $args = apply_filters( 'axeweb_blocks/<%= ownerFilename %>/<%= blockFilename %>::prepare_args', array_merge( $default_args, $args ) );
<% if (templateFormat === 'php') { %>
$output = ( include( __DIR__ . '/templates/<%= blockFilename %>.template.php' ) )( array_merge( [], $args ), self::class ); $output = ( include( __DIR__ . '/templates/<%= blockFilename %>.template.php' ) )( $args, self::class );
echo apply_filters( 'the_content', wpautop( $output ) );
<% } %> return apply_filters( 'axeweb_blocks/<%= ownerFilename %>/<%= blockFilename %>::content', $output );
} }
<% if (!include_acf_block && !include_native_gutenberg_block) { %> <% if (!include_acf_block && !include_native_gutenberg_block) { %>function register_assets(): void {
public function register_assets() { $version = get_plugin_data( __DIR__ . "/../../scytale-custom-blocks.php" )['Version']; // In Plugins
$this->add_style( __DIR__ . '/templates/styles/<%= blockFilename %>.min.css' ); // $version = \Core\Global_Functions::get_current_version_number(); // In Theme
<% if (include_script) { %>$this->add_script( __DIR__ . '/templates/scripts/<%= blockFilename %>.js' );<% } %>
}
<% } %><% if (include_elementor_widget) { %> function register_custom_logic(): void { // $base_path = get_template_directory_uri() . '/components/partials/<%= blockFilename %>/';
wp_enqueue_style( 'block-<%= blockFilename %>', plugins_url( 'templates/styles/<%= blockFilename %>.min.css', __FILE__ ), ['assets-style'], get_blocks_version() );<% if (include_script) { %>
wp_enqueue_script( 'block-<%= blockFilename %>', plugins_url( 'templates/scripts/<%= blockFilename %>.min.js', __FILE__ ), ['assets-script'], get_blocks_version(), true );<% } %>
wp_enqueue_script( 'script-block-<%= blockFilename %>' );
}<% } %>
<% if (include_elementor_widget) { %>function register_custom_logic(): void {
add_action( 'elementor/widgets/widgets_registered', [ $this, 'register_elementor_widget' ] ); add_action( 'elementor/widgets/widgets_registered', [ $this, 'register_elementor_widget' ] );
} }
@@ -31,21 +35,17 @@ class <%= blockClassModel %>_Component extends \Core\Component {
<% } %><% if (include_acf_block) { %> function register_acf_block() { <% } %><% if (include_acf_block) { %> function register_acf_block() {
$this->register_block( __DIR__ . "/<%= blockFilename %>.block.json", [ $this->register_block( __DIR__ . "/<%= blockFilename %>.block.json", [
'enqueue_assets' => function () { 'style_assets' => [
wp_enqueue_style( '<%= blockFilename %>', \Core\Global_Functions::get_file_url( __DIR__ . '/templates/styles/<%= blockFilename %>.min.css', true ), [], get_blocks_version() );<% if (include_script) { %> [
wp_enqueue_script( '<%= blockFilename %>', \Core\Global_Functions::get_file_url( __DIR__ . '/templates/scripts/<%= blockFilename %>.js', true ), ['assets-script'], get_blocks_version() );<% } %> 'name' => '<%= blockFilename %>',
}, 'url' => plugins_url( 'templates/styles/<%= blockFilename %>.min.css', __FILE__ ),
'default' => Helpers\<%= blockClassModel %>_Defaults::default_args(), ]
'supports' => [
//'jsx' => true,
'color' => [
'background' => true,
'text' => true,
],
'spacing' => [
'margin' => [ 'top', 'bottom' ],
'padding' => [ 'top', 'bottom' ]
], ],
'script_assets' => [
[
'name' => '<%= blockFilename %>',
'url' => plugins_url( 'templates/scripts/<%= blockFilename %>.min.js', __FILE__ ),
]
] ]
] ); ] );
} }
@@ -66,3 +66,5 @@ class <%= blockClassModel %>_Component extends \Core\Component {
}<% } %> }<% } %>
} }
<%= blockClassModel %>_Component::get_instance();
@@ -8,8 +8,10 @@ namespace AXEWEB_Blocks\Blocks\<%= ownerClass %>\<%= blockClassModel %>\Helpers;
class <%= blockClassModel %>_Defaults { class <%= blockClassModel %>_Defaults {
public static function default_args(): array { public static function default_args(): array {
return [ $args = <%- defaultData %>;
'title' => '<%= title %>',
]; // $args['base_url'] = \Core\Global_Functions::get_file_url( __DIR__ . '/../templates/' );
return $args;
} }
} }
@@ -0,0 +1,60 @@
<?php
namespace AXEWEB_Blocks\Blocks\<%= ownerClass %>\<%= blockClassModel %>\Helpers;
class <%= blockClassModel %>_Elementor_Widget extends \Elementor\Widget_Base {
const PLUGIN_NAME = '<%= blockFilename %>';
public function get_name() {
return self::PLUGIN_NAME;
}
public function get_title() {
return '<%= blockClassModel %>';
}
public function get_icon() {
return 'eicon-plus-square-o';
}
protected function _register_controls() {
$this->start_controls_section( 'section_content', [ 'label' => 'Content' ] );
$repeater = new \Elementor\Repeater();
// $repeater->add_control(
// 'video_url', [
// 'label' => 'YouTube URL',
// 'type' => \Elementor\Controls_Manager::URL,
// 'label_block' => true,
// 'condition' => [
// 'type' => 'video',
// ],
// ]
// );
$this->end_controls_section();
}
function get_style_depends() {
return [ '<%= blockFilename %>' ];
}
function get_script_depends() {
return [ 'script-<%= blockFilename %>' ];
}
protected function render() {
$settings = $this->get_settings_for_display();
$component = new \AXEWEB_Blocks\Blocks\Scytale\<%= blockClassModel %>\<%= blockClassModel %>_Component();
$args = self::prepare( $settings );
$component->render( $args );
}
public static function prepare( $args ): array {
// Prepare $args for render function.
return $args;
}
}
+105 -24
View File
@@ -2,23 +2,25 @@ import path from "path";
import {mkdir, copyFile} from "fs/promises"; import {mkdir, copyFile} from "fs/promises";
import {capitalize, createFiles, getBlockName, getConfigs, readJSONFile} from "../../helpers.js"; import {capitalize, createFiles, getBlockName, getConfigs, readJSONFile} from "../../helpers.js";
import {fileURLToPath} from 'url'; import {fileURLToPath} from 'url';
import {copy} from "fs-extra";
import {exec} from 'child_process';
import execPhp from "exec-php";
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
const {projectPath} = getConfigs(); export async function buildWordPress(blockName, isBlock = false, isElementor = false) {
const {modulesPath, projectPath} = getConfigs();
export async function buildWordPress(isBlock = false) {
const distPath = path.join(projectPath, 'exports', 'wordpress'); const distPath = path.join(projectPath, 'exports', 'wordpress');
await mkdir(distPath, {recursive: true}) // await mkdir(distPath, {recursive: true})
await mkdir(path.join(distPath, 'templates'), {recursive: true})
const jsonFilePath = path.join(projectPath, 'block.json'); const blockFilePath = path.join(projectPath, 'block.json');
await copyFile(jsonFilePath, `${distPath}/block.json`)
let data = await readJSONFile(jsonFilePath); let data = await readJSONFile(blockFilePath);
Object.assign(data, getBlockName(data.name)); Object.assign(data, getBlockName(data.name));
// let data = await readJSONFile(path.join(projectPath, `block.json`));
const title = capitalize(data.name); const title = capitalize(data.name);
const owner = capitalize(data.project); const owner = capitalize(data.project);
@@ -31,12 +33,58 @@ export async function buildWordPress(isBlock = false) {
ownerClass: owner.replace(/ /ig, '_'), ownerClass: owner.replace(/ /ig, '_'),
ownerFilename: owner.toLowerCase().replace(/ /ig, '-'), ownerFilename: owner.toLowerCase().replace(/ /ig, '-'),
templateFormat: 'php', templateFormat: 'php',
include_acf_block: false, include_acf_block: isBlock,
include_native_gutenberg_block: false, include_native_gutenberg_block: false,
include_script: true, include_script: true,
include_elementor_widget: false, include_elementor_widget: isElementor,
isElementor,
}); });
await copyFile(blockFilePath, path.join(distPath, data.blockFilename + '.block.json'));
const backPath = modulesPath ? modulesPath.split('/').map(() => '..').join('/') : '';
const phpGeneratorPath = path.join(modulesPath, 'platforms', 'php');
await execCommand(`cd ${phpGeneratorPath} && composer install`);
await execPHPFile(path.join(phpGeneratorPath, 'build.php'), 'build', {blockName, backPath, projectPath});
await copyStaticFile(
path.join(projectPath, 'src', 'styles', `${data.blockFilename}.min.css`),
path.join(distPath, 'templates', 'styles', `${data.blockFilename}.min.css`),
);
await copyStaticFile(
path.join(projectPath, 'src', 'scripts', `${data.blockFilename}.min.js`),
path.join(distPath, 'templates', 'scripts', `${data.blockFilename}.min.js`),
);
await copy(
path.join(projectPath, 'src', 'images'),
path.join(distPath, 'templates', 'images'),
);
const phpDataObject = await execPHPFile(path.join(phpGeneratorPath, 'build.php'), 'jsonToPhp', {
json: await readJSONFile(path.join(projectPath, 'data', 'default.json'), "utf8"),
});
// await createFiles(Object.assign({}, data, {defaultData: phpDataObject}), [{
// from: `templates/helpers/Template_Defaults.php`,
// to: `helpers/${data.blockClassModel}_Defaults.php`,
// }], {
// pathDist: distPath,
// generatorsPath: path.join(__dirname),
// });
if (isElementor) {
await createFiles(data, [{
from: `templates/helpers/Template_Elementor_Widget.php`,
to: `helpers/${data.blockClassModel}_Elementor_Widget.php`,
}], {
pathDist: distPath,
generatorsPath: path.join(__dirname)
});
}
if (isBlock) { if (isBlock) {
await createFiles(data, [{ await createFiles(data, [{
from: `templates/Template_Component.php`, from: `templates/Template_Component.php`,
@@ -46,21 +94,13 @@ export async function buildWordPress(isBlock = false) {
generatorsPath: path.join(__dirname) generatorsPath: path.join(__dirname)
}); });
await createFiles(data, [{ // await createFiles(data, [{
from: `templates/helpers/Template_API.php`, // from: `templates/helpers/Template_API.php`,
to: `helpers/${data.blockClassModel}_API.php`, // to: `helpers/${data.blockClassModel}_API.php`,
}], { // }], {
pathDist: distPath, // pathDist: distPath,
generatorsPath: path.join(__dirname) // generatorsPath: path.join(__dirname)
}); // });
await createFiles(data, [{
from: `templates/helpers/Template_Defaults.php`,
to: `helpers/${data.blockClassModel}_Defaults.php`,
}], {
pathDist: distPath,
generatorsPath: path.join(__dirname)
});
} else { } else {
await createFiles(data, [{ await createFiles(data, [{
from: `templates/Template_Basic_Component.php`, from: `templates/Template_Basic_Component.php`,
@@ -71,3 +111,44 @@ export async function buildWordPress(isBlock = false) {
}); });
} }
} }
export function execCommand(cmd = '') {
return new Promise((resolve, reject) => {
exec(cmd, function (error) {
if (error) {
console.log('Error:', error)
reject(error);
}
// console.log(stdout);
resolve();
});
});
}
function execPHPFile(file = '', functionName = '', args = {}) {
return new Promise((resolve, reject) => {
execPhp(file, 'php', (err, php, out) => {
if (err) {
console.error(out);
return reject(err);
}
php[functionName.toLowerCase()](args, (err, res, out) => {
if (err) {
console.error(out);
return reject(err);
}
return resolve(res);
})
})
});
}
async function copyStaticFile(from = '', to = '') {
await mkdir(path.dirname(to), {recursive: true})
await copyFile(from, to);
}
+20 -5
View File
@@ -3,13 +3,17 @@ import {nodeResolve} from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs'; import commonjs from '@rollup/plugin-commonjs';
import replace from '@rollup/plugin-replace'; import replace from '@rollup/plugin-replace';
import css from "@modular-css/rollup"; import css from "@modular-css/rollup";
import copy from 'rollup-plugin-copy' import copy from 'rollup-plugin-copy';
import {terser} from "rollup-plugin-terser";
export default { const devMode = (process.env.NODE_ENV === 'development');
console.log('Build Mode', devMode ? 'Development' : 'Production');
export default [{
input: 'layouts/scripts/index.js', input: 'layouts/scripts/index.js',
output: { output: {
file: 'layouts/scripts/dist/index.min.js', file: 'layouts/scripts/dist/index.min.js',
sourcemap: true sourcemap: devMode,
}, },
plugins: [ plugins: [
nodeResolve({ nodeResolve({
@@ -26,10 +30,21 @@ export default {
presets: ["@babel/preset-react"], presets: ["@babel/preset-react"],
}), }),
commonjs(), commonjs(),
!devMode && terser(),
copy({ copy({
targets: [ targets: [
{ src: 'layouts/scripts/toolbar/images/**/*', dest: 'layouts/scripts/dist/toolbar/images' } {src: 'layouts/scripts/toolbar/images/**/*', dest: 'layouts/scripts/dist/toolbar/images'}
] ]
}) })
], ],
} }, {
input: 'layouts/scripts/frame/frame.js',
output: {
file: 'layouts/scripts/dist/frame-index.min.js',
sourcemap: devMode
},
plugins: [
commonjs(),
!devMode && terser()
]
}];
+25 -61
View File
@@ -4,7 +4,6 @@ import path from 'path';
import fetch from "node-fetch"; import fetch from "node-fetch";
import express from 'express'; import express from 'express';
import {create} from 'express-handlebars'; import {create} from 'express-handlebars';
import fsExtra from 'fs-extra';
import browserSync from 'browser-sync'; import browserSync from 'browser-sync';
import config from 'config'; import config from 'config';
import gulp from 'gulp'; import gulp from 'gulp';
@@ -19,16 +18,18 @@ import open from "open";
import {sanitizeUrl} from "@braintree/sanitize-url"; import {sanitizeUrl} from "@braintree/sanitize-url";
import sanitizeHtml from 'sanitize-html'; import sanitizeHtml from 'sanitize-html';
import {escape} from "lodash-es"; import {escape} from "lodash-es";
import archiver from 'archiver'; import {getBlockConfigs, getConfigs, readJSONFile, zipProject} from "./helpers.js";
import {getBlockConfigs, getConfigs, readJSONFile} from "./helpers.js";
import PluginError from 'plugin-error'; import PluginError from 'plugin-error';
/** /**
* Constants * Constants
*/ */
const PRODUCTION_REGISTRY_URL = 'https://blocks-registery.axe-web.com';
const {isDev, modulesPath, projectPath, developmentBlockName} = getConfigs(); const {isDev, modulesPath, projectPath, developmentBlockName} = getConfigs();
const blocksRegistry = isDev ? 'http://localhost:3020' : 'https://axe-web-blocks-registry.captain.devdevdev.life'; const blocksRegistry = isDev ? 'http://localhost:3020' : PRODUCTION_REGISTRY_URL;
/** /**
* Init server * Init server
@@ -75,7 +76,7 @@ app.get('/', async (req, res) => {
data.helpers = { data.helpers = {
port, port,
include_partial: (filesPath) => path.join(modulesPath, filesPath), include_partial: (filesPath) => handlebarLayoutsPath(modulesPath, filesPath),
baseView, baseView,
previewFrameUrl: `${previewFrameUrl}/${baseViewUrl}`, previewFrameUrl: `${previewFrameUrl}/${baseViewUrl}`,
} }
@@ -93,10 +94,14 @@ app.get('/view/:baseView', async (req, res) => {
const blockName = config.has('blockName') ? config.get('blockName') : developmentBlockName; const blockName = config.has('blockName') ? config.get('blockName') : developmentBlockName;
data.helpers = { data.helpers = {
include_partial: (filesPath) => path.join(modulesPath, filesPath), include_partial: (filesPath) => handlebarLayoutsPath(modulesPath, filesPath),
include_block_template: () => path.join(projectPath, 'src', `${blockName}.template`), include_block_template: () => handlebarLayoutsPath(projectPath, 'src', `${blockName}.template`),
section_class: `${blockName}--${jsonFileName}`, section_class: `${blockName}--${jsonFileName}`,
base_url: '/' base_url: '/',
}
if (!!req.query.iframe) {
data.iframeMode = true;
} }
const baseView = req.params.baseView ?? 'container'; const baseView = req.params.baseView ?? 'container';
@@ -127,7 +132,7 @@ app.get('/publish', async (req, res) => {
} }
if (responseData.uploadUrl) { if (responseData.uploadUrl) {
await zipProject(); await zipProject(path.join(projectPath, 'src'));
const body = await fs.readFile(path.join(projectPath, 'dist.zip')); const body = await fs.readFile(path.join(projectPath, 'dist.zip'));
const response = await fetch(`${responseData.uploadUrl}`, { const response = await fetch(`${responseData.uploadUrl}`, {
method: 'PUT', method: 'PUT',
@@ -218,7 +223,7 @@ function startBrowserSync() {
return cb(); return cb();
}])); }]));
gulp.watch(path.join(projectPath, 'src/**/*.scss'), {delay: 400}, gulp.series(['build-styling-files', function (cb) { gulp.watch(path.posix.join(projectPath, "src/**/*.scss"), {delay: 400}, gulp.series(['build-styling-files', function (cb) {
browserSyncReload(bs, 'css', 'Style Files Change'); browserSyncReload(bs, 'css', 'Style Files Change');
return cb(); return cb();
}])); }]));
@@ -272,12 +277,12 @@ function browserSyncReload(bs, extension = '', message = '') {
} }
function getJSBundleFiles() { function getJSBundleFiles() {
return [path.join(projectPath, 'src/**/*.js'), path.join(projectPath, 'src/**/*.mjs'), '!' + path.join(projectPath, 'src/**/*.min.js')]; return [path.posix.join(projectPath, "src/**/*.js"), path.posix.join(projectPath, "src/**/*.mjs"), "!" + path.posix.join(projectPath, "src/**/*.min.js")];
} }
function buildScriptFiles(done) { function buildScriptFiles(done) {
const files = getJSBundleFiles(); const files = getJSBundleFiles();
return gulp.src(files) return gulp.src(files, {base: path.posix.join(projectPath, 'src')})
.pipe(sourcemaps.init({})) .pipe(sourcemaps.init({}))
.pipe(babel()).on('error', function (error) { .pipe(babel()).on('error', function (error) {
showError(new PluginError('JavaScript', error).toString()); showError(new PluginError('JavaScript', error).toString());
@@ -288,11 +293,11 @@ function buildScriptFiles(done) {
.pipe(uglify()) .pipe(uglify())
.pipe(rename({extname: '.min.js'})) .pipe(rename({extname: '.min.js'}))
.pipe(sourcemaps.write('.')) .pipe(sourcemaps.write('.'))
.pipe(gulp.dest(path.join(projectPath, 'src/'))); .pipe(gulp.dest(path.posix.join(projectPath, 'src')));
} }
function buildStyleFiles(done) { function buildStyleFiles(done) {
return gulp.src(path.join(projectPath, 'src/**/*.scss')) return gulp.src(path.join(projectPath, 'src/**/*.scss'), {base: path.posix.join(projectPath, 'src')})
.pipe(sourcemaps.init({})) .pipe(sourcemaps.init({}))
.pipe(sass.sync({outputStyle: 'compressed'}).on('error', function (error) { .pipe(sass.sync({outputStyle: 'compressed'}).on('error', function (error) {
showError(new PluginError('SCSS', error.messageFormatted).toString()); showError(new PluginError('SCSS', error.messageFormatted).toString());
@@ -302,7 +307,7 @@ function buildStyleFiles(done) {
// .pipe(gulp.dest('src/')) // .pipe(gulp.dest('src/'))
.pipe(rename({extname: '.min.css'})) .pipe(rename({extname: '.min.css'}))
.pipe(sourcemaps.write('.', {})) .pipe(sourcemaps.write('.', {}))
.pipe(gulp.dest(path.join(projectPath, 'src'))) .pipe(gulp.dest(path.posix.join(projectPath, 'src')))
} }
function buildAssetFiles() { function buildAssetFiles() {
@@ -336,52 +341,6 @@ function prepareListOfDataFiles(dataFiles) {
.sort(); .sort();
} }
async function zipProject() {
// create a file to stream archive data to.
const output = await fsExtra.createWriteStream('dist.zip');
const archive = archiver('zip', {});
// listen for all archive data to be written
// 'close' event is fired only when a file descriptor is involved
output.on('close', function () {
console.log(archive.pointer() + ' total bytes');
console.log('archiver has been finalized and the output file descriptor has closed.');
});
// This event is fired when the data source is drained no matter what was the data source.
// It is not part of this library but rather from the NodeJS Stream API.
// @see: https://nodejs.org/api/stream.html#stream_event_end
output.on('end', function () {
console.log('Data has been drained');
});
// good practice to catch warnings (ie stat failures and other non-blocking errors)
archive.on('warning', function (err) {
if (err.code === 'ENOENT') {
// log warning
} else {
// throw error
throw err;
}
});
// good practice to catch this error explicitly
archive.on('error', function (err) {
throw err;
});
// pipe archive data to the file
archive.pipe(output);
// append files from a subdirectory, putting its contents at the root of archive
archive.directory(path.join(projectPath, 'src', '/'), false);
// finalize the archive (ie we are done appending files but streams have to finish yet)
// 'close', 'end' or 'finish' may be fired right after calling this method so register to them beforehand
await archive.finalize();
}
function handleSyntaxErrors(err, req, res, next) { function handleSyntaxErrors(err, req, res, next) {
if (err) { if (err) {
return res.render('error', { return res.render('error', {
@@ -394,3 +353,8 @@ function handleSyntaxErrors(err, req, res, next) {
next(); next();
} }
function handlebarLayoutsPath() {
return path.join(...arguments)
.replace(/\\/g, '/'); // Windows path issue. Fix all "\" for Handlebars.
}