PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
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 / meme-generator / frontend.js

frontend.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/meme-generator/frontend.js

208 lines 8.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 'use strict';
3
4 function drawMeme(canvas, img, topText, bottomText, opts) {
5 var ctx = canvas.getContext('2d');
6 var W = canvas.width, H = canvas.height;
7
8 // Background
9 ctx.fillStyle = opts.canvasBg || '#cccccc';
10 ctx.fillRect(0, 0, W, H);
11
12 // Image
13 if (img && img.complete && img.naturalWidth > 0) {
14 // Cover fit
15 var iw = img.naturalWidth, ih = img.naturalHeight;
16 var scale = Math.max(W / iw, H / ih);
17 var dw = iw * scale, dh = ih * scale;
18 ctx.drawImage(img, (W - dw) / 2, (H - dh) / 2, dw, dh);
19 }
20
21 // Text settings
22 var fontSize = opts.memeFontSize || 52;
23 var font = opts.memeFont || 'Impact';
24 var fillColor = opts.memeTextColor || '#ffffff';
25 var stroke = opts.memeStrokeColor|| '#000000';
26 var strokeW = (opts.memeStrokeWidth || 3) * (W / 560);
27
28 ctx.font = 'bold ' + fontSize + 'px ' + font + ', Arial Black, sans-serif';
29 ctx.textAlign = 'center';
30 ctx.textBaseline = 'top';
31 ctx.lineJoin = 'round';
32 ctx.miterLimit = 2;
33
34 function drawText(text, y) {
35 if (!text) return;
36 text = text.toUpperCase();
37 ctx.strokeStyle = stroke;
38 ctx.lineWidth = strokeW;
39 ctx.strokeText(text, W / 2, y, W - 24);
40 ctx.fillStyle = fillColor;
41 ctx.fillText(text, W / 2, y, W - 24);
42 }
43
44 var pad = Math.round(fontSize * 0.2);
45 drawText(topText, pad);
46
47 ctx.textBaseline = 'bottom';
48 drawText(bottomText, H - pad);
49 }
50
51 function initBlock(root) {
52 var optsRaw = root.getAttribute('data-opts');
53 var opts;
54 try { opts = JSON.parse(optsRaw); } catch (e) { opts = {}; }
55
56 var _typoKeys = { family:'font-family', weight:'font-weight', style:'font-style', decoration:'text-decoration', transform:'text-transform', sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m', lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m', letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m', wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m' };
57 function typoCssVarsForEl(el, typo, prefix) {
58 if (!typo || typeof typo !== 'object') return;
59 Object.keys(_typoKeys).forEach(function (k) {
60 if (typo[k] !== undefined && typo[k] !== '') el.style.setProperty(prefix + _typoKeys[k], typo[k]);
61 });
62 }
63
64 var accent = opts.accentColor || '#6366f1';
65 var titleColor = opts.titleColor || '#1e1b4b';
66 var sectionBg = opts.sectionBg || '';
67
68 if (sectionBg) root.style.background = sectionBg;
69 root.style.setProperty('--bkbg-mme-accent', accent);
70
71 typoCssVarsForEl(root, opts.titleTypo, '--bkbg-mme-tt-');
72 typoCssVarsForEl(root, opts.subtitleTypo, '--bkbg-mme-st-');
73
74 // Style title/subtitle
75 var titleEl = root.querySelector('.bkbg-mme-title');
76 if (titleEl) { titleEl.style.color = titleColor; }
77 var subEl = root.querySelector('.bkbg-mme-subtitle');
78 if (subEl) { subEl.style.color = titleColor; }
79
80 var W = opts.canvasWidth || 560;
81 var H = opts.canvasHeight || 420;
82
83 // ---- Canvas ----
84 var canvasWrap = document.createElement('div');
85 canvasWrap.className = 'bkbg-mme-canvas-wrap';
86
87 var canvas = document.createElement('canvas');
88 canvas.className = 'bkbg-mme-canvas';
89 canvas.width = W;
90 canvas.height = H;
91 canvasWrap.appendChild(canvas);
92 root.appendChild(canvasWrap);
93
94 // ---- Controls ----
95 var ctrlDiv = document.createElement('div');
96 ctrlDiv.className = 'bkbg-mme-controls';
97 root.appendChild(ctrlDiv);
98
99 function makeRow(labelText, inputEl) {
100 var row = document.createElement('div');
101 row.className = 'bkbg-mme-row';
102 var lbl = document.createElement('label');
103 lbl.className = 'bkbg-mme-label';
104 lbl.style.color = titleColor;
105 lbl.textContent = labelText;
106 row.appendChild(lbl);
107 row.appendChild(inputEl);
108 ctrlDiv.appendChild(row);
109 }
110
111 function makeInput(placeholder, val) {
112 var inp = document.createElement('input');
113 inp.type = 'text';
114 inp.className = 'bkbg-mme-input';
115 inp.placeholder = placeholder;
116 inp.value = val || '';
117 inp.style.background = opts.canvasBg || '#f3f4f6';
118 inp.style.color = '#1e1b4b';
119 return inp;
120 }
121
122 var topInput = makeInput('Top text…', opts.defaultTopText || 'TOP TEXT');
123 var bottomInput = makeInput('Bottom text…', opts.defaultBottomText || 'BOTTOM TEXT');
124 var urlInput = makeInput('Image URL (https://…)', opts.defaultImageUrl || '');
125
126 makeRow('Top Text', topInput);
127 makeRow('Bottom Text', bottomInput);
128 makeRow('Image URL', urlInput);
129
130 // ---- Actions ----
131 var actions = document.createElement('div');
132 actions.className = 'bkbg-mme-actions';
133 root.appendChild(actions);
134
135 if (opts.showDownload !== false) {
136 var dlBtn = document.createElement('button');
137 dlBtn.className = 'bkbg-mme-dl-btn';
138 dlBtn.style.background = '#22c55e';
139 dlBtn.style.color = '#fff';
140 dlBtn.textContent = '⬇️ Download PNG';
141 actions.appendChild(dlBtn);
142
143 dlBtn.addEventListener('click', function () {
144 canvas.toBlob(function (blob) {
145 if (!blob) { alert('Could not export — cross-origin image may be blocking download.'); return; }
146 var url = URL.createObjectURL(blob);
147 var a = document.createElement('a');
148 a.href = url;
149 a.download = 'meme.png';
150 a.click();
151 URL.revokeObjectURL(url);
152 });
153 });
154 }
155
156 var resetBtn = document.createElement('button');
157 resetBtn.className = 'bkbg-mme-reset-btn';
158 resetBtn.style.background = '#e5e7eb';
159 resetBtn.style.color = '#374151';
160 resetBtn.textContent = '↺ Reset';
161 actions.appendChild(resetBtn);
162
163 // ---- Image management ----
164 var img = null;
165 var currentUrl = '';
166
167 function loadImage(url) {
168 if (!url) {
169 img = null;
170 redraw();
171 return;
172 }
173 if (url === currentUrl && img) return;
174 currentUrl = url;
175 var newImg = new Image();
176 newImg.crossOrigin = 'anonymous';
177 newImg.onload = function () { img = newImg; redraw(); };
178 newImg.onerror = function () { img = null; redraw(); };
179 newImg.src = url;
180 }
181
182 function redraw() {
183 drawMeme(canvas, img, topInput.value, bottomInput.value, opts);
184 }
185
186 topInput.addEventListener('input', redraw);
187 bottomInput.addEventListener('input', redraw);
188 urlInput.addEventListener('change', function () { loadImage(urlInput.value.trim()); });
189 urlInput.addEventListener('keydown', function (e) { if (e.key === 'Enter') loadImage(urlInput.value.trim()); });
190
191 resetBtn.addEventListener('click', function () {
192 topInput.value = opts.defaultTopText || 'TOP TEXT';
193 bottomInput.value = opts.defaultBottomText || 'BOTTOM TEXT';
194 urlInput.value = opts.defaultImageUrl || '';
195 loadImage(urlInput.value.trim());
196 redraw();
197 });
198
199 // Initial load
200 loadImage((opts.defaultImageUrl || '').trim());
201 redraw();
202 }
203
204 document.querySelectorAll('.bkbg-mme-app').forEach(function (root) {
205 initBlock(root);
206 });
207 })();
208