PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.11
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.11
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / code-block / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.11, at blocks/code-block/index.js

337 lines 18.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function () {
2 var el = wp.element.createElement;
3 var Fragment = wp.element.Fragment;
4 var useState = wp.element.useState;
5 var useEffect = wp.element.useEffect;
6 var useRef = wp.element.useRef;
7 var __ = wp.i18n.__;
8 var registerBlockType = wp.blocks.registerBlockType;
9 var InspectorControls = wp.blockEditor.InspectorControls;
10 var useBlockProps = wp.blockEditor.useBlockProps;
11 var PanelBody = wp.components.PanelBody;
12 var Button = wp.components.Button;
13 var ToggleControl = wp.components.ToggleControl;
14 var RangeControl = wp.components.RangeControl;
15 var SelectControl = wp.components.SelectControl;
16 var TextControl = wp.components.TextControl;
17 var TextareaControl = wp.components.TextareaControl;
18 var ColorPicker = wp.components.ColorPicker;
19 var Popover = wp.components.Popover;
20
21 function getTypographyControl() { return (window.bkbgTypographyControl || function () { return null; }); }
22 function _tv() { var fn = window.bkbgTypoCssVars; return fn ? fn.apply(null, arguments) : {}; }
23
24 /* ── Language map ───────────────────────────────────────────────────── */
25 var LANGUAGES = [
26 { label: 'JavaScript', value: 'javascript' },
27 { label: 'TypeScript', value: 'typescript' },
28 { label: 'JSX / TSX', value: 'jsx' },
29 { label: 'HTML', value: 'html' },
30 { label: 'CSS', value: 'css' },
31 { label: 'SCSS / Sass', value: 'scss' },
32 { label: 'PHP', value: 'php' },
33 { label: 'Python', value: 'python' },
34 { label: 'JSON', value: 'json' },
35 { label: 'Bash / Shell',value: 'bash' },
36 { label: 'SQL', value: 'sql' },
37 { label: 'Go', value: 'go' },
38 { label: 'Rust', value: 'rust' },
39 { label: 'Ruby', value: 'ruby' },
40 { label: 'Java', value: 'java' },
41 { label: 'C / C++', value: 'c' },
42 { label: 'C#', value: 'csharp' },
43 { label: 'Swift', value: 'swift' },
44 { label: 'Kotlin', value: 'kotlin' },
45 { label: 'YAML', value: 'yaml' },
46 { label: 'XML', value: 'xml' },
47 { label: 'Markdown', value: 'markdown' },
48 { label: 'Plain Text', value: 'plaintext' }
49 ];
50
51 /* ── CSS vars ────────────────────────────────────────────────────────── */
52 function buildWrapStyle(a) {
53 var style = {
54 '--bkbg-cb-font-size' : a.fontSize + 'px',
55 '--bkbg-cb-line-height': (a.lineHeight / 100).toFixed(2),
56 '--bkbg-cb-radius' : a.borderRadius + 'px'
57 };
58 if (a.maxHeight > 0) style['--bkbg-cb-max-height'] = a.maxHeight + 'px';
59 if (a.bgColor) style['--bkbg-cb-bg'] = a.bgColor;
60 if (a.textColor) style['--bkbg-cb-text'] = a.textColor;
61 if (a.accentColor) style['--bkbg-cb-accent'] = a.accentColor;
62 if (a.headerBg) style['--bkbg-cb-header-bg'] = a.headerBg;
63 Object.assign(style, _tv(a.typoCode, '--bkbg-cb-cd'));
64 return style;
65 }
66
67 /* ── Color picker ────────────────────────────────────────────────────── */
68 function renderColorControl(key, label, value, onChange, openKey, setOpenKey) {
69 var isOpen = openKey === key;
70 return el('div', { key: key, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0', gap: '8px' } },
71 el('span', { style: { fontSize: '12px', color: '#1e1e1e', flex: 1, lineHeight: 1.4 } }, label),
72 el('div', { style: { position: 'relative', flexShrink: 0 } },
73 el('button', {
74 type: 'button', title: value || 'default',
75 onClick: function () { setOpenKey(isOpen ? null : key); },
76 style: { width: '28px', height: '28px', borderRadius: '4px', border: isOpen ? '2px solid #007cba' : '2px solid #ddd', cursor: 'pointer', padding: 0, background: value || '#cccccc' }
77 }),
78 value && el('button', {
79 type: 'button',
80 title: __('Clear', 'blockenberg'),
81 onClick: function () { onChange(''); setOpenKey(null); },
82 style: { marginLeft: '4px', background: 'transparent', border: 'none', cursor: 'pointer', color: '#888', fontSize: '14px', lineHeight: 1, padding: '2px' }
83 }, '×'),
84 isOpen && el(Popover, { position: 'bottom left', onClose: function () { setOpenKey(null); } },
85 el('div', { style: { padding: '8px' } },
86 el(ColorPicker, { color: value, enableAlpha: true, onChange: onChange })
87 )
88 )
89 )
90 );
91 }
92
93 /* ── Editor line number preview helper ───────────────────────────────── */
94 function renderEditorPreview(a) {
95 var lines = (a.code || '// Enter your code here\nconsole.log("Hello, World!");').split('\n');
96 var start = a.startLine || 1;
97
98 return el('div', { className: 'bkbg-cb-wrap bkbg-cb-theme-' + a.theme, style: buildWrapStyle(a) },
99 // Header bar
100 el('div', { className: 'bkbg-cb-header' },
101 el('div', { className: 'bkbg-cb-dots' },
102 el('span', { className: 'bkbg-cb-dot bkbg-cb-dot-red' }),
103 el('span', { className: 'bkbg-cb-dot bkbg-cb-dot-yellow' }),
104 el('span', { className: 'bkbg-cb-dot bkbg-cb-dot-green' })
105 ),
106 a.fileName && el('span', { className: 'bkbg-cb-filename' }, a.fileName),
107 a.showLanguageBadge && el('span', { className: 'bkbg-cb-badge' }, a.language),
108 a.showCopyButton && el('button', { type: 'button', className: 'bkbg-cb-copy-btn', disabled: true },
109 el('svg', { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2', width: '14', height: '14' },
110 el('rect', { x: '9', y: '9', width: '13', height: '13', rx: '2', ry: '2' }),
111 el('path', { d: 'M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1' })
112 ),
113 el('span', {}, a.copyLabel || 'Copy')
114 )
115 ),
116 // Code area
117 el('div', { className: 'bkbg-cb-code-area' + (a.wordWrap ? ' bkbg-cb-wrap-text' : '') },
118 a.showLineNumbers && el('div', { className: 'bkbg-cb-line-numbers', 'aria-hidden': 'true' },
119 lines.map(function (_, i) {
120 return el('span', { key: i, className: 'bkbg-cb-ln' }, start + i);
121 })
122 ),
123 el('pre', { className: 'bkbg-cb-pre' },
124 el('code', { className: 'bkbg-cb-code language-' + a.language }, a.code || '// Enter your code here\nconsole.log("Hello, World!");')
125 )
126 )
127 );
128 }
129
130 /* ── Register ────────────────────────────────────────────────────────── */
131 registerBlockType('blockenberg/code-block', {
132 title: __('Code Block', 'blockenberg'),
133 icon: 'editor-code',
134 category: 'bkbg-dev',
135 description: __('Syntax-highlighted code with copy button, line numbers, and themes.', 'blockenberg'),
136
137 edit: function (props) {
138 var a = props.attributes;
139 var setAttributes = props.setAttributes;
140
141 var openColorKeyState = useState(null);
142 var openColorKey = openColorKeyState[0];
143 var setOpenColorKey = openColorKeyState[1];
144
145 var showEditorState = useState(false);
146 var showEditor = showEditorState[0];
147 var setShowEditor = showEditorState[1];
148
149 function cc(key, label, attrKey) {
150 return renderColorControl(key, label, a[attrKey], function (val) {
151 var upd = {}; upd[attrKey] = val; setAttributes(upd);
152 }, openColorKey, setOpenColorKey);
153 }
154
155 var blockProps = useBlockProps({
156 className: 'bkbg-cb-editor-root'
157 });
158
159 /* ── Inspector ──────────────────────────────────────────────── */
160 var inspector = el(InspectorControls, {},
161 el(PanelBody, { title: __('Code & Language', 'blockenberg'), initialOpen: true },
162 el(SelectControl, {
163 label: __('Language', 'blockenberg'), value: a.language,
164 options: LANGUAGES,
165 onChange: function (v) { setAttributes({ language: v }); }
166 }),
167 el(TextControl, {
168 label: __('File Name (optional)', 'blockenberg'),
169 value: a.fileName, placeholder: 'app.js',
170 onChange: function (v) { setAttributes({ fileName: v }); }
171 }),
172 el(TextControl, {
173 label: __('Highlight Lines (e.g. 1,3-5)', 'blockenberg'),
174 value: a.highlightLines,
175 help: __('Comma-separated line numbers or ranges.', 'blockenberg'),
176 onChange: function (v) { setAttributes({ highlightLines: v }); }
177 }),
178 el(RangeControl, {
179 label: __('Starting Line Number', 'blockenberg'), value: a.startLine, min: 1, max: 999,
180 onChange: function (v) { setAttributes({ startLine: v }); }
181 })
182 ),
183
184 el(PanelBody, { title: __('Appearance', 'blockenberg'), initialOpen: false },
185 el(SelectControl, {
186 label: __('Theme', 'blockenberg'), value: a.theme,
187 options: [
188 { label: __('Dark (Night Owl)', 'blockenberg'), value: 'dark' },
189 { label: __('Light (GitHub)', 'blockenberg'), value: 'light' },
190 { label: __('Ocean', 'blockenberg'), value: 'ocean' },
191 { label: __('Monokai', 'blockenberg'), value: 'monokai' },
192 { label: __('Custom', 'blockenberg'), value: 'custom' }
193 ],
194 onChange: function (v) { setAttributes({ theme: v }); }
195 }),
196 el(RangeControl, {
197 label: __('Border Radius (px)', 'blockenberg'), value: a.borderRadius, min: 0, max: 20,
198 onChange: function (v) { setAttributes({ borderRadius: v }); }
199 }),
200 el(RangeControl, {
201 label: __('Max Height (0 = unlimited)', 'blockenberg'), value: a.maxHeight, min: 0, max: 1200, step: 20,
202 onChange: function (v) { setAttributes({ maxHeight: v }); }
203 }),
204 el(ToggleControl, {
205 label: __('Word Wrap', 'blockenberg'), checked: a.wordWrap,
206 onChange: function (v) { setAttributes({ wordWrap: v }); }
207 })
208 ),
209
210 el(PanelBody, { title: __('Controls', 'blockenberg'), initialOpen: false },
211 el(ToggleControl, {
212 label: __('Show Line Numbers', 'blockenberg'), checked: a.showLineNumbers,
213 onChange: function (v) { setAttributes({ showLineNumbers: v }); }
214 }),
215 el(ToggleControl, {
216 label: __('Show Copy Button', 'blockenberg'), checked: a.showCopyButton,
217 onChange: function (v) { setAttributes({ showCopyButton: v }); }
218 }),
219 el(ToggleControl, {
220 label: __('Show Language Badge', 'blockenberg'), checked: a.showLanguageBadge,
221 onChange: function (v) { setAttributes({ showLanguageBadge: v }); }
222 }),
223 el(TextControl, {
224 label: __('Copy Label', 'blockenberg'), value: a.copyLabel,
225 onChange: function (v) { setAttributes({ copyLabel: v }); }
226 }),
227 el(TextControl, {
228 label: __('Copied! Label', 'blockenberg'), value: a.copiedLabel,
229 onChange: function (v) { setAttributes({ copiedLabel: v }); }
230 })
231 ),
232
233 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
234 el(getTypographyControl(), { label: __('Code Text', 'blockenberg'), value: a.typoCode, onChange: function (v) { setAttributes({ typoCode: v }); } }),
235 el(RangeControl, {
236 label: __('Font Size (px)', 'blockenberg'), value: a.fontSize, min: 10, max: 24,
237 onChange: function (v) { setAttributes({ fontSize: v }); }
238 }),
239 el(RangeControl, {
240 label: __('Line Height (%)', 'blockenberg'), value: a.lineHeight, min: 120, max: 250,
241 onChange: function (v) { setAttributes({ lineHeight: v }); }
242 })
243 ),
244 el(PanelBody, { title: __('Custom Colors', 'blockenberg'), initialOpen: false },
245 cc('bgColor', __('Background', 'blockenberg'), 'bgColor'),
246 cc('headerBg', __('Header Background', 'blockenberg'), 'headerBg'),
247 cc('textColor', __('Code Text', 'blockenberg'), 'textColor'),
248 cc('accentColor', __('Accent / Highlight', 'blockenberg'), 'accentColor')
249 )
250 );
251
252 return el(Fragment, {},
253 inspector,
254 el('div', blockProps,
255 el('div', { style: { marginBottom: '8px' } },
256 el(Button, {
257 variant: showEditor ? 'primary' : 'secondary',
258 size: 'small',
259 onClick: function () { setShowEditor(!showEditor); }
260 }, showEditor ? __('Hide Code Editor', 'blockenberg') : __('Edit Code', 'blockenberg'))
261 ),
262 showEditor && el(TextareaControl, {
263 label: __('Code', 'blockenberg'),
264 value: a.code,
265 rows: 12,
266 style: { fontFamily: 'monospace', fontSize: '13px' },
267 onChange: function (v) { setAttributes({ code: v }); }
268 }),
269 renderEditorPreview(a)
270 )
271 );
272 },
273
274 /* ── Save ───────────────────────────────────────────────────────── */
275 save: function (props) {
276 var a = props.attributes;
277 var lines = (a.code || '').split('\n');
278 var start = a.startLine || 1;
279
280 var highlighted = a.highlightLines ? (function () {
281 var map = {};
282 a.highlightLines.split(',').forEach(function (part) {
283 var range = part.trim().split('-');
284 if (range.length === 2) {
285 for (var i = parseInt(range[0], 10); i <= parseInt(range[1], 10); i++) map[i] = true;
286 } else if (range[0]) {
287 map[parseInt(range[0], 10)] = true;
288 }
289 });
290 return map;
291 })() : {};
292
293 return el('div', wp.blockEditor.useBlockProps.save({
294 className: 'bkbg-cb-wrap bkbg-cb-theme-' + a.theme,
295 style: buildWrapStyle(a)
296 }),
297 el('div', { className: 'bkbg-cb-header' },
298 el('div', { className: 'bkbg-cb-dots', 'aria-hidden': 'true' },
299 el('span', { className: 'bkbg-cb-dot bkbg-cb-dot-red' }),
300 el('span', { className: 'bkbg-cb-dot bkbg-cb-dot-yellow' }),
301 el('span', { className: 'bkbg-cb-dot bkbg-cb-dot-green' })
302 ),
303 a.fileName && el('span', { className: 'bkbg-cb-filename' }, a.fileName),
304 a.showLanguageBadge && el('span', { className: 'bkbg-cb-badge' }, a.language),
305 a.showCopyButton && el('button', {
306 type: 'button',
307 className: 'bkbg-cb-copy-btn',
308 'data-copy-label': a.copyLabel || 'Copy',
309 'data-copied-label': a.copiedLabel || 'Copied!',
310 'aria-label': a.copyLabel || 'Copy code'
311 },
312 el('svg', { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2', width: '14', height: '14', 'aria-hidden': 'true' },
313 el('rect', { x: '9', y: '9', width: '13', height: '13', rx: '2', ry: '2' }),
314 el('path', { d: 'M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1' })
315 ),
316 el('span', { className: 'bkbg-cb-copy-label' }, a.copyLabel || 'Copy')
317 )
318 ),
319 el('div', { className: 'bkbg-cb-code-area' + (a.wordWrap ? ' bkbg-cb-wrap-text' : '') },
320 a.showLineNumbers && el('div', { className: 'bkbg-cb-line-numbers', 'aria-hidden': 'true' },
321 lines.map(function (_, i) {
322 var lineNum = start + i;
323 return el('span', {
324 key: i,
325 className: 'bkbg-cb-ln' + (highlighted[lineNum] ? ' bkbg-cb-ln-highlight' : '')
326 }, lineNum);
327 })
328 ),
329 el('pre', { className: 'bkbg-cb-pre', tabIndex: '0' },
330 el('code', { className: 'bkbg-cb-code language-' + a.language }, a.code)
331 )
332 )
333 );
334 }
335 });
336 }() );
337