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 / password-generator / index.js

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

331 lines 21.5 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 useState = wp.element.useState;
4 var useEffect = wp.element.useEffect;
5 var Fragment = wp.element.Fragment;
6 var registerBlockType = wp.blocks.registerBlockType;
7 var __ = wp.i18n.__;
8 var InspectorControls = wp.blockEditor.InspectorControls;
9 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
10 var useBlockProps = wp.blockEditor.useBlockProps;
11 var PanelBody = wp.components.PanelBody;
12 var RangeControl = wp.components.RangeControl;
13 var TextControl = wp.components.TextControl;
14 var ToggleControl = wp.components.ToggleControl;
15
16 var _tc, _tv;
17 function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
18 function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
19
20 /* ── Character sets ─────────────────────────────────────────────────────── */
21 var UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
22 var LOWER = 'abcdefghijklmnopqrstuvwxyz';
23 var NUMBERS = '0123456789';
24 var SYMBOLS = '!@#$%^&*()_+-=[]{}|;:,.<>?';
25 var AMBIG = /[0Ol1I]/g;
26
27 function generatePassword(opts) {
28 var pool = '';
29 if (opts.includeUppercase !== false) pool += UPPER;
30 if (opts.includeLowercase !== false) pool += LOWER;
31 if (opts.includeNumbers !== false) pool += NUMBERS;
32 if (opts.includeSymbols !== false) pool += SYMBOLS;
33 if (opts.excludeAmbiguous) pool = pool.replace(AMBIG, '');
34 if (!pool) pool = LOWER;
35
36 var len = opts.length || 16;
37 var arr = [];
38 for (var i = 0; i < len; i++) {
39 arr.push(pool.charAt(Math.floor(Math.random() * pool.length)));
40 }
41 return arr.join('');
42 }
43
44 function getStrength(pwd, opts) {
45 var score = 0;
46 if (pwd.length >= 12) score++;
47 if (pwd.length >= 16) score++;
48 if (/[A-Z]/.test(pwd) && opts.includeUppercase !== false) score++;
49 if (/[0-9]/.test(pwd) && opts.includeNumbers !== false) score++;
50 if (/[^A-Za-z0-9]/.test(pwd) && opts.includeSymbols !== false) score++;
51 if (score <= 1) return { level: 'weak', label: 'Weak', pct: 25 };
52 if (score === 2) return { level: 'fair', label: 'Fair', pct: 50 };
53 if (score === 3) return { level: 'good', label: 'Good', pct: 75 };
54 return { level: 'strong', label: 'Strong', pct: 100 };
55 }
56
57 /* ── Preview component ────────────────────────────────────────────────── */
58 function PwdPreview(props) {
59 var a = props.attrs;
60 var accent = a.accentColor || '#6c3fb5';
61 var cRadius = (a.cardRadius || 16) + 'px';
62 var btnR = (a.btnRadius || 8) + 'px';
63
64 var lenState = useState(a.defaultLength || 16);
65 var length = lenState[0]; var setLength = lenState[1];
66 var upState = useState(a.includeUppercase !== false);
67 var upper = upState[0]; var setUpper = upState[1];
68 var loState = useState(a.includeLowercase !== false);
69 var lower = loState[0]; var setLower = loState[1];
70 var numState = useState(a.includeNumbers !== false);
71 var numbers = numState[0]; var setNumbers = numState[1];
72 var symState = useState(a.includeSymbols !== false);
73 var symbols = symState[0]; var setSymbols = symState[1];
74 var ambState = useState(a.excludeAmbiguous === true);
75 var excAmb = ambState[0]; var setExcAmb = ambState[1];
76 var pwdState = useState('');
77 var pwd = pwdState[0]; var setPwd = pwdState[1];
78 var visState = useState(false);
79 var visible = visState[0]; var setVisible = visState[1];
80 var copState = useState(false);
81 var copied = copState[0]; var setCopied = copState[1];
82
83 function generate() {
84 var p = generatePassword({ includeUppercase: upper, includeLowercase: lower, includeNumbers: numbers, includeSymbols: symbols, excludeAmbiguous: excAmb, length: length });
85 setPwd(p);
86 setCopied(false);
87 }
88
89 useEffect(function() { generate(); }, []);
90
91 var strength = pwd ? getStrength(pwd, { includeUppercase: upper, includeNumbers: numbers, includeSymbols: symbols }) : null;
92 var strengthColors = {
93 weak: a.strengthWeak || '#ef4444',
94 fair: a.strengthFair || '#f59e0b',
95 good: a.strengthGood || '#3b82f6',
96 strong: a.strengthStrong || '#10b981',
97 };
98 var strCol = strength ? strengthColors[strength.level] : '#e5e7eb';
99
100 var cardStyle = {
101 background: a.cardBg || '#ffffff',
102 borderRadius: cRadius,
103 padding: '32px',
104 boxShadow: '0 4px 24px rgba(0,0,0,0.08)',
105 maxWidth: (a.maxWidth || 560) + 'px',
106 margin: '0 auto',
107 paddingTop: (a.paddingTop || 60) + 'px',
108 paddingBottom: (a.paddingBottom|| 60) + 'px',
109 boxSizing: 'border-box',
110 };
111
112 return el('div', { className: 'bkbg-pg-card', style: cardStyle },
113 a.showTitle && el('h2', { className: 'bkbg-pg-title', style: { color: a.titleColor || '#1e1b4b' } }, a.title || __('Password Generator', 'blockenberg')),
114 a.showSubtitle && el('p', { style: { color: a.subtitleColor || '#6b7280', textAlign: 'center', marginTop: 0, marginBottom: 28 } }, a.subtitle),
115
116 /* Password display */
117 el('div', {
118 style: {
119 background: a.pwdBg || '#f5f3ff',
120 border: '1.5px solid ' + (a.pwdBorder || '#ede9fe'),
121 borderRadius: cRadius,
122 padding: '16px 20px',
123 display: 'flex',
124 alignItems: 'center',
125 gap: '12px',
126 marginBottom: '16px',
127 }
128 },
129 el('div', {
130 className: 'bkbg-pg-password' + (visible ? '' : ' blurred'),
131 style: {
132 color: a.pwdColor || '#1e1b4b'
133 }
134 }, pwd || '••••••••••••••••'),
135 a.showToggleVisible && el('button', {
136 onClick: function() { setVisible(!visible); },
137 title: visible ? __('Hide', 'blockenberg') : __('Show', 'blockenberg'),
138 style: { background: 'none', border: 'none', cursor: 'pointer', fontSize: '18px', color: '#9ca3af', padding: '4px', flexShrink: 0 }
139 }, visible ? '🙈' : '👁'),
140 a.showRefreshBtn && el('button', {
141 onClick: generate,
142 title: __('Generate new', 'blockenberg'),
143 style: { background: 'none', border: 'none', cursor: 'pointer', fontSize: '18px', color: accent, padding: '4px', flexShrink: 0 }
144 }, '')
145 ),
146
147 /* Strength bar */
148 a.showStrength && strength && el('div', { style: { marginBottom: '20px' } },
149 el('div', { style: { display: 'flex', justifyContent: 'space-between', fontSize: '12px', fontWeight: 600, marginBottom: '4px', color: strCol } },
150 el('span', null, __('Strength', 'blockenberg')),
151 el('span', null, strength.label)
152 ),
153 el('div', { style: { height: '6px', borderRadius: '99px', background: '#e5e7eb', overflow: 'hidden' } },
154 el('div', { style: { height: '100%', borderRadius: '99px', width: strength.pct + '%', background: strCol, transition: 'width 0.4s ease, background 0.3s' } })
155 )
156 ),
157
158 /* Length slider */
159 a.showLength && el('div', { style: { marginBottom: '20px' } },
160 el('div', { style: { display: 'flex', justifyContent: 'space-between', fontSize: '13px', fontWeight: 600, color: a.labelColor || '#374151', marginBottom: '6px' } },
161 el('span', null, __('Length', 'blockenberg')),
162 el('span', { style: { color: accent, fontWeight: 700 } }, length)
163 ),
164 el('input', {
165 type: 'range',
166 value: length,
167 min: a.minLength || 6,
168 max: a.maxLength || 64,
169 onChange: function(e) { setLength(Number(e.target.value)); generate(); },
170 style: { width: '100%', accentColor: accent, cursor: 'pointer' }
171 })
172 ),
173
174 /* Toggle options */
175 el('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px 16px', marginBottom: '24px' } },
176 ['uppercase', 'lowercase', 'numbers', 'symbols'].map(function(type) {
177 var checked = type === 'uppercase' ? upper : type === 'lowercase' ? lower : type === 'numbers' ? numbers : symbols;
178 var setter = type === 'uppercase' ? setUpper : type === 'lowercase' ? setLower : type === 'numbers' ? setNumbers : setSymbols;
179 var label = { uppercase: __('Uppercase (A-Z)', 'blockenberg'), lowercase: __('Lowercase (a-z)', 'blockenberg'), numbers: __('Numbers (0-9)', 'blockenberg'), symbols: __('Symbols (!@#…)', 'blockenberg') }[type];
180 return el('label', { key: type, style: { display: 'flex', alignItems: 'center', gap: '8px', fontSize: '14px', color: a.labelColor || '#374151', cursor: 'pointer', userSelect: 'none' } },
181 el('input', {
182 type: 'checkbox',
183 checked: checked,
184 onChange: function(e) { setter(e.target.checked); },
185 style: { width: '16px', height: '16px', accentColor: accent, cursor: 'pointer' }
186 }),
187 label
188 );
189 }),
190 el('label', { style: { display: 'flex', alignItems: 'center', gap: '8px', fontSize: '14px', color: a.labelColor || '#374151', cursor: 'pointer', userSelect: 'none', gridColumn: '1 / -1' } },
191 el('input', {
192 type: 'checkbox',
193 checked: excAmb,
194 onChange: function(e) { setExcAmb(e.target.checked); },
195 style: { width: '16px', height: '16px', accentColor: accent, cursor: 'pointer' }
196 }),
197 __('Exclude ambiguous characters (0, O, l, 1, I)', 'blockenberg')
198 )
199 ),
200
201 /* Action buttons */
202 el('div', { style: { display: 'flex', gap: '10px' } },
203 el('button', {
204 onClick: generate,
205 style: {
206 flex: 1,
207 padding: '12px',
208 borderRadius: btnR,
209 border: 'none',
210 cursor: 'pointer',
211 fontWeight: 700,
212 fontSize: '14px',
213 background: a.genBtnBg || '#f3f4f6',
214 color: a.genBtnColor || '#374151',
215 transition: 'filter 0.15s',
216 }
217 }, a.generateLabel || __('Generate New', 'blockenberg')),
218 a.showCopyBtn && el('button', {
219 onClick: function() { if (pwd) { navigator.clipboard.writeText(pwd).then(function() { setCopied(true); setTimeout(function() { setCopied(false); }, 2000); }); } },
220 style: {
221 flex: 1,
222 padding: '12px',
223 borderRadius: btnR,
224 border: 'none',
225 cursor: 'pointer',
226 fontWeight: 700,
227 fontSize: '14px',
228 background: copied ? '#10b981' : (a.copyBtnBg || accent),
229 color: a.copyBtnColor || '#ffffff',
230 transition: 'background 0.2s',
231 }
232 }, copied ? (a.copiedLabel || __('Copied!', 'blockenberg')) : (a.copyLabel || __('Copy Password', 'blockenberg')))
233 )
234 );
235 }
236
237 registerBlockType('blockenberg/password-generator', {
238 edit: function(props) {
239 var a = props.attributes;
240 var setAttr = props.setAttributes;
241 var blockProps = useBlockProps((function() {
242 var tv = getTypoCssVars();
243 var s = {};
244 if (a.bgColor) s.background = a.bgColor;
245 Object.assign(s, tv(a.titleTypo, '--bkbg-pg-tt-'));
246 Object.assign(s, tv(a.pwdTypo, '--bkbg-pg-pw-'));
247 return { style: s };
248 })());
249
250 return el(Fragment, null,
251 el(InspectorControls, null,
252
253 el(PanelBody, { title: __('Content', 'blockenberg'), initialOpen: true },
254 el(ToggleControl, { label: __('Show Title', 'blockenberg'), checked: a.showTitle, onChange: function(v) { setAttr({ showTitle: v }); }, __nextHasNoMarginBottom: true }),
255 a.showTitle && el(TextControl, { label: __('Title', 'blockenberg'), value: a.title, onChange: function(v) { setAttr({ title: v }); } }),
256 el(ToggleControl, { label: __('Show Subtitle', 'blockenberg'), checked: a.showSubtitle, onChange: function(v) { setAttr({ showSubtitle: v }); }, __nextHasNoMarginBottom: true }),
257 a.showSubtitle && el(TextControl, { label: __('Subtitle', 'blockenberg'), value: a.subtitle, onChange: function(v) { setAttr({ subtitle: v }); } }),
258 el(TextControl, { label: __('Copy Button Label', 'blockenberg'), value: a.copyLabel, onChange: function(v) { setAttr({ copyLabel: v }); } }),
259 el(TextControl, { label: __('Copied Confirmation Label', 'blockenberg'), value: a.copiedLabel, onChange: function(v) { setAttr({ copiedLabel: v }); } }),
260 el(TextControl, { label: __('Generate Button Label', 'blockenberg'), value: a.generateLabel, onChange: function(v) { setAttr({ generateLabel: v }); } })
261 ),
262
263 el(PanelBody, { title: __('Password Options', 'blockenberg'), initialOpen: false },
264 el(RangeControl, { label: __('Default Length', 'blockenberg'), value: a.defaultLength, min: 4, max: 64, onChange: function(v) { setAttr({ defaultLength: v }); } }),
265 el(RangeControl, { label: __('Min Length', 'blockenberg'), value: a.minLength, min: 4, max: 32, onChange: function(v) { setAttr({ minLength: v }); } }),
266 el(RangeControl, { label: __('Max Length', 'blockenberg'), value: a.maxLength, min: 16, max: 128, onChange: function(v) { setAttr({ maxLength: v }); } }),
267 el(ToggleControl, { label: __('Include Uppercase (A-Z)', 'blockenberg'), checked: a.includeUppercase, onChange: function(v) { setAttr({ includeUppercase: v }); }, __nextHasNoMarginBottom: true }),
268 el(ToggleControl, { label: __('Include Lowercase (a-z)', 'blockenberg'), checked: a.includeLowercase, onChange: function(v) { setAttr({ includeLowercase: v }); }, __nextHasNoMarginBottom: true }),
269 el(ToggleControl, { label: __('Include Numbers (0-9)', 'blockenberg'), checked: a.includeNumbers, onChange: function(v) { setAttr({ includeNumbers: v }); }, __nextHasNoMarginBottom: true }),
270 el(ToggleControl, { label: __('Include Symbols (!@#…)', 'blockenberg'), checked: a.includeSymbols, onChange: function(v) { setAttr({ includeSymbols: v }); }, __nextHasNoMarginBottom: true }),
271 el(ToggleControl, { label: __('Exclude Ambiguous (0,O,l,1,I)', 'blockenberg'), checked: a.excludeAmbiguous, onChange: function(v) { setAttr({ excludeAmbiguous: v }); }, __nextHasNoMarginBottom: true })
272 ),
273
274 el(PanelBody, { title: __('Display Options', 'blockenberg'), initialOpen: false },
275 el(ToggleControl, { label: __('Show Strength Meter', 'blockenberg'), checked: a.showStrength, onChange: function(v) { setAttr({ showStrength: v }); }, __nextHasNoMarginBottom: true }),
276 el(ToggleControl, { label: __('Show Length Slider', 'blockenberg'), checked: a.showLength, onChange: function(v) { setAttr({ showLength: v }); }, __nextHasNoMarginBottom: true }),
277 el(ToggleControl, { label: __('Show Copy Button', 'blockenberg'), checked: a.showCopyBtn, onChange: function(v) { setAttr({ showCopyBtn: v }); }, __nextHasNoMarginBottom: true }),
278 el(ToggleControl, { label: __('Show Refresh Button', 'blockenberg'), checked: a.showRefreshBtn, onChange: function(v) { setAttr({ showRefreshBtn: v }); }, __nextHasNoMarginBottom: true }),
279 el(ToggleControl, { label: __('Show Visibility Toggle', 'blockenberg'), checked: a.showToggleVisible, onChange: function(v) { setAttr({ showToggleVisible: v }); }, __nextHasNoMarginBottom: true })
280 ),
281
282
283 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
284 el( getTypoControl(), { label: __('Title','blockenberg'), value: a.titleTypo, onChange: function(v){ setAttr({ titleTypo: v }); } }),
285 el( getTypoControl(), { label: __('Password','blockenberg'), value: a.pwdTypo, onChange: function(v){ setAttr({ pwdTypo: v }); } })
286 ),
287 el(PanelColorSettings, {
288 title: __('Colors', 'blockenberg'), initialOpen: false,
289 colorSettings: [
290 { label: __('Accent Color', 'blockenberg'), value: a.accentColor, onChange: function(v) { setAttr({ accentColor: v || '#6c3fb5' }); } },
291 { label: __('Copy Button Background', 'blockenberg'), value: a.copyBtnBg, onChange: function(v) { setAttr({ copyBtnBg: v || '#6c3fb5' }); } },
292 { label: __('Copy Button Text', 'blockenberg'), value: a.copyBtnColor, onChange: function(v) { setAttr({ copyBtnColor: v || '#ffffff' }); } },
293 { label: __('Generate Button Background', 'blockenberg'), value: a.genBtnBg,onChange: function(v) { setAttr({ genBtnBg: v || '#f3f4f6' }); } },
294 { label: __('Password Field Background', 'blockenberg'), value: a.pwdBg, onChange: function(v) { setAttr({ pwdBg: v || '#f5f3ff' }); } },
295 { label: __('Password Text Color', 'blockenberg'), value: a.pwdColor, onChange: function(v) { setAttr({ pwdColor: v || '#1e1b4b' }); } },
296 { label: __('Weak Strength Color', 'blockenberg'), value: a.strengthWeak, onChange: function(v) { setAttr({ strengthWeak: v || '#ef4444' }); } },
297 { label: __('Fair Strength Color', 'blockenberg'), value: a.strengthFair, onChange: function(v) { setAttr({ strengthFair: v || '#f59e0b' }); } },
298 { label: __('Good Strength Color', 'blockenberg'), value: a.strengthGood, onChange: function(v) { setAttr({ strengthGood: v || '#3b82f6' }); } },
299 { label: __('Strong Strength Color', 'blockenberg'),value: a.strengthStrong,onChange: function(v) { setAttr({ strengthStrong: v || '#10b981' }); } },
300 { label: __('Card Background', 'blockenberg'), value: a.cardBg, onChange: function(v) { setAttr({ cardBg: v || '#ffffff' }); } },
301 { label: __('Section Background', 'blockenberg'), value: a.bgColor, onChange: function(v) { setAttr({ bgColor: v || '' }); } },
302 ]
303 }),
304
305 el(PanelBody, { title: __('Sizing', 'blockenberg'), initialOpen: false },
306 el(RangeControl, { label: __('Card Radius (px)', 'blockenberg'), value: a.cardRadius, min: 0, max: 40, onChange: function(v) { setAttr({ cardRadius: v }); } }),
307 el(RangeControl, { label: __('Button Radius (px)', 'blockenberg'), value: a.btnRadius, min: 0, max: 40, onChange: function(v) { setAttr({ btnRadius: v }); } }),
308 el(RangeControl, { label: __('Max Width (px)', 'blockenberg'), value: a.maxWidth, min: 300, max: 900, onChange: function(v) { setAttr({ maxWidth: v }); } }),
309 el(RangeControl, { label: __('Padding Top (px)', 'blockenberg'), value: a.paddingTop, min: 0, max: 160, onChange: function(v) { setAttr({ paddingTop: v }); } }),
310 el(RangeControl, { label: __('Padding Bottom (px)', 'blockenberg'), value: a.paddingBottom, min: 0, max: 160, onChange: function(v) { setAttr({ paddingBottom: v }); } })
311 )
312 ),
313
314 el('div', blockProps,
315 el(PwdPreview, { attrs: a })
316 )
317 );
318 },
319
320 save: function(props) {
321 var a = props.attributes;
322 var blockProps = wp.blockEditor.useBlockProps.save({ style: { background: a.bgColor || undefined } });
323 return el('div', blockProps,
324 el('div', { className: 'bkbg-pg-app', 'data-opts': JSON.stringify(a) },
325 el('p', { className: 'bkbg-pg-loading' }, 'Loading password generator…')
326 )
327 );
328 }
329 });
330 }() );
331