html-to-gutenberg 4.2.5 → 4.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +14 -0
- package/index.ts +837 -408
- package/package.json +2 -2
package/index.ts
CHANGED
|
@@ -1,67 +1,23 @@
|
|
|
1
|
-
import
|
|
1
|
+
import presetReact from '@babel/preset-react';
|
|
2
|
+
import * as babel from '@babel/core';
|
|
2
3
|
import * as cheerio from 'cheerio';
|
|
3
|
-
import
|
|
4
|
+
import scopeCss from 'css-scoping';
|
|
5
|
+
import extractAssets from 'fetch-page-assets';
|
|
4
6
|
import fs from 'fs';
|
|
5
|
-
import path from 'path';
|
|
6
|
-
import * as babel from '@babel/core';
|
|
7
|
-
import presetReact from '@babel/preset-react';
|
|
8
|
-
import { transform } from '@svgr/core';
|
|
9
|
-
import extractAssets from 'fetch-page-assets/index.js';
|
|
10
7
|
import icon from 'html-screenshots';
|
|
11
|
-
import
|
|
8
|
+
import { createRequire } from 'module';
|
|
9
|
+
import convert from 'node-html-to-jsx';
|
|
10
|
+
import path from 'path';
|
|
12
11
|
|
|
13
12
|
import {
|
|
14
13
|
imports,
|
|
15
|
-
panels,
|
|
16
14
|
images,
|
|
17
15
|
characters
|
|
18
16
|
} from './globals.js';
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
attribute?: string,
|
|
23
|
-
selector?: string,
|
|
24
|
-
default?: string,
|
|
25
|
-
type?: string
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface Panel {
|
|
30
|
-
type?: string,
|
|
31
|
-
title?: string,
|
|
32
|
-
attributes?: any,
|
|
33
|
-
};
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
const { version } = require('./package.json');
|
|
34
20
|
|
|
35
|
-
interface Image {
|
|
36
|
-
randomUrlVariable: string,
|
|
37
|
-
randomAltVariable: string,
|
|
38
|
-
imgClass: string,
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
interface ImageProperties {
|
|
42
|
-
imgTag: any,
|
|
43
|
-
imgSrc: string,
|
|
44
|
-
imgAlt: string,
|
|
45
|
-
imgClass: string,
|
|
46
|
-
isBackground: boolean,
|
|
47
|
-
type?: string,
|
|
48
|
-
attribute?: string,
|
|
49
|
-
prefix?: string,
|
|
50
|
-
}
|
|
51
|
-
interface BlockOptions {
|
|
52
|
-
name: string,
|
|
53
|
-
prefix: string,
|
|
54
|
-
category: string,
|
|
55
|
-
basePath: string,
|
|
56
|
-
htmlContent?: string,
|
|
57
|
-
cssFiles?: string[],
|
|
58
|
-
jsFiles?: string[],
|
|
59
|
-
generateIconPreview?: boolean,
|
|
60
|
-
shouldSaveFiles?: boolean,
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
let js = '';
|
|
64
|
-
let css = '';
|
|
65
21
|
const block = async (
|
|
66
22
|
htmlContent,
|
|
67
23
|
options = {
|
|
@@ -70,27 +26,40 @@ const block = async (
|
|
|
70
26
|
category: 'common',
|
|
71
27
|
basePath: process.cwd(),
|
|
72
28
|
shouldSaveFiles: true,
|
|
29
|
+
generateIconPreview: false,
|
|
30
|
+
jsFiles: [],
|
|
31
|
+
cssFiles: [],
|
|
32
|
+
source: null,
|
|
73
33
|
}
|
|
74
34
|
) => {
|
|
35
|
+
const panels = [];
|
|
75
36
|
const styles = [];
|
|
76
37
|
const scripts = [];
|
|
77
38
|
const attributes = {};
|
|
39
|
+
const formVars = {};
|
|
40
|
+
|
|
41
|
+
const { name, prefix, source } = options;
|
|
78
42
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
43
|
+
let js = '';
|
|
44
|
+
let css = '';
|
|
45
|
+
let phpEmailData = '';
|
|
46
|
+
let emailTemplate = '';
|
|
83
47
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}).filter(Boolean);
|
|
48
|
+
function hasTailwindCdnSource(jsFiles) {
|
|
49
|
+
const tailwindCdnRegex = /https:\/\/(cdn\.tailwindcss\.com(\?[^"'\s]*)?|cdn\.jsdelivr\.net\/npm\/@tailwindcss\/browser@4(\.\d+){0,2})/;
|
|
87
50
|
|
|
88
|
-
|
|
51
|
+
return jsFiles.some(url => tailwindCdnRegex.test(url));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function replaceSourceUrlVars(str, source) {
|
|
55
|
+
if (!source) return str;
|
|
89
56
|
|
|
90
|
-
|
|
57
|
+
const escapedSource = source.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
58
|
+
const pattern = new RegExp(`var\.url\+'${escapedSource}([^']+)'`, 'g');
|
|
59
|
+
return str.replace(pattern, (match, path) => `\${vars.url}${path}`);
|
|
91
60
|
}
|
|
92
61
|
|
|
93
|
-
function
|
|
62
|
+
function sanitizeAndReplaceLeadingNumbers(str) {
|
|
94
63
|
const numberWords = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];
|
|
95
64
|
let firstNumberReplaced = false;
|
|
96
65
|
|
|
@@ -100,85 +69,132 @@ const block = async (
|
|
|
100
69
|
.replace(/\d/g, (digit) => {
|
|
101
70
|
if (!firstNumberReplaced) {
|
|
102
71
|
firstNumberReplaced = true;
|
|
72
|
+
|
|
103
73
|
return numberWords[parseInt(digit)] + digit;
|
|
104
74
|
}
|
|
105
|
-
return digit;
|
|
75
|
+
return digit;
|
|
106
76
|
})
|
|
107
77
|
.replace(/^[^a-z]+/, '');
|
|
108
78
|
}
|
|
109
79
|
|
|
110
|
-
const
|
|
111
|
-
return
|
|
80
|
+
const replaceUnderscoresSpacesAndUppercaseLetters = (name = '') => {
|
|
81
|
+
return name.replace(new RegExp(/\W|_/, 'g'), '-').toLowerCase();
|
|
112
82
|
};
|
|
83
|
+
|
|
113
84
|
const saveFile = (fileName, contents, options) => {
|
|
114
85
|
try {
|
|
115
86
|
const filePath = path.join(options.basePath, fileName);
|
|
87
|
+
|
|
116
88
|
fs.writeFileSync(filePath, contents);
|
|
89
|
+
|
|
117
90
|
return contents;
|
|
118
91
|
} catch (error) {
|
|
119
92
|
logError(error);
|
|
120
93
|
}
|
|
121
94
|
};
|
|
122
|
-
|
|
95
|
+
|
|
96
|
+
function replaceRelativeUrls(html, replacer) {
|
|
97
|
+
const urlAttributes = [
|
|
98
|
+
'src', 'href', 'action', 'srcset', 'poster', 'data', 'formaction'
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
const regex = new RegExp(
|
|
102
|
+
`\\b(${urlAttributes.join('|')}|data-[a-zA-Z0-9_-]+)\\s*=\\s*(['"])(?!https?:|//|mailto:|tel:|#)([^'"]+)\\2`,
|
|
103
|
+
'gi'
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
return html.replace(regex, (_match, attr, quote, url) => {
|
|
107
|
+
const newUrl = replacer(url);
|
|
108
|
+
return `${attr}=${quote}${newUrl}${quote}`;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
function replaceRelativeUrlsInCss(css, replacer) {
|
|
114
|
+
const regex = /url\(\s*(['"]?)(.+?)\1\s*\)/gi;
|
|
115
|
+
|
|
116
|
+
return css.replace(regex, (match, quote, url) => {
|
|
117
|
+
if (/^(https?:|\/\/|data:|mailto:|tel:|#)/.test(url.trim())) {
|
|
118
|
+
return match;
|
|
119
|
+
}
|
|
120
|
+
const newUrl = replacer(url);
|
|
121
|
+
return `url(${quote}${newUrl}${quote})`;
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function replaceRelativeUrlsInHtml(html, baseUrl) {
|
|
126
|
+
return replaceRelativeUrls(html, (url) => {
|
|
127
|
+
return new URL(url, baseUrl).href;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function replaceRelativeUrlsInCssWithBase(css, cssFileUrl) {
|
|
132
|
+
return replaceRelativeUrlsInCss(css, (url) => {
|
|
133
|
+
if (/^(https?:|\/\/|data:|mailto:|tel:|#)/.test(url.trim())) {
|
|
134
|
+
return url;
|
|
135
|
+
}
|
|
136
|
+
return new URL(url, cssFileUrl).href;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const parseRequirements = async (files, options) => {
|
|
141
|
+
const { source } = options;
|
|
123
142
|
let output = '';
|
|
143
|
+
|
|
124
144
|
for (const file of files) {
|
|
125
145
|
try {
|
|
126
|
-
const
|
|
127
|
-
|
|
146
|
+
const response = await fetch(file);
|
|
147
|
+
|
|
148
|
+
if (!response.ok) {
|
|
149
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let data = await response.text();
|
|
153
|
+
|
|
154
|
+
if (source) {
|
|
155
|
+
data = replaceRelativeUrlsInCssWithBase(data, file);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
output += `${data}\n\n`;
|
|
128
159
|
} catch (error) {
|
|
129
160
|
logError(error);
|
|
130
161
|
}
|
|
131
162
|
}
|
|
163
|
+
|
|
132
164
|
return output;
|
|
133
165
|
};
|
|
134
|
-
|
|
166
|
+
|
|
167
|
+
const convertDashesSpacesAndUppercaseToUnderscoresAndLowercase = (string) => {
|
|
135
168
|
if (string) {
|
|
136
|
-
return `${string.replaceAll('-', '_').replaceAll(' ', '_').toLowerCase()}
|
|
137
|
-
'func',
|
|
138
|
-
3
|
|
139
|
-
)}`;
|
|
169
|
+
return `${string.replaceAll('-', '_').replaceAll(' ', '_').toLowerCase()}`;
|
|
140
170
|
}
|
|
141
171
|
|
|
142
172
|
return '';
|
|
143
173
|
};
|
|
144
174
|
|
|
175
|
+
const newName = replaceUnderscoresSpacesAndUppercaseLetters(name);
|
|
176
|
+
const blockName = `${sanitizeAndReplaceLeadingNumbers(replaceUnderscoresSpacesAndUppercaseLetters(prefix))}/${sanitizeAndReplaceLeadingNumbers(replaceUnderscoresSpacesAndUppercaseLetters(name))}`;
|
|
177
|
+
const blockNameHandle = `${prefix}-${newName}`;
|
|
178
|
+
|
|
145
179
|
const getPhp = (options) => {
|
|
146
180
|
const { name, prefix, jsFiles, cssFiles } = options;
|
|
147
|
-
const
|
|
148
|
-
const
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
const inlineRemoteLoader = `
|
|
152
|
-
var remoteUrls = ${JSON.stringify(jsFiles)};
|
|
153
|
-
|
|
154
|
-
(function loadScripts() {
|
|
155
|
-
window._loadedRemoteScripts = window._loadedRemoteScripts || new Set();
|
|
156
|
-
|
|
157
|
-
remoteUrls.forEach((url) => {
|
|
158
|
-
if (window._loadedRemoteScripts.has(url)) return;
|
|
159
|
-
|
|
160
|
-
const script = document.createElement('script');
|
|
161
|
-
script.src = url;
|
|
162
|
-
script.async = true;
|
|
163
|
-
document.head.appendChild(script);
|
|
164
|
-
|
|
165
|
-
window._loadedRemoteScripts.add(url);
|
|
166
|
-
});
|
|
167
|
-
})();
|
|
168
|
-
`;
|
|
169
|
-
|
|
181
|
+
const phpName = convertDashesSpacesAndUppercaseToUnderscoresAndLowercase(name);
|
|
182
|
+
const phpPrefix = `${functionSufix}${convertDashesSpacesAndUppercaseToUnderscoresAndLowercase(prefix)}`;
|
|
183
|
+
const tailwindFix = hasTailwindCdnSource(jsFiles) ? 'function forceTailwindUpdate(){let e=setInterval(()=>{if("undefined"!=typeof tailwind){clearInterval(e);let n=document.documentElement.outerHTML;tailwind.config.content=[{raw:n,extension:"html"}]}},100)}forceTailwindUpdate();' : '';
|
|
184
|
+
const tailwindFooter = hasTailwindCdnSource(jsFiles) ? '(()=>{if(window.__tailwindObserverActive)return;window.__tailwindObserverActive=!0;let e=new MutationObserver(()=>{let t=[...document.querySelectorAll("style")].find(e=>e.innerText.includes("--tw-"));t&&(document.body.appendChild(t),e.disconnect(),window.__tailwindObserverActive=!1)});e.observe(document.documentElement,{childList:!0,subtree:!0})})();' : '';
|
|
185
|
+
const inlineRemoteLoader = `var remoteUrls = ${JSON.stringify(jsFiles)};(function loadScripts() {window._loadedRemoteScripts = window._loadedRemoteScripts || new Set();const style = document.createElement('style');remoteUrls.forEach((url) => {if (window._loadedRemoteScripts.has(url)) return;const script = document.createElement('script');script.src = url;document.head.appendChild(script);window._loadedRemoteScripts.add(url);});})();${tailwindFix}${tailwindFooter}`;
|
|
170
186
|
|
|
171
187
|
const enqueueRemoteStyles = cssFiles
|
|
172
188
|
.map((remoteUrl) => {
|
|
173
189
|
return `
|
|
174
190
|
wp_enqueue_style(
|
|
175
|
-
'${
|
|
191
|
+
'${blockNameHandle}-${remoteUrl
|
|
176
192
|
.split('/')
|
|
177
193
|
.pop()
|
|
178
194
|
.replace(/\.\w+$/, '')}',
|
|
179
195
|
'${remoteUrl}',
|
|
180
196
|
array(),
|
|
181
|
-
null
|
|
197
|
+
null
|
|
182
198
|
);
|
|
183
199
|
`;
|
|
184
200
|
})
|
|
@@ -187,7 +203,7 @@ const block = async (
|
|
|
187
203
|
return `<?php
|
|
188
204
|
/*
|
|
189
205
|
* Plugin Name: ${name}
|
|
190
|
-
* Version:
|
|
206
|
+
* Version: ${version}
|
|
191
207
|
* Author: Html to Gutenberg
|
|
192
208
|
* Author URI: https://www.html-to-gutenberg.io/
|
|
193
209
|
* Description: A custom editable block built with Html to Gutenberg
|
|
@@ -198,59 +214,44 @@ const block = async (
|
|
|
198
214
|
exit;
|
|
199
215
|
}
|
|
200
216
|
|
|
201
|
-
function ${
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
max-width: 100%;
|
|
209
|
-
margin: 0;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
[aria-label="Empty block; start writing or type forward slash to choose a block"] {
|
|
213
|
-
max-width: 1200px !important;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
span.block-editor-block-types-list__item-icon img {
|
|
217
|
-
max-width: 100%;
|
|
218
|
-
width: 100%;
|
|
219
|
-
margin: 0;
|
|
220
|
-
display: block;
|
|
221
|
-
}
|
|
217
|
+
function parse_form_placeholders_${functionSufix}($content, $post_data)
|
|
218
|
+
{
|
|
219
|
+
return preg_replace_callback('/{{(.*?)}}/', function ($matches) use ($post_data) {
|
|
220
|
+
$key = trim($matches[1]);
|
|
221
|
+
return isset($post_data[$key]) ? sanitize_text_field($post_data[$key]) : '';
|
|
222
|
+
}, $content);
|
|
223
|
+
}
|
|
222
224
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
all: inherit;
|
|
226
|
-
}
|
|
225
|
+
add_action('wp_ajax_send_test_email_${functionSufix}}', function() {
|
|
226
|
+
//check_ajax_referer('wp_rest');
|
|
227
227
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
228
|
+
$post_data = $_POST;
|
|
229
|
+
$to = sanitize_email(parse_form_placeholders_${functionSufix}($post_data['to'], $post_data));
|
|
230
|
+
$from = sanitize_email(parse_form_placeholders_${functionSufix}($post_data['from'], $post_data));
|
|
231
|
+
$subject = sanitize_text_field(parse_form_placeholders_${functionSufix}($post_data['subject'], $post_data));
|
|
232
|
+
$message = wp_kses_post(parse_form_placeholders_${functionSufix}($post_data['message'], $post_data));
|
|
232
233
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
width: 100%;
|
|
237
|
-
}
|
|
234
|
+
if (empty($to) || empty($from)) {
|
|
235
|
+
wp_send_json_error('Missing email addresses.');
|
|
236
|
+
}
|
|
238
237
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
238
|
+
$sent = wp_mail($to, $subject, $message, [
|
|
239
|
+
'Content-Type: text/html; charset=UTF-8',
|
|
240
|
+
'From: ' . $from
|
|
241
|
+
]);
|
|
243
242
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
243
|
+
if ($sent) {
|
|
244
|
+
wp_send_json_success('Email sent');
|
|
245
|
+
} else {
|
|
246
|
+
error_log('Failed to send. To: ' . $to . ' | From: ' . $from);
|
|
247
|
+
wp_send_json_error('Failed to send email.');
|
|
248
|
+
}
|
|
249
|
+
});
|
|
247
250
|
|
|
248
|
-
|
|
249
|
-
display: none;
|
|
250
|
-
}
|
|
251
|
-
|
|
251
|
+
${phpEmailData}
|
|
252
252
|
|
|
253
|
-
|
|
253
|
+
function ${phpPrefix}_${phpName}_add_custom_editor_styles() {
|
|
254
|
+
echo '<style>span.block-editor-rich-text__editable.rich-text{all:unset!important}a br[data-rich-text-line-break=true],span.block-editor-block-icon.block-editor-block-switcher__toggle.has-colors img{display:none}.block-editor-block-types-list__list-item{width:100%!important}.block-editor-block-list__layout.is-root-container>:where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width:100%;margin:0}[aria-label="Empty block; start writing or type forward slash to choose a block"]{max-width:1200px!important}span.block-editor-block-types-list__item-icon img{max-width:100%;width:100%;margin:0;display:block}span.block-editor-block-icon.has-colors{all:inherit;order:2;flex:0 0 100%;width:100%}span.block-editor-block-icon.has-colors svg{margin-left:auto;margin-right:auto}.block-editor-block-card{display:flex!important;flex-wrap:wrap}.block-editor-inserter__preview-content-missing{display:none!important}</style>';
|
|
254
255
|
}
|
|
255
256
|
|
|
256
257
|
add_action('admin_footer', function () {
|
|
@@ -258,7 +259,7 @@ const block = async (
|
|
|
258
259
|
|
|
259
260
|
if ($screen && method_exists($screen, 'is_block_editor') && $screen->is_block_editor()) {
|
|
260
261
|
$href = esc_url(plugins_url('editor.css', __FILE__));
|
|
261
|
-
echo "<link rel='stylesheet' id='${
|
|
262
|
+
echo "<link rel='stylesheet' id='${blockNameHandle}-style' href='$href' type='text/css' media='all' />";
|
|
262
263
|
}
|
|
263
264
|
});
|
|
264
265
|
|
|
@@ -272,39 +273,38 @@ const block = async (
|
|
|
272
273
|
remove_action('wp_footer', 'wp_global_styles_render_svg_filters');
|
|
273
274
|
}, 100);
|
|
274
275
|
|
|
275
|
-
|
|
276
276
|
function ${phpPrefix}_${phpName}_editor_assets() {
|
|
277
277
|
$filepath = plugin_dir_path(__FILE__) . 'block.js';
|
|
278
278
|
$version = file_exists($filepath) ? filemtime($filepath) : time();
|
|
279
279
|
|
|
280
280
|
wp_enqueue_script(
|
|
281
|
-
'${
|
|
281
|
+
'${blockNameHandle}',
|
|
282
282
|
plugins_url( 'block.js', __FILE__ ),
|
|
283
283
|
array( 'wp-blocks', 'wp-components', 'wp-element' ,'wp-editor'),
|
|
284
284
|
$version
|
|
285
285
|
);
|
|
286
286
|
|
|
287
|
-
wp_localize_script( '${
|
|
287
|
+
wp_localize_script( '${blockNameHandle}', 'vars', array( 'url' => plugin_dir_url( __FILE__ ) ) );
|
|
288
|
+
|
|
289
|
+
${enqueueRemoteStyles}
|
|
290
|
+
|
|
291
|
+
${phpPrefix}_${phpName}_add_custom_editor_styles();
|
|
292
|
+
|
|
293
|
+
wp_dequeue_style('${blockNameHandle}-frontend');
|
|
294
|
+
wp_deregister_style('${blockNameHandle}-frontend');
|
|
288
295
|
|
|
289
296
|
wp_enqueue_script(
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
297
|
+
'${blockNameHandle}-remote-loader',
|
|
298
|
+
plugins_url('remote-loader.js', __FILE__),
|
|
299
|
+
array(),
|
|
300
|
+
null,
|
|
301
|
+
true
|
|
295
302
|
);
|
|
296
303
|
|
|
297
304
|
wp_add_inline_script(
|
|
298
|
-
'${
|
|
305
|
+
'${blockNameHandle}-remote-loader',
|
|
299
306
|
${JSON.stringify(inlineRemoteLoader)}
|
|
300
307
|
);
|
|
301
|
-
|
|
302
|
-
${enqueueRemoteStyles}
|
|
303
|
-
|
|
304
|
-
${phpPrefix}_${phpName}_add_custom_editor_styles();
|
|
305
|
-
|
|
306
|
-
wp_dequeue_style('${prefix}-${newName}-frontend');
|
|
307
|
-
wp_deregister_style('${prefix}-${newName}-frontend');
|
|
308
308
|
}
|
|
309
309
|
|
|
310
310
|
add_action('enqueue_block_editor_assets', function () {
|
|
@@ -314,177 +314,175 @@ const block = async (
|
|
|
314
314
|
wp_dequeue_style('wp-format-library');
|
|
315
315
|
}, 100);
|
|
316
316
|
|
|
317
|
-
add_action( 'enqueue_block_assets', '${phpPrefix}_${phpName}_block_assets' );
|
|
318
317
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
'${
|
|
322
|
-
plugins_url('
|
|
318
|
+
add_action('init', function () {
|
|
319
|
+
wp_register_script(
|
|
320
|
+
'${blockNameHandle}-scripts',
|
|
321
|
+
plugins_url('scripts.js', __FILE__),
|
|
322
|
+
array(),
|
|
323
|
+
null,
|
|
324
|
+
true
|
|
323
325
|
);
|
|
324
|
-
}
|
|
325
326
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
}
|
|
327
|
+
wp_register_style(
|
|
328
|
+
'${blockNameHandle}-frontend',
|
|
329
|
+
plugins_url('style.css', __FILE__)
|
|
330
|
+
);
|
|
331
331
|
|
|
332
|
-
|
|
333
|
-
|
|
332
|
+
wp_register_script(
|
|
333
|
+
'${blockNameHandle}-remote-loader',
|
|
334
334
|
plugins_url('remote-loader.js', __FILE__),
|
|
335
335
|
array(),
|
|
336
336
|
null,
|
|
337
337
|
true
|
|
338
338
|
);
|
|
339
|
+
});
|
|
339
340
|
|
|
340
|
-
|
|
341
|
-
wp_add_inline_script(
|
|
342
|
-
'${prefix}-${newName}-remote-loader',
|
|
343
|
-
${JSON.stringify(inlineRemoteLoader)}
|
|
344
|
-
);
|
|
345
|
-
}
|
|
346
|
-
`;
|
|
347
|
-
};
|
|
348
|
-
|
|
349
|
-
function scopeCss(css, blockClass) {
|
|
350
|
-
const GLOBAL_SELECTORS = ['html', 'body', ':root', ':host', '::backdrop'];
|
|
351
|
-
const lines = css.split('\n');
|
|
341
|
+
add_action( 'wp_enqueue_scripts', '${phpPrefix}_${phpName}_block_assets', 999 );
|
|
352
342
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
let selectorBuffer = [];
|
|
356
|
-
let insidePropertyBlock = false;
|
|
357
|
-
let insideRule = false;
|
|
358
|
-
let currentIsScoped = false;
|
|
359
|
-
|
|
360
|
-
function scopeSelector(sel) {
|
|
361
|
-
sel = sel.trim();
|
|
362
|
-
|
|
363
|
-
const whereMatch = sel.match(/^([^ :]+)(:where\(.*\))$/);
|
|
364
|
-
if (whereMatch) {
|
|
365
|
-
const base = whereMatch[1];
|
|
366
|
-
const pseudo = whereMatch[2];
|
|
367
|
-
const scopedBase = scopeSelector(base);
|
|
368
|
-
return `${scopedBase}${pseudo}`;
|
|
369
|
-
}
|
|
343
|
+
function ${phpPrefix}_${phpName}_block_assets() {
|
|
344
|
+
global $wp_query;
|
|
370
345
|
|
|
371
|
-
|
|
372
|
-
const inner = sel.slice(7, -1);
|
|
373
|
-
const scopedInner = inner
|
|
374
|
-
.split(',')
|
|
375
|
-
.map(scopeSelector)
|
|
376
|
-
.join(', ');
|
|
377
|
-
return `:where(${scopedInner})`;
|
|
378
|
-
}
|
|
346
|
+
$used = false;
|
|
379
347
|
|
|
380
|
-
|
|
381
|
-
|
|
348
|
+
if (!empty($wp_query->posts)) {
|
|
349
|
+
foreach ($wp_query->posts as $post) {
|
|
350
|
+
$blocks = parse_blocks($post->post_content);
|
|
382
351
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
352
|
+
foreach ($blocks as $block) {
|
|
353
|
+
if ($block['blockName'] === '${blockName}') {
|
|
354
|
+
$used = true;
|
|
355
|
+
break 2;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
387
359
|
}
|
|
388
360
|
|
|
389
|
-
|
|
390
|
-
|
|
361
|
+
if ($used) {
|
|
362
|
+
$handle = '${blockNameHandle}';
|
|
391
363
|
|
|
392
|
-
|
|
393
|
-
insidePropertyBlock = true;
|
|
394
|
-
nestingStack.push('@property');
|
|
395
|
-
result += `${rawLine}\n`;
|
|
396
|
-
continue;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
if (insidePropertyBlock) {
|
|
400
|
-
result += `${rawLine}\n`;
|
|
401
|
-
if (line === '}') {
|
|
402
|
-
nestingStack.pop();
|
|
403
|
-
insidePropertyBlock = false;
|
|
404
|
-
}
|
|
405
|
-
continue;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
if (line.startsWith('@') && line.endsWith('{')) {
|
|
409
|
-
nestingStack.push('@block');
|
|
410
|
-
result += `${rawLine}\n`;
|
|
411
|
-
continue;
|
|
412
|
-
}
|
|
364
|
+
wp_enqueue_style($handle . '-frontend');
|
|
413
365
|
|
|
414
|
-
|
|
415
|
-
if (nestingStack.length) nestingStack.pop();
|
|
416
|
-
result += `${rawLine}\n`;
|
|
417
|
-
insideRule = false;
|
|
418
|
-
currentIsScoped = false;
|
|
419
|
-
continue;
|
|
420
|
-
}
|
|
366
|
+
wp_enqueue_script($handle . '-scripts');
|
|
421
367
|
|
|
422
|
-
|
|
423
|
-
|
|
368
|
+
wp_localize_script(
|
|
369
|
+
$handle . '-scripts',
|
|
370
|
+
'vars',
|
|
371
|
+
array(
|
|
372
|
+
'postId' => get_queried_object_id(),
|
|
373
|
+
'ajaxUrl' => admin_url('admin-ajax.php')
|
|
374
|
+
)
|
|
375
|
+
);
|
|
424
376
|
|
|
425
|
-
|
|
426
|
-
insideRule = true;
|
|
377
|
+
wp_enqueue_script($handle . '-remote-loader');
|
|
427
378
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
379
|
+
wp_add_inline_script(
|
|
380
|
+
$handle . '-remote-loader',
|
|
381
|
+
${JSON.stringify(inlineRemoteLoader)}
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
`;
|
|
386
|
+
};
|
|
431
387
|
|
|
432
|
-
|
|
433
|
-
|
|
388
|
+
function preprocessSvgAttributes(code) {
|
|
389
|
+
return code.replace(/(<svg[\s\S]*?>[\s\S]*?<\/svg>)/gi, (svgBlock) => {
|
|
390
|
+
let processed = svgBlock.replace(/([a-zA-Z0-9]+)-([a-zA-Z0-9]+)=/g, (match, p1, p2) => {
|
|
391
|
+
const camel = p1 + p2.charAt(0).toUpperCase() + p2.slice(1);
|
|
392
|
+
return camel + '=';
|
|
393
|
+
});
|
|
394
|
+
return processed;
|
|
395
|
+
});
|
|
396
|
+
}
|
|
434
397
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
398
|
+
function unwrapBody(code) {
|
|
399
|
+
try {
|
|
400
|
+
return code.replace(/<\/?(html|body)[^>]*>/gi, '');
|
|
401
|
+
} catch (e) {
|
|
402
|
+
return code;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
438
405
|
|
|
439
|
-
|
|
440
|
-
|
|
406
|
+
function transformBlockFile(blockCode) {
|
|
407
|
+
let test = '';
|
|
441
408
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
}
|
|
409
|
+
try {
|
|
410
|
+
test = babel.transformSync(blockCode, {
|
|
411
|
+
presets: [[presetReact, { pragma: 'wp.element.createElement' }]],
|
|
412
|
+
filename: 'block.js'
|
|
413
|
+
});
|
|
414
|
+
} catch (error) {
|
|
415
|
+
console.log(error);
|
|
450
416
|
|
|
451
|
-
result += `${rawLine}\n`;
|
|
452
417
|
}
|
|
453
418
|
|
|
454
|
-
return
|
|
419
|
+
return test;
|
|
455
420
|
}
|
|
456
421
|
|
|
457
422
|
const saveFiles = async (options) => {
|
|
458
|
-
const { cssFiles = [], shouldSaveFiles, name, prefix } = options;
|
|
459
|
-
|
|
423
|
+
const { cssFiles = [], jsFiles = [], shouldSaveFiles, name, prefix } = options;
|
|
424
|
+
const tailwindRegex = /(class|className)\s*=\s*["'][^"']*\b(items-center|justify-center|gap-\d+|rounded(-[a-z]+)?|text-[a-z]+-\d{3}|bg-[a-z]+-\d{3}|w-(full|screen)|h-(full|screen)|max-w-[\w\[\]-]+|p-\d+|m-\d+)\b[^"']*["']/i;
|
|
425
|
+
const hasTailwind = tailwindRegex.test(htmlContent);
|
|
426
|
+
const hasTailwindCdn = hasTailwindCdnSource(jsFiles);
|
|
427
|
+
|
|
428
|
+
css = hasTailwind && hasTailwindCdn ? '' : `
|
|
429
|
+
*:not(.components-button) {
|
|
430
|
+
all: revert-layer;
|
|
431
|
+
}\n`;
|
|
432
|
+
|
|
433
|
+
css += await parseRequirements(cssFiles, options);
|
|
434
|
+
|
|
435
|
+
console.log('[CSS BEFORE]', css);
|
|
436
|
+
|
|
460
437
|
|
|
461
438
|
for (const style of styles) {
|
|
462
|
-
css
|
|
463
|
-
*:not(.components-button) {
|
|
464
|
-
all: revert-layer;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
${style.content}` : `${style.content}`;
|
|
439
|
+
css += style.content;
|
|
468
440
|
}
|
|
469
441
|
|
|
470
|
-
|
|
471
|
-
|
|
442
|
+
css = css.replace(/[^{}]+:is\([^)]*\[.*?['"].*?\)[^{}]*\{[^}]*\}/g, '');
|
|
443
|
+
|
|
444
|
+
const scopedCssFrontend = scopeCss(css, `.wp-block-${sanitizeAndReplaceLeadingNumbers(replaceUnderscoresSpacesAndUppercaseLetters(prefix))}-${sanitizeAndReplaceLeadingNumbers(replaceUnderscoresSpacesAndUppercaseLetters(name))}`);
|
|
445
|
+
const editorStyleFile = scopeCss(css, `[data-type="${blockName}"]`);
|
|
472
446
|
const scriptFile = js;
|
|
447
|
+
|
|
448
|
+
htmlContent = htmlContent
|
|
449
|
+
.replace(/<head[\s\S]*?<\/head>/gi, '')
|
|
450
|
+
.replace(/<script[\s\S]*?<\/script>/gi, '')
|
|
451
|
+
.replace(/<style[\s\S]*?<\/style>/gi, '');
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
let blockCode = await getBlock(options);
|
|
455
|
+
|
|
456
|
+
blockCode = blockCode.replaceAll(' / dangerouslySetInnerHTML', ' dangerouslySetInnerHTML')
|
|
457
|
+
|
|
473
458
|
const indexFile = getPhp(options);
|
|
474
|
-
|
|
459
|
+
let blockFile = '';
|
|
460
|
+
|
|
461
|
+
try {
|
|
462
|
+
blockFile = transformBlockFile(blockCode).code
|
|
463
|
+
?.replace(/name: \"\{field.name\}\"/g, 'name: field.name')
|
|
464
|
+
?.replace(/key: \"\{index\}\"/g, 'key: index')
|
|
465
|
+
} catch (error) {
|
|
466
|
+
|
|
467
|
+
console.log(error);
|
|
468
|
+
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
console.log(blockFile);
|
|
475
472
|
|
|
476
|
-
const blockFile = babel.transformSync(blockCode, {
|
|
477
|
-
presets: [[presetReact, { pragma: 'wp.element.createElement' }]],
|
|
478
|
-
filename: 'block.js',
|
|
479
|
-
});
|
|
480
473
|
|
|
481
474
|
if (shouldSaveFiles) {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
475
|
+
try {
|
|
476
|
+
saveFile('style.css', scopedCssFrontend, options);
|
|
477
|
+
saveFile('editor.css', editorStyleFile, options);
|
|
478
|
+
saveFile('scripts.js', `${scriptFile}\n\n${emailTemplate}`, options);
|
|
479
|
+
saveFile('index.php', indexFile, options);
|
|
480
|
+
saveFile('block.js', blockFile, options);
|
|
481
|
+
saveFile('remote-loader.js', '', options);
|
|
482
|
+
} catch (error) {
|
|
483
|
+
console.log(error);
|
|
484
|
+
|
|
485
|
+
}
|
|
488
486
|
}
|
|
489
487
|
|
|
490
488
|
return {
|
|
@@ -492,7 +490,7 @@ const block = async (
|
|
|
492
490
|
'editor.css': editorStyleFile,
|
|
493
491
|
'scripts.js': scriptFile,
|
|
494
492
|
'index.php': indexFile,
|
|
495
|
-
'block.js': blockFile
|
|
493
|
+
'block.js': blockFile,
|
|
496
494
|
}
|
|
497
495
|
|
|
498
496
|
};
|
|
@@ -503,22 +501,24 @@ const block = async (
|
|
|
503
501
|
|
|
504
502
|
const generateRandomVariableName = (prefix = 'content', length = 3) => {
|
|
505
503
|
let suffix = '';
|
|
504
|
+
|
|
506
505
|
for (let i = 0; i < length; i++) {
|
|
507
506
|
suffix += characters.charAt(
|
|
508
507
|
Math.floor(Math.random() * characters.length)
|
|
509
508
|
);
|
|
510
509
|
}
|
|
510
|
+
|
|
511
511
|
return `${prefix}${suffix}`;
|
|
512
512
|
};
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
513
|
+
|
|
514
|
+
const functionSufix = generateRandomVariableName('func');
|
|
515
|
+
|
|
516
|
+
const setRandomAttributeContent = (randomVariableName, content) => {
|
|
517
|
+
const isArray = Array.isArray(content);
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
attributes[randomVariableName] = { type: isArray ? 'array' : 'string', default: content };
|
|
521
|
+
|
|
522
522
|
};
|
|
523
523
|
|
|
524
524
|
const hasAbsoluteKeyword = (str) => {
|
|
@@ -551,6 +551,7 @@ const block = async (
|
|
|
551
551
|
width: '100%',
|
|
552
552
|
height: '100%',
|
|
553
553
|
zIndex: 10,
|
|
554
|
+
cursor: 'pointer'
|
|
554
555
|
}}
|
|
555
556
|
></div>
|
|
556
557
|
</div>
|
|
@@ -559,12 +560,12 @@ const block = async (
|
|
|
559
560
|
`;
|
|
560
561
|
};
|
|
561
562
|
|
|
562
|
-
|
|
563
563
|
const replaceHtmlImage = (html, image) => {
|
|
564
564
|
const { randomUrlVariable } = image;
|
|
565
565
|
const regex = new RegExp(`<img\\s+[^>]*src=\\{[^}]*${randomUrlVariable}[^}]*\\}[^>]*>`, 'gi');
|
|
566
566
|
return html.replace(regex, getImageTemplate(image));
|
|
567
567
|
};
|
|
568
|
+
|
|
568
569
|
const replaceImageComponents = (html) => {
|
|
569
570
|
images.forEach((image) => {
|
|
570
571
|
html = replaceHtmlImage(html, image);
|
|
@@ -577,9 +578,10 @@ const block = async (
|
|
|
577
578
|
if (htmlContent) {
|
|
578
579
|
const newHtml = await extractAssets(htmlContent, {
|
|
579
580
|
basePath,
|
|
581
|
+
saveFile: true,
|
|
580
582
|
verbose: false,
|
|
581
|
-
saveFile: false,
|
|
582
583
|
});
|
|
584
|
+
|
|
583
585
|
return cheerio.load(newHtml, {
|
|
584
586
|
xmlMode: true,
|
|
585
587
|
decodeEntities: false,
|
|
@@ -642,53 +644,191 @@ const block = async (
|
|
|
642
644
|
};
|
|
643
645
|
const setImageAttribute = (properties) => {
|
|
644
646
|
const { imgTag, imgSrc, imgAlt, attribute, type, prefix } = properties;
|
|
645
|
-
const newPrefix = prefix ?
|
|
647
|
+
const newPrefix = prefix ? replaceUnderscoresSpacesAndUppercaseLetters(prefix) : 'wp';
|
|
646
648
|
const randomVariable = generateRandomVariableName(`${type}${newPrefix}`);
|
|
649
|
+
|
|
650
|
+
let imgSrcWithoutOrigin = imgSrc;
|
|
651
|
+
try {
|
|
652
|
+
if (typeof imgSrc === 'string') {
|
|
653
|
+
if (/^https?:\/\//.test(imgSrc)) {
|
|
654
|
+
const urlObj = new URL(imgSrc);
|
|
655
|
+
imgSrcWithoutOrigin = urlObj.pathname + urlObj.search + urlObj.hash;
|
|
656
|
+
} else if (source && imgSrc.startsWith(source)) {
|
|
657
|
+
imgSrcWithoutOrigin = imgSrc.slice(source.length);
|
|
658
|
+
if (imgSrcWithoutOrigin.startsWith('/')) imgSrcWithoutOrigin = imgSrcWithoutOrigin.slice(1);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
} catch (e) {
|
|
662
|
+
imgSrcWithoutOrigin = imgSrc;
|
|
663
|
+
}
|
|
664
|
+
let imgSrcNoLeadingSlash = imgSrcWithoutOrigin;
|
|
665
|
+
if (typeof imgSrcNoLeadingSlash === 'string' && imgSrcNoLeadingSlash.startsWith('/')) {
|
|
666
|
+
imgSrcNoLeadingSlash = imgSrcNoLeadingSlash.slice(1);
|
|
667
|
+
}
|
|
647
668
|
attributes[randomVariable] = {
|
|
648
669
|
attribute,
|
|
649
670
|
type: 'string',
|
|
650
671
|
selector: 'img',
|
|
651
|
-
default: attribute === 'alt' ? imgAlt :
|
|
672
|
+
default: attribute === 'alt' ? imgAlt : `{vars.url}${imgSrcNoLeadingSlash}`.replace(/^\u007f/, '$'),
|
|
652
673
|
};
|
|
674
|
+
|
|
653
675
|
imgTag.attr(attribute, `{attributes.${randomVariable}}`);
|
|
676
|
+
|
|
654
677
|
return randomVariable;
|
|
655
678
|
};
|
|
679
|
+
|
|
656
680
|
const processImage = (properties) => {
|
|
657
681
|
const { imgClass, type } = properties;
|
|
682
|
+
|
|
658
683
|
const randomUrlVariable = setImageAttribute({
|
|
659
684
|
...properties,
|
|
660
685
|
attribute: 'src',
|
|
661
686
|
prefix: 'Url',
|
|
662
687
|
});
|
|
688
|
+
|
|
663
689
|
const randomAltVariable = setImageAttribute({
|
|
664
690
|
...properties,
|
|
665
691
|
attribute: 'alt',
|
|
666
692
|
prefix: 'Alt',
|
|
667
693
|
});
|
|
694
|
+
|
|
668
695
|
if (type !== 'background') {
|
|
669
696
|
images.push({ randomUrlVariable, randomAltVariable, imgClass });
|
|
697
|
+
|
|
670
698
|
return;
|
|
671
699
|
}
|
|
700
|
+
|
|
672
701
|
createPanel({
|
|
673
702
|
type: 'media',
|
|
674
703
|
title: 'Background Image',
|
|
675
704
|
attributes: [randomUrlVariable, randomAltVariable],
|
|
676
705
|
});
|
|
677
706
|
};
|
|
707
|
+
|
|
708
|
+
const createPanelsForForm = () => {
|
|
709
|
+
const randomFormIdVariable = generateRandomVariableName('form');
|
|
710
|
+
const randomHiddenFieldsAttr = generateRandomVariableName('hiddenFields');
|
|
711
|
+
const randomSendEmailVariable = generateRandomVariableName('send');
|
|
712
|
+
const randomEmailFromVariable = generateRandomVariableName('emailFrom');
|
|
713
|
+
const randomEmailToVariable = generateRandomVariableName('emailTo');
|
|
714
|
+
const randomEmailSubjectVariable = generateRandomVariableName('emailSubj');
|
|
715
|
+
const randomEmailMessageVariable = generateRandomVariableName('emailMsg');
|
|
716
|
+
const randomTestFeedbackAttr = generateRandomVariableName('emailTestMsg');
|
|
717
|
+
|
|
718
|
+
Object.assign(formVars, {
|
|
719
|
+
randomFormIdVariable,
|
|
720
|
+
randomSendEmailVariable,
|
|
721
|
+
randomEmailFromVariable,
|
|
722
|
+
randomEmailToVariable,
|
|
723
|
+
randomEmailSubjectVariable,
|
|
724
|
+
randomEmailMessageVariable,
|
|
725
|
+
randomTestFeedbackAttr,
|
|
726
|
+
randomHiddenFieldsAttr
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
setRandomAttributeContent(randomFormIdVariable, `form-${randomFormIdVariable}`);
|
|
730
|
+
setRandomAttributeContent(randomSendEmailVariable, false);
|
|
731
|
+
setRandomAttributeContent(randomEmailFromVariable, '');
|
|
732
|
+
setRandomAttributeContent(randomEmailToVariable, '');
|
|
733
|
+
setRandomAttributeContent(randomEmailSubjectVariable, 'New Form Submission');
|
|
734
|
+
setRandomAttributeContent(randomEmailMessageVariable, 'Form data:\n{{fields}}');
|
|
735
|
+
setRandomAttributeContent(randomTestFeedbackAttr, '');
|
|
736
|
+
setRandomAttributeContent(randomHiddenFieldsAttr, []);
|
|
737
|
+
|
|
738
|
+
createPanel({
|
|
739
|
+
type: 'formSettings',
|
|
740
|
+
title: 'Form Settings',
|
|
741
|
+
attributes: [randomFormIdVariable, randomSendEmailVariable],
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
createPanel({
|
|
745
|
+
type: 'emailSettings',
|
|
746
|
+
title: 'Email Settings',
|
|
747
|
+
attributes: [
|
|
748
|
+
randomSendEmailVariable,
|
|
749
|
+
randomEmailFromVariable,
|
|
750
|
+
randomEmailToVariable,
|
|
751
|
+
randomEmailSubjectVariable,
|
|
752
|
+
randomEmailMessageVariable,
|
|
753
|
+
randomTestFeedbackAttr,
|
|
754
|
+
randomFormIdVariable
|
|
755
|
+
],
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
createPanel({
|
|
759
|
+
type: 'hiddenFields',
|
|
760
|
+
title: 'Hidden Fields',
|
|
761
|
+
attributes: [randomHiddenFieldsAttr],
|
|
762
|
+
});
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
const getFormVariables = () => ({ ...formVars });
|
|
766
|
+
|
|
767
|
+
const transformFormToDynamicJSX = (htmlContent) => {
|
|
768
|
+
const regex = /<form([\s\S]*?)>([\s\S]*?)<\/form>/gi
|
|
769
|
+
const formExists = regex.test(htmlContent);
|
|
770
|
+
|
|
771
|
+
if (!formExists) {
|
|
772
|
+
return htmlContent;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
return htmlContent.replace(
|
|
777
|
+
/<form([\s\S]*?)>([\s\S]*?)<\/form>/gi,
|
|
778
|
+
(_match, formAttributes, innerContent) => {
|
|
779
|
+
createPanelsForForm();
|
|
780
|
+
|
|
781
|
+
const {
|
|
782
|
+
randomFormIdVariable,
|
|
783
|
+
randomHiddenFieldsAttr
|
|
784
|
+
} = getFormVariables();
|
|
785
|
+
|
|
786
|
+
return `
|
|
787
|
+
<form
|
|
788
|
+
${formAttributes.trim()}
|
|
789
|
+
id={attributes.${randomFormIdVariable}}
|
|
790
|
+
>
|
|
791
|
+
${innerContent}
|
|
792
|
+
|
|
793
|
+
{ (attributes.${randomHiddenFieldsAttr} || []).map((field, index) => (<input key={index} name={field.name} value={field.value} type="hidden" /> )) }
|
|
794
|
+
</form>
|
|
795
|
+
`;
|
|
796
|
+
}
|
|
797
|
+
);
|
|
798
|
+
};
|
|
799
|
+
|
|
678
800
|
const getFixedHtml = (html) => {
|
|
801
|
+
function parseStyleString(style) {
|
|
802
|
+
const entries = style.split(';').filter(Boolean).map(rule => {
|
|
803
|
+
const [key, value] = rule.split(':');
|
|
804
|
+
if (!key || !value) return null;
|
|
805
|
+
const camelKey = key.trim().replace(/-([a-z])/g, (_, char) => char.toUpperCase());
|
|
806
|
+
return [camelKey, value.trim()];
|
|
807
|
+
}).filter(Boolean);
|
|
808
|
+
const styleObject = Object.fromEntries(entries);
|
|
809
|
+
return JSON.stringify(styleObject).replace(/"([^"\n]+)":/g, '$1:');
|
|
810
|
+
}
|
|
679
811
|
return html
|
|
812
|
+
.replace(/style="([^"]+)"/g, (_, styleString) => {
|
|
813
|
+
const styleObj = parseStyleString(styleString);
|
|
814
|
+
return `style={${styleObj}}`;
|
|
815
|
+
})
|
|
680
816
|
.replace(/ onChange="{" \(newtext\)=""\>/gi, ' onChange={ (newtext) => ')
|
|
681
817
|
.replace(/\<\/RichText\>/gi, '')
|
|
682
818
|
.replace(/value="{(.*?)}"/gi, 'value={$1}')
|
|
683
819
|
.replace(/"{attributes.(.*?)}"/gi, '{attributes.$1}');
|
|
684
820
|
};
|
|
821
|
+
|
|
685
822
|
const processImages = (imgTag) => {
|
|
686
823
|
const properties = getImageProperties(imgTag);
|
|
687
824
|
const { isBackground } = properties;
|
|
825
|
+
|
|
688
826
|
if (!isBackground) {
|
|
689
827
|
processImage({ ...properties, type: 'image' });
|
|
828
|
+
|
|
690
829
|
return;
|
|
691
830
|
}
|
|
831
|
+
|
|
692
832
|
processImage({ ...properties, type: 'background' });
|
|
693
833
|
};
|
|
694
834
|
const loopImages = ($) => {
|
|
@@ -696,9 +836,11 @@ const block = async (
|
|
|
696
836
|
processImages($(img));
|
|
697
837
|
});
|
|
698
838
|
};
|
|
839
|
+
|
|
699
840
|
const getHtml = ($) => {
|
|
700
841
|
return $.html({ xml: false, decodeEntities: false });
|
|
701
842
|
};
|
|
843
|
+
|
|
702
844
|
const processEditImages = async (options) => {
|
|
703
845
|
const $ = await loadHtml(options);
|
|
704
846
|
loopImages($);
|
|
@@ -715,43 +857,52 @@ const block = async (
|
|
|
715
857
|
}}
|
|
716
858
|
/><`;
|
|
717
859
|
};
|
|
860
|
+
|
|
718
861
|
const convertToRichText = (variableContent) => {
|
|
719
862
|
const randomVariable = generateRandomVariableName('content');
|
|
720
|
-
|
|
863
|
+
|
|
864
|
+
setRandomAttributeContent(randomVariable, variableContent);
|
|
865
|
+
|
|
721
866
|
return getRichTextTemplate(randomVariable, variableContent);
|
|
722
867
|
};
|
|
868
|
+
|
|
723
869
|
const parseContent = (content) => {
|
|
724
870
|
return content.replace(/>([^<]+)</g, (match, variableContent) => {
|
|
725
|
-
|
|
871
|
+
const regex = /{|}|\(|\)|=>/;
|
|
872
|
+
|
|
873
|
+
if (regex.test(variableContent.trim())) {
|
|
874
|
+
return match;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
if (variableContent.trim() === '') {
|
|
726
878
|
return match;
|
|
727
879
|
}
|
|
880
|
+
|
|
728
881
|
return convertToRichText(variableContent);
|
|
729
882
|
});
|
|
730
883
|
};
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
884
|
+
|
|
885
|
+
const getEditJsxContent = async (options) => {
|
|
886
|
+
let content = transformFormToDynamicJSX(options.htmlContent);
|
|
887
|
+
|
|
888
|
+
content = content.replaceAll(/<!--(.*?)-->/gs, '');
|
|
889
|
+
|
|
736
890
|
content = `<div className="custom-block">${content}</div>`;
|
|
891
|
+
|
|
737
892
|
return await processEditImages({
|
|
738
893
|
...options,
|
|
739
|
-
htmlContent:
|
|
894
|
+
htmlContent: parseContent(content),
|
|
740
895
|
});
|
|
741
896
|
};
|
|
897
|
+
|
|
742
898
|
const createPanel = (values) => {
|
|
743
899
|
if (values.attributes && values.attributes.length > 0) {
|
|
744
900
|
panels.push(values);
|
|
745
901
|
}
|
|
746
902
|
};
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
${group1}
|
|
751
|
-
dangerouslySetInnerHTML={ { __html: attributes.${randomSVGVariable} }}
|
|
752
|
-
>
|
|
753
|
-
${group3}
|
|
754
|
-
`;
|
|
903
|
+
|
|
904
|
+
const getSvgTemplate = (_match, group1, _group3, randomSVGVariable) => {
|
|
905
|
+
return `<svg ${group1} dangerouslySetInnerHTML={ { __html: attributes.${randomSVGVariable} }}></svg>`;
|
|
755
906
|
};
|
|
756
907
|
const replaceSVGImages = async (html) => {
|
|
757
908
|
const regex = /<\s*svg\b((?:[^>'"]|"[^"]*"|'[^']*')*)>(\s*(?:[^<]|<(?!\/svg\s*>))*)(<\/\s*svg\s*>)/gim;
|
|
@@ -770,17 +921,15 @@ const block = async (
|
|
|
770
921
|
const content = group2.trim();
|
|
771
922
|
if (content) {
|
|
772
923
|
const randomSVGVariable = generateRandomVariableName('svg');
|
|
773
|
-
|
|
924
|
+
setRandomAttributeContent(randomSVGVariable, content.replaceAll('className', 'class'));
|
|
774
925
|
createPanel({
|
|
775
926
|
type: 'svg',
|
|
776
927
|
title: 'SVG Markup',
|
|
777
928
|
attributes: [randomSVGVariable],
|
|
778
929
|
});
|
|
779
930
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
{ jsxRuntime: 'classic' }
|
|
783
|
-
);
|
|
931
|
+
|
|
932
|
+
const replacement = getSvgTemplate(fullMatch, group1, group3, randomSVGVariable)
|
|
784
933
|
|
|
785
934
|
result += replacement;
|
|
786
935
|
} else {
|
|
@@ -791,6 +940,9 @@ const block = async (
|
|
|
791
940
|
}
|
|
792
941
|
|
|
793
942
|
result += html.slice(lastIndex);
|
|
943
|
+
|
|
944
|
+
console.log(result);
|
|
945
|
+
|
|
794
946
|
return result;
|
|
795
947
|
};
|
|
796
948
|
const getSvgPanelTemplate = (panel) => {
|
|
@@ -822,6 +974,7 @@ const block = async (
|
|
|
822
974
|
? `${panel.attributes[0]}: media.url,
|
|
823
975
|
${panel.attributes[1]}: media.alt`
|
|
824
976
|
: '';
|
|
977
|
+
|
|
825
978
|
return panel.attributes &&
|
|
826
979
|
panel.attributes[0] &&
|
|
827
980
|
attributes[panel.attributes[0]]
|
|
@@ -830,10 +983,7 @@ const block = async (
|
|
|
830
983
|
<PanelRow>
|
|
831
984
|
<div>
|
|
832
985
|
<MediaUpload
|
|
833
|
-
onSelect={ (media) => {
|
|
834
|
-
setAttributes({
|
|
835
|
-
${mediaAtts}
|
|
836
|
-
});
|
|
986
|
+
onSelect={ (media) => { setAttributes({ ${mediaAtts} });
|
|
837
987
|
} }
|
|
838
988
|
type="image"
|
|
839
989
|
value={ attributes.${panel.attributes?.[0]} }
|
|
@@ -851,12 +1001,272 @@ const block = async (
|
|
|
851
1001
|
: '';
|
|
852
1002
|
};
|
|
853
1003
|
|
|
854
|
-
const
|
|
1004
|
+
const getFormSettingsPanelTemplate = (panel) => {
|
|
1005
|
+
const [formIdAttr, sendEmailAttr] = panel.attributes;
|
|
1006
|
+
|
|
1007
|
+
return `
|
|
1008
|
+
<PanelBody title="${panel.title}" initialOpen={true}>
|
|
1009
|
+
<TextControl
|
|
1010
|
+
label="Form ID"
|
|
1011
|
+
disabled="true"
|
|
1012
|
+
value={attributes.${formIdAttr}}
|
|
1013
|
+
onChange={(val) => setAttributes({ ${formIdAttr}: val })}
|
|
1014
|
+
/>
|
|
1015
|
+
<ToggleControl
|
|
1016
|
+
label="Send Email on Submit"
|
|
1017
|
+
checked={attributes.${sendEmailAttr}}
|
|
1018
|
+
onChange={(val) => setAttributes({ ${sendEmailAttr}: val })}
|
|
1019
|
+
/>
|
|
1020
|
+
</PanelBody>
|
|
1021
|
+
`;
|
|
1022
|
+
};
|
|
1023
|
+
|
|
1024
|
+
const getPhpEmailData = (formIdAttr, fromAttr, toAttr, subjectAttr, messageAttr) => {
|
|
1025
|
+
return `
|
|
1026
|
+
add_action('wp_ajax_send_email_${formIdAttr}', function() {
|
|
1027
|
+
//check_ajax_referer('wp_rest');
|
|
1028
|
+
|
|
1029
|
+
$post_id = $_POST['postId'];
|
|
1030
|
+
|
|
1031
|
+
if (!$post_id) {
|
|
1032
|
+
wp_send_json_error('Missing post ID.');
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
$post_data = $_POST;
|
|
1036
|
+
$post = get_post($post_id);
|
|
1037
|
+
|
|
1038
|
+
if (!$post) {
|
|
1039
|
+
wp_send_json_error('Post not found.');
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
$blocks = parse_blocks($post->post_content);
|
|
1043
|
+
|
|
1044
|
+
$target_block = null;
|
|
1045
|
+
|
|
1046
|
+
foreach ($blocks as $block) {
|
|
1047
|
+
if ($block['blockName'] === '${blockName}') {
|
|
1048
|
+
$target_block = $block;
|
|
1049
|
+
break;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
if (!$target_block) {
|
|
1054
|
+
wp_send_json_error('Block not found.');
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
$attrs = $target_block['attrs'] ?? [];
|
|
1058
|
+
|
|
1059
|
+
$to = sanitize_email(parse_form_placeholders_${functionSufix}($attrs['${toAttr}'] ?? '', $post_data));
|
|
1060
|
+
$from = sanitize_email(parse_form_placeholders_${functionSufix}($attrs['${fromAttr}'] ?? '', $post_data));
|
|
1061
|
+
$subject = sanitize_text_field(parse_form_placeholders_${functionSufix}($attrs['${subjectAttr}'] ?? '', $post_data));
|
|
1062
|
+
$message = wp_kses_post(parse_form_placeholders_${functionSufix}($attrs['${messageAttr}'] ?? '', $post_data));
|
|
1063
|
+
|
|
1064
|
+
if (empty($to) || empty($from)) {
|
|
1065
|
+
wp_send_json_error('Missing email addresses.');
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
$sent = wp_mail($to, $subject, $message, [
|
|
1069
|
+
'Content-Type: text/html; charset=UTF-8',
|
|
1070
|
+
'From: ' . $from
|
|
1071
|
+
]);
|
|
1072
|
+
|
|
1073
|
+
if ($sent) {
|
|
1074
|
+
wp_send_json_success('Email sent');
|
|
1075
|
+
} else {
|
|
1076
|
+
error_log('Failed to send. To: ' . $to . ' | From: ' . $from);
|
|
1077
|
+
wp_send_json_error('Failed to send email.');
|
|
1078
|
+
}
|
|
1079
|
+
});
|
|
1080
|
+
`;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
const getEmailSettingsPanelTemplate = (panel) => {
|
|
1084
|
+
const [
|
|
1085
|
+
sendEmailAttr,
|
|
1086
|
+
fromAttr,
|
|
1087
|
+
toAttr,
|
|
1088
|
+
subjectAttr,
|
|
1089
|
+
messageAttr,
|
|
1090
|
+
testFeedbackAttr,
|
|
1091
|
+
formIdAttr,
|
|
1092
|
+
] = panel.attributes;
|
|
1093
|
+
|
|
1094
|
+
emailTemplate += sendEmailAttr ? getEmailSaveTemplate(formIdAttr) : '';
|
|
1095
|
+
phpEmailData += getPhpEmailData(formIdAttr, fromAttr, toAttr, subjectAttr, messageAttr);
|
|
1096
|
+
|
|
1097
|
+
return `
|
|
1098
|
+
{ attributes.${sendEmailAttr} && (
|
|
1099
|
+
<PanelBody title="${panel.title}" initialOpen={true}>
|
|
1100
|
+
<TextControl
|
|
1101
|
+
label="From"
|
|
1102
|
+
value={attributes.${fromAttr}}
|
|
1103
|
+
onChange={(val) => setAttributes({ ${fromAttr}: val })}
|
|
1104
|
+
/>
|
|
1105
|
+
<TextControl
|
|
1106
|
+
label="To"
|
|
1107
|
+
value={attributes.${toAttr}}
|
|
1108
|
+
onChange={(val) => setAttributes({ ${toAttr}: val })}
|
|
1109
|
+
/>
|
|
1110
|
+
<TextControl
|
|
1111
|
+
label="Subject"
|
|
1112
|
+
value={attributes.${subjectAttr}}
|
|
1113
|
+
onChange={(val) => setAttributes({ ${subjectAttr}: val })}
|
|
1114
|
+
/>
|
|
1115
|
+
<TextareaControl
|
|
1116
|
+
label="Message Template (HTML Supported)"
|
|
1117
|
+
help="Use {{fieldName}} to insert field values."
|
|
1118
|
+
value={attributes.${messageAttr}}
|
|
1119
|
+
onChange={(val) => setAttributes({ ${messageAttr}: val })}
|
|
1120
|
+
/>
|
|
1121
|
+
|
|
1122
|
+
<Button
|
|
1123
|
+
variant="primary"
|
|
1124
|
+
onClick={() => {
|
|
1125
|
+
const form = document.getElementById('form-${formIdAttr}');
|
|
1126
|
+
const inputs = form.querySelectorAll('input, select, textarea');
|
|
1127
|
+
const body = new URLSearchParams();
|
|
1128
|
+
|
|
1129
|
+
inputs.forEach(input => {
|
|
1130
|
+
if (input.name && !input.disabled) {
|
|
1131
|
+
body.append(input.name, input.value);
|
|
1132
|
+
}
|
|
1133
|
+
});
|
|
1134
|
+
|
|
1135
|
+
body.append('action', 'send_test_email_${functionSufix}');
|
|
1136
|
+
body.append('from', attributes?.${fromAttr} || '');
|
|
1137
|
+
body.append('to', attributes?.${toAttr} || '');
|
|
1138
|
+
body.append('subject', attributes?.${subjectAttr} || '');
|
|
1139
|
+
body.append('message', attributes?.${messageAttr} || '');
|
|
1140
|
+
|
|
1141
|
+
fetch(vars.ajaxUrl, {
|
|
1142
|
+
method: 'POST',
|
|
1143
|
+
body
|
|
1144
|
+
})
|
|
1145
|
+
.then(res => res.json())
|
|
1146
|
+
.then(data => {
|
|
1147
|
+
setAttributes({ ${testFeedbackAttr}: data.success ? 'Test Email Sent!' : data.error });
|
|
1148
|
+
})
|
|
1149
|
+
.catch(() => {
|
|
1150
|
+
setAttributes({ ${testFeedbackAttr}: 'Failed to send test email.' });
|
|
1151
|
+
});
|
|
1152
|
+
}}
|
|
1153
|
+
>
|
|
1154
|
+
Send Test Email
|
|
1155
|
+
</Button>
|
|
1156
|
+
|
|
1157
|
+
{attributes.${testFeedbackAttr} && (
|
|
1158
|
+
<Notice status="info" isDismissible={false}>
|
|
1159
|
+
{attributes.${testFeedbackAttr}}
|
|
1160
|
+
</Notice>
|
|
1161
|
+
)}
|
|
1162
|
+
</PanelBody>
|
|
1163
|
+
)}
|
|
1164
|
+
`;
|
|
1165
|
+
};
|
|
1166
|
+
|
|
1167
|
+
const getEmailSaveTemplate = (formIdAttr) => {
|
|
1168
|
+
return `
|
|
1169
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
1170
|
+
const form = document.getElementById('form-${formIdAttr}');
|
|
1171
|
+
|
|
1172
|
+
form.addEventListener('submit', function(event) {
|
|
1173
|
+
event.preventDefault();
|
|
1174
|
+
|
|
1175
|
+
const inputs = form.querySelectorAll('input, select, textarea');
|
|
1176
|
+
const body = new URLSearchParams();
|
|
1177
|
+
|
|
1178
|
+
inputs.forEach(input => {
|
|
1179
|
+
if (input.name && !input.disabled) {
|
|
1180
|
+
body.append(input.name, input.value);
|
|
1181
|
+
}
|
|
1182
|
+
});
|
|
1183
|
+
|
|
1184
|
+
body.append('action', 'send_email_${formIdAttr}');
|
|
1185
|
+
body.append('postId', vars.postId);
|
|
1186
|
+
|
|
1187
|
+
fetch(vars.ajaxUrl, {
|
|
1188
|
+
method: 'POST',
|
|
1189
|
+
body
|
|
1190
|
+
})
|
|
1191
|
+
.then(res => res.json())
|
|
1192
|
+
.then(data => {
|
|
1193
|
+
console.log(data.success ? 'Test Email Sent!' : data.error);
|
|
1194
|
+
})
|
|
1195
|
+
.catch(() => {
|
|
1196
|
+
console.log('Failed to send test email.');
|
|
1197
|
+
});
|
|
1198
|
+
|
|
1199
|
+
form.reset()
|
|
1200
|
+
});
|
|
1201
|
+
});
|
|
1202
|
+
`;
|
|
1203
|
+
};
|
|
1204
|
+
|
|
1205
|
+
const getHiddenFieldsPanelTemplate = (panel) => {
|
|
1206
|
+
const [hiddenFieldsAttr] = panel.attributes;
|
|
1207
|
+
|
|
1208
|
+
return `
|
|
1209
|
+
<PanelBody title="${panel.title}" initialOpen={false}>
|
|
1210
|
+
{ (attributes.${hiddenFieldsAttr} || []).map((field, index) => (
|
|
1211
|
+
<div key={index} style={{ marginBottom: '10px', borderBottom: '1px solid #ddd', paddingBottom: '10px' }}>
|
|
1212
|
+
<TextControl
|
|
1213
|
+
label="Name"
|
|
1214
|
+
value={field.name}
|
|
1215
|
+
onChange={(val) => {
|
|
1216
|
+
const newFields = [...attributes.${hiddenFieldsAttr}];
|
|
1217
|
+
newFields[index].name = val;
|
|
1218
|
+
setAttributes({ ${hiddenFieldsAttr}: newFields });
|
|
1219
|
+
}}
|
|
1220
|
+
/>
|
|
1221
|
+
<TextControl
|
|
1222
|
+
label="Value"
|
|
1223
|
+
value={field.value}
|
|
1224
|
+
onChange={(val) => {
|
|
1225
|
+
const newFields = [...attributes.${hiddenFieldsAttr}];
|
|
1226
|
+
newFields[index].value = val;
|
|
1227
|
+
setAttributes({ ${hiddenFieldsAttr}: newFields });
|
|
1228
|
+
}}
|
|
1229
|
+
/>
|
|
1230
|
+
<Button
|
|
1231
|
+
variant="secondary"
|
|
1232
|
+
onClick={() => {
|
|
1233
|
+
const newFields = [...attributes.${hiddenFieldsAttr}];
|
|
1234
|
+
newFields.splice(index, 1);
|
|
1235
|
+
setAttributes({ ${hiddenFieldsAttr}: newFields });
|
|
1236
|
+
}}
|
|
1237
|
+
>
|
|
1238
|
+
Remove
|
|
1239
|
+
</Button>
|
|
1240
|
+
</div>
|
|
1241
|
+
))}
|
|
1242
|
+
|
|
1243
|
+
<Button
|
|
1244
|
+
variant="primary"
|
|
1245
|
+
onClick={() => {
|
|
1246
|
+
const newFields = [...(attributes.${hiddenFieldsAttr} || [])];
|
|
1247
|
+
newFields.push({ name: '', value: '' });
|
|
1248
|
+
setAttributes({ ${hiddenFieldsAttr}: newFields });
|
|
1249
|
+
}}
|
|
1250
|
+
>
|
|
1251
|
+
Add Hidden Field
|
|
1252
|
+
</Button>
|
|
1253
|
+
</PanelBody>
|
|
1254
|
+
`;
|
|
1255
|
+
};
|
|
1256
|
+
|
|
1257
|
+
|
|
1258
|
+
const findAndGetPanelTemplate = (panel) => {
|
|
855
1259
|
switch (panel.type) {
|
|
856
1260
|
case 'svg':
|
|
857
1261
|
return getSvgPanelTemplate(panel);
|
|
858
1262
|
case 'media':
|
|
859
1263
|
return getMediaPanelTemplate(panel);
|
|
1264
|
+
case 'formSettings':
|
|
1265
|
+
return getFormSettingsPanelTemplate(panel);
|
|
1266
|
+
case 'emailSettings':
|
|
1267
|
+
return getEmailSettingsPanelTemplate(panel);
|
|
1268
|
+
case 'hiddenFields':
|
|
1269
|
+
return getHiddenFieldsPanelTemplate(panel);
|
|
860
1270
|
default:
|
|
861
1271
|
return '';
|
|
862
1272
|
}
|
|
@@ -865,7 +1275,7 @@ const block = async (
|
|
|
865
1275
|
const getPanelsTemplate = () => {
|
|
866
1276
|
return panels
|
|
867
1277
|
.map((panel) => {
|
|
868
|
-
return
|
|
1278
|
+
return findAndGetPanelTemplate(panel);
|
|
869
1279
|
})
|
|
870
1280
|
.join('\n');
|
|
871
1281
|
};
|
|
@@ -877,28 +1287,35 @@ const block = async (
|
|
|
877
1287
|
</Panel>`;
|
|
878
1288
|
};
|
|
879
1289
|
|
|
880
|
-
const
|
|
1290
|
+
const buildSaveContent = (editContent) => {
|
|
881
1291
|
return editContent.replace(
|
|
882
1292
|
/<RichText((.|\n)*?)value=\{(.*?)\}((.|\n)*?)\/>/gi,
|
|
883
1293
|
'<RichText.Content value={$3} />'
|
|
884
|
-
)
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
1294
|
+
)
|
|
1295
|
+
.replaceAll('class=', 'className=')
|
|
1296
|
+
.replace(
|
|
1297
|
+
/<MediaUpload\b[^>]*>([\s\S]*?(<img\b[^>]*>*\/>)[\s\S]*?)\/>/g,
|
|
1298
|
+
(_match, _attributes, img) => {
|
|
1299
|
+
return img.replace(/onClick={[^}]+}\s*/, '');
|
|
1300
|
+
}
|
|
1301
|
+
);
|
|
889
1302
|
};
|
|
890
1303
|
|
|
891
1304
|
const removeHref = (match) => {
|
|
892
1305
|
return match.replace(/href="(.*?)"/, '');
|
|
893
1306
|
};
|
|
1307
|
+
|
|
894
1308
|
const replaceRichText = (match, group1, _group2, group3) => {
|
|
895
1309
|
return removeHref(match)
|
|
896
1310
|
.replace(group1, '<span')
|
|
897
1311
|
.replace(group3, '</span>');
|
|
898
1312
|
};
|
|
1313
|
+
|
|
899
1314
|
const processLinks = (options) => {
|
|
900
|
-
let htmlContent = options
|
|
901
|
-
|
|
1315
|
+
let { htmlContent } = options;
|
|
1316
|
+
|
|
1317
|
+
htmlContent = htmlContent
|
|
1318
|
+
? htmlContent.replace(
|
|
902
1319
|
/(<a)[^>]*>([\s\S]*?)(<\/a>)/gim,
|
|
903
1320
|
replaceRichText
|
|
904
1321
|
)
|
|
@@ -935,84 +1352,62 @@ const block = async (
|
|
|
935
1352
|
);
|
|
936
1353
|
};
|
|
937
1354
|
|
|
938
|
-
const transformOnClickEvent = (img) => {
|
|
939
|
-
return img.replace(/onClick={[^}]+}\s*/, '');
|
|
940
|
-
};
|
|
941
|
-
|
|
942
|
-
const processSaveImages = (htmlString) => {
|
|
943
|
-
return htmlString.replace(
|
|
944
|
-
/<MediaUpload\b[^>]*>([\s\S]*?(<img\b[^>]*>*\/>)[\s\S]*?)\/>/g,
|
|
945
|
-
(_match, _attributes, img) => transformOnClickEvent(img)
|
|
946
|
-
);
|
|
947
|
-
};
|
|
948
|
-
|
|
949
1355
|
const getComponentAttributes = () => {
|
|
950
|
-
return
|
|
1356
|
+
return Object.entries(attributes)
|
|
1357
|
+
.map(([key, value]) => {
|
|
1358
|
+
if (typeof value === 'object' && value !== null) {
|
|
1359
|
+
return `${key}: { ${Object.entries(value).map(([k, v]) => `${k}: \`${v}\``).join(', ')} }`;
|
|
1360
|
+
} else {
|
|
1361
|
+
return `${key}:\`${value}\``;
|
|
1362
|
+
}
|
|
1363
|
+
})
|
|
1364
|
+
.join(',\n');
|
|
951
1365
|
};
|
|
952
1366
|
|
|
953
1367
|
const getEdit = async (options) => {
|
|
954
1368
|
let { htmlContent } = options;
|
|
955
1369
|
|
|
956
1370
|
if (htmlContent) {
|
|
957
|
-
htmlContent =
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1371
|
+
options.htmlContent = unwrapBody(htmlContent);
|
|
1372
|
+
const postProcessLinks = processLinks(options);
|
|
1373
|
+
const postGetEditJsx = await getEditJsxContent(postProcessLinks);
|
|
1374
|
+
const preConvert = await postGetEditJsx.replace(/<\/br>/g, '<br/>').replace(/<\/hr>/g, '<hr/>')
|
|
1375
|
+
return convert(preConvert)
|
|
962
1376
|
}
|
|
1377
|
+
|
|
963
1378
|
return '';
|
|
964
1379
|
};
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1380
|
+
|
|
1381
|
+
const parseBlockAttributes = () => {
|
|
1382
|
+
const attrs = `{${getComponentAttributes()}}`;
|
|
1383
|
+
return replaceSourceUrlVars(attrs, options.source);
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
const getBlock = async (settings) => {
|
|
969
1387
|
let {
|
|
970
|
-
prefix,
|
|
971
1388
|
name,
|
|
972
1389
|
category,
|
|
973
1390
|
generateIconPreview,
|
|
974
|
-
basePath,
|
|
975
|
-
cssFiles,
|
|
976
|
-
jsFiles,
|
|
977
1391
|
} = settings;
|
|
978
|
-
|
|
979
|
-
const
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
let iconPreview = "'shield'";
|
|
983
|
-
let edit = await getEdit(settings);
|
|
984
|
-
edit = edit.replace(
|
|
985
|
-
/dangerouslySetInnerHTML="{" {="" __html:="" (.*?)="" }}=""/gm,
|
|
986
|
-
`dangerouslySetInnerHTML={{ __html: $1 }}`
|
|
987
|
-
);
|
|
988
|
-
const save = getSave(edit);
|
|
1392
|
+
|
|
1393
|
+
const iconPreview = generateIconPreview ? `(<img src={vars.url + 'preview.jpeg'} />)` : "'shield'";
|
|
1394
|
+
const edit = await getEdit(settings);
|
|
1395
|
+
const save = buildSaveContent(edit);
|
|
989
1396
|
const blockPanels = createPanels();
|
|
990
|
-
|
|
991
|
-
JSON.stringify(getComponentAttributes(), null, 2)
|
|
992
|
-
).replace(/"var.url\+\'(.*?)\'(.*?)"/g, "vars.url+'$1'$2").replaceAll("var(.*?).url\+'(http.*?)'", 'http$2')}`;
|
|
993
|
-
if (generateIconPreview) {
|
|
994
|
-
try {
|
|
995
|
-
await icon(htmlContent, { basePath, cssFiles, jsFiles });
|
|
996
|
-
iconPreview = `(<img src="data:image/jpeg;base64,${await imageToBase64(
|
|
997
|
-
path.join(basePath, 'preview.jpeg')
|
|
998
|
-
)}" />)`;
|
|
999
|
-
} catch (error) {
|
|
1000
|
-
console.log(`There was an error generating preview. ${error.message}`);
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1397
|
+
|
|
1003
1398
|
const output = `
|
|
1004
1399
|
(function () {
|
|
1005
1400
|
${imports}
|
|
1006
1401
|
|
|
1007
|
-
registerBlockType('${
|
|
1402
|
+
registerBlockType('${blockName}', {
|
|
1008
1403
|
title: '${name}',
|
|
1009
1404
|
icon: ${iconPreview},
|
|
1010
1405
|
category: '${category}',
|
|
1011
|
-
attributes: ${
|
|
1406
|
+
attributes: ${parseBlockAttributes()},
|
|
1012
1407
|
edit(props) {
|
|
1013
|
-
|
|
1408
|
+
const { attributes, setAttributes } = props;
|
|
1014
1409
|
|
|
1015
|
-
|
|
1410
|
+
return (
|
|
1016
1411
|
<div>
|
|
1017
1412
|
<InspectorControls>
|
|
1018
1413
|
${blockPanels}
|
|
@@ -1023,22 +1418,22 @@ const block = async (
|
|
|
1023
1418
|
);
|
|
1024
1419
|
},
|
|
1025
1420
|
save(props) {
|
|
1026
|
-
|
|
1421
|
+
const { attributes } = props;
|
|
1027
1422
|
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1423
|
+
return (
|
|
1424
|
+
${save}
|
|
1425
|
+
);
|
|
1031
1426
|
},
|
|
1032
1427
|
});
|
|
1033
1428
|
})();`;
|
|
1034
|
-
|
|
1035
|
-
return output.replace(/icon: \s * (')([^']*)(')/, 'icon: $2');
|
|
1036
|
-
}
|
|
1429
|
+
|
|
1037
1430
|
return output;
|
|
1038
1431
|
};
|
|
1432
|
+
|
|
1039
1433
|
const setupVariables = async (htmlContent, options) => {
|
|
1434
|
+
|
|
1040
1435
|
const styleRegex = /<style[^>]*>([\s\S]*?)<\/style>/gi;
|
|
1041
|
-
const linkRegex = /<link\
|
|
1436
|
+
const linkRegex = /<link\b[^>]*((\brel=["']stylesheet["'])|\bhref=["'][^"']+\.css["'])[^>]*>/gi;
|
|
1042
1437
|
|
|
1043
1438
|
let match;
|
|
1044
1439
|
|
|
@@ -1061,10 +1456,15 @@ const block = async (
|
|
|
1061
1456
|
|
|
1062
1457
|
await Promise.all(fetchCssPromises);
|
|
1063
1458
|
|
|
1064
|
-
css
|
|
1459
|
+
css += styles.map((style) => {
|
|
1065
1460
|
return `${style.content}`;
|
|
1066
1461
|
}).join('\n');
|
|
1067
1462
|
|
|
1463
|
+
|
|
1464
|
+
console.log('[CSSFETCHED]', css);
|
|
1465
|
+
|
|
1466
|
+
|
|
1467
|
+
|
|
1068
1468
|
const scriptRegex = /<script[^>]*>([\s\S]*?)<\/script>/gi;
|
|
1069
1469
|
const scriptSrcRegex =
|
|
1070
1470
|
/<script\s+[^>]*src=["']([^"']+)["'][^>]*>\s*<\/script>/gi;
|
|
@@ -1079,6 +1479,7 @@ const block = async (
|
|
|
1079
1479
|
});
|
|
1080
1480
|
|
|
1081
1481
|
const fetchJsPromises = [];
|
|
1482
|
+
|
|
1082
1483
|
while ((jsMatch = scriptSrcRegex.exec(htmlContent)) !== null) {
|
|
1083
1484
|
const url = jsMatch[1];
|
|
1084
1485
|
const fetchJsPromise = fetch(url)
|
|
@@ -1092,7 +1493,7 @@ const block = async (
|
|
|
1092
1493
|
|
|
1093
1494
|
await Promise.all(fetchJsPromises);
|
|
1094
1495
|
|
|
1095
|
-
js
|
|
1496
|
+
js += scripts.map((script) => script.content).join('\n');
|
|
1096
1497
|
|
|
1097
1498
|
let {
|
|
1098
1499
|
basePath = process.cwd(),
|
|
@@ -1100,9 +1501,24 @@ const block = async (
|
|
|
1100
1501
|
jsFiles = [],
|
|
1101
1502
|
name = 'My block',
|
|
1102
1503
|
} = options;
|
|
1103
|
-
|
|
1504
|
+
|
|
1505
|
+
const newDir = path.join(basePath, replaceUnderscoresSpacesAndUppercaseLetters(name));
|
|
1506
|
+
|
|
1507
|
+
const $ = cheerio.load(htmlContent, {
|
|
1508
|
+
xmlMode: true,
|
|
1509
|
+
decodeEntities: false,
|
|
1510
|
+
});
|
|
1511
|
+
|
|
1512
|
+
$('head, script, style').remove();
|
|
1513
|
+
|
|
1514
|
+
htmlContent = $('body').html();
|
|
1515
|
+
|
|
1516
|
+
options.html
|
|
1517
|
+
|
|
1518
|
+
|
|
1104
1519
|
try {
|
|
1105
1520
|
fs.mkdirSync(newDir, { recursive: true });
|
|
1521
|
+
|
|
1106
1522
|
return {
|
|
1107
1523
|
...options,
|
|
1108
1524
|
jsFiles,
|
|
@@ -1114,6 +1530,19 @@ const block = async (
|
|
|
1114
1530
|
logError(error);
|
|
1115
1531
|
}
|
|
1116
1532
|
};
|
|
1533
|
+
|
|
1534
|
+
if (source) {
|
|
1535
|
+
htmlContent = replaceRelativeUrlsInHtml(htmlContent, source);
|
|
1536
|
+
htmlContent = replaceRelativeUrlsInCssWithBase(htmlContent, source);
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
try {
|
|
1540
|
+
icon(htmlContent, { basePath: path.join(options.basePath, replaceUnderscoresSpacesAndUppercaseLetters(options.name)) });
|
|
1541
|
+
} catch (error) {
|
|
1542
|
+
console.log(`There was an error generating preview. ${error.message}`);
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1117
1545
|
return saveFiles(await setupVariables(htmlContent, options));
|
|
1118
1546
|
};
|
|
1119
|
-
|
|
1547
|
+
|
|
1548
|
+
export default block;
|