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 / morse-code-converter / frontend.js

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

236 lines 12.3 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 var _typoKeys = {
5 family:'font-family', weight:'font-weight', style:'font-style',
6 decoration:'text-decoration', transform:'text-transform',
7 sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m',
8 lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m',
9 letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m',
10 wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m'
11 };
12 function typoCssVarsForEl(el, obj, prefix) {
13 if (!obj || typeof obj !== 'object') return;
14 Object.keys(_typoKeys).forEach(function (k) {
15 var v = obj[k];
16 if (v === undefined || v === '' || v === null) return;
17 if (k === 'sizeDesktop' || k === 'sizeTablet' || k === 'sizeMobile') v = v + (obj.sizeUnit || 'px');
18 else if (k === 'lineHeightDesktop' || k === 'lineHeightTablet' || k === 'lineHeightMobile') v = v + (obj.lineHeightUnit || '');
19 else if (k === 'letterSpacingDesktop' || k === 'letterSpacingTablet' || k === 'letterSpacingMobile') v = v + (obj.letterSpacingUnit || 'px');
20 else if (k === 'wordSpacingDesktop' || k === 'wordSpacingTablet' || k === 'wordSpacingMobile') v = v + (obj.wordSpacingUnit || 'px');
21 el.style.setProperty(prefix + _typoKeys[k], String(v));
22 });
23 }
24
25 var MORSE_MAP = {
26 'A':'.-','B':'-...','C':'-.-.','D':'-..','E':'.','F':'..-.','G':'--.','H':'....','I':'..','J':'.---',
27 'K':'-.-','L':'.-..','M':'--','N':'-.','O':'---','P':'.--.','Q':'--.-','R':'.-.','S':'...','T':'-',
28 'U':'..-','V':'...-','W':'.--','X':'-..-','Y':'-.--','Z':'--..',
29 '0':'-----','1':'.----','2':'..---','3':'...--','4':'....-','5':'.....','6':'-....','7':'--...','8':'---..','9':'----.',
30 ' ':'/'
31 };
32 var REVERSE_MAP = {};
33 Object.keys(MORSE_MAP).forEach(function(k){ REVERSE_MAP[MORSE_MAP[k]] = k; });
34
35 function toMorse(text) {
36 return text.toUpperCase().split('').map(function(c){ return MORSE_MAP[c] || ''; }).join(' ').replace(/ +/g,' ').trim();
37 }
38 function fromMorse(morse) {
39 return morse.trim().split(' / ').map(function(word){
40 return word.trim().split(' ').map(function(code){ return REVERSE_MAP[code.trim()] || ''; }).join('');
41 }).join(' ');
42 }
43
44 function showToast(msg) {
45 var t = document.querySelector('.bkbg-mcc-toast');
46 if (!t) { t = document.createElement('div'); t.className = 'bkbg-mcc-toast'; document.body.appendChild(t); }
47 t.textContent = msg; t.classList.add('show');
48 setTimeout(function(){ t.classList.remove('show'); }, 1800);
49 }
50
51 // Web Audio API Morse playback
52 function playMorse(morseStr) {
53 if (!window.AudioContext && !window.webkitAudioContext) { showToast('Audio not supported'); return; }
54 var ctx = new (window.AudioContext || window.webkitAudioContext)();
55 var wpm = 15;
56 var dot = 1200 / wpm / 1000;
57 var t = ctx.currentTime + 0.1;
58 var freq = 600;
59
60 function beep(dur) {
61 var osc = ctx.createOscillator();
62 var gain = ctx.createGain();
63 osc.connect(gain); gain.connect(ctx.destination);
64 osc.frequency.value = freq;
65 gain.gain.setValueAtTime(0.3, t);
66 osc.start(t); osc.stop(t + dur);
67 t += dur;
68 }
69 function pause(dur) { t += dur; }
70
71 morseStr.split('').forEach(function(ch) {
72 if (ch === '.') { beep(dot); pause(dot); }
73 else if (ch === '-') { beep(dot * 3); pause(dot); }
74 else if (ch === ' ') { pause(dot * 2); }
75 else if (ch === '/') { pause(dot * 4); }
76 });
77 }
78
79 var CHARS = Object.keys(MORSE_MAP).filter(function(k){ return k !== ' '; });
80
81 function initBlock(app) {
82 var opts = {};
83 try { opts = JSON.parse(app.getAttribute('data-opts') || '{}'); } catch(e) {}
84
85 var accent = opts.accentColor || '#6c3fb5';
86 var outputBg = opts.outputBg || '#f5f3ff';
87 var outputBorder = opts.outputBorder || '#ede9fe';
88 var outputColor = opts.outputColor || '#3b0764';
89 var tabActiveBg = opts.tabActiveBg || accent;
90 var tabActiveClr = opts.tabActiveColor || '#fff';
91 var tabInactiveBg = opts.tabInactiveBg || '#f3f4f6';
92 var tabInactiveClr= opts.tabInactiveColor|| '#374151';
93 var refBg = opts.refBg || '#f9fafb';
94 var refBorder = opts.refBorder || '#e5e7eb';
95 var inputBorder = opts.inputBorder || '#e5e7eb';
96 var labelColor = opts.labelColor || '#374151';
97 var cardRadius = (opts.cardRadius !== undefined ? opts.cardRadius : 16) + 'px';
98 var inputRadius = (opts.inputRadius !== undefined ? opts.inputRadius : 8) + 'px';
99 var outputFS = (opts.outputFontSize || 18) + 'px';
100
101 var state = { mode: opts.defaultMode || 'encode' };
102
103 // Wrap
104 var wrap = document.createElement('div');
105 wrap.className = 'bkbg-mcc-wrap';
106 wrap.style.borderRadius = cardRadius;
107 if (opts.cardBg) wrap.style.background = opts.cardBg;
108 app.appendChild(wrap);
109
110 // Header
111 if (opts.showTitle || opts.showSubtitle) {
112 var hdr = document.createElement('div'); hdr.className = 'bkbg-mcc-header';
113 if (opts.showTitle && opts.title) {
114 var ti = document.createElement('div'); ti.className = 'bkbg-mcc-title';
115 if (opts.titleColor) ti.style.color = opts.titleColor;
116 ti.textContent = opts.title; hdr.appendChild(ti);
117 }
118 if (opts.showSubtitle && opts.subtitle) {
119 var su = document.createElement('div'); su.className = 'bkbg-mcc-subtitle';
120 if (opts.subtitleColor) su.style.color = opts.subtitleColor;
121 su.textContent = opts.subtitle; hdr.appendChild(su);
122 }
123 wrap.appendChild(hdr);
124 }
125
126 // Tabs
127 var tabWrap = document.createElement('div'); tabWrap.className = 'bkbg-mcc-tabs';
128 var tabEncode = document.createElement('button'); tabEncode.className = 'bkbg-mcc-tab'; tabEncode.type = 'button'; tabEncode.textContent = 'Text → Morse';
129 var tabDecode = document.createElement('button'); tabDecode.className = 'bkbg-mcc-tab'; tabDecode.type = 'button'; tabDecode.textContent = 'Morse → Text';
130 tabWrap.appendChild(tabEncode); tabWrap.appendChild(tabDecode); wrap.appendChild(tabWrap);
131
132 function styleTab(btn, active) {
133 btn.style.background = active ? tabActiveBg : tabInactiveBg;
134 btn.style.color = active ? tabActiveClr : tabInactiveClr;
135 btn.classList.toggle('active', active);
136 }
137
138 // Label
139 var inputLabel = document.createElement('label'); inputLabel.className = 'bkbg-mcc-label'; inputLabel.style.color = labelColor;
140 // Textarea
141 var textarea = document.createElement('textarea'); textarea.className = 'bkbg-mcc-textarea';
142 textarea.style.borderRadius = inputRadius; textarea.style.borderColor = inputBorder;
143 textarea.rows = 3;
144 var inputWrap = document.createElement('div'); inputWrap.style.marginBottom = '12px';
145 inputWrap.appendChild(inputLabel); inputWrap.appendChild(textarea); wrap.appendChild(inputWrap);
146
147 // Output
148 var outputBox = document.createElement('div'); outputBox.className = 'bkbg-mcc-output';
149 outputBox.style.background = outputBg; outputBox.style.borderColor = outputBorder; outputBox.style.borderRadius = inputRadius;
150 var outputLabel = document.createElement('div'); outputLabel.className = 'bkbg-mcc-output-label'; outputLabel.style.color = labelColor;
151 var outputText = document.createElement('div'); outputText.className = 'bkbg-mcc-output-text'; outputText.style.color = outputColor;
152 outputBox.appendChild(outputLabel); outputBox.appendChild(outputText); wrap.appendChild(outputBox);
153
154 // Buttons
155 var actionsRow = document.createElement('div'); actionsRow.className = 'bkbg-mcc-actions'; actionsRow.style.marginBottom = '20px';
156 if (opts.showCopyButton !== false) {
157 var copyBtn = document.createElement('button'); copyBtn.className = 'bkbg-mcc-btn-copy'; copyBtn.type = 'button'; copyBtn.textContent = '📋 Copy'; copyBtn.style.background = accent;
158 copyBtn.addEventListener('click', function(){
159 var val = outputText.textContent;
160 if (!val) return;
161 if (navigator.clipboard) { navigator.clipboard.writeText(val).then(function(){ showToast('Copied!'); }); }
162 else { showToast('Copy not supported'); }
163 });
164 actionsRow.appendChild(copyBtn);
165 }
166 if (opts.showPlayButton !== false) {
167 var playBtn = document.createElement('button'); playBtn.className = 'bkbg-mcc-btn-play'; playBtn.type = 'button'; playBtn.textContent = '🔊 Play Audio';
168 playBtn.addEventListener('click', function(){
169 var morse = state.mode === 'encode' ? outputText.textContent : textarea.value;
170 playMorse(morse);
171 });
172 actionsRow.appendChild(playBtn);
173 }
174 wrap.appendChild(actionsRow);
175
176 // Reference table
177 if (opts.showReference !== false) {
178 var refDetails = document.createElement('details'); refDetails.className = 'bkbg-mcc-ref';
179 var refSummary = document.createElement('summary'); refSummary.textContent = 'Morse Code Reference (A–Z, 0–9)'; refSummary.style.background = refBg;
180 var refGrid = document.createElement('div'); refGrid.className = 'bkbg-mcc-ref-grid'; refGrid.style.background = refBg;
181 CHARS.forEach(function(c){
182 var cell = document.createElement('div'); cell.className = 'bkbg-mcc-ref-cell'; cell.style.borderColor = refBorder;
183 var charEl = document.createElement('div'); charEl.className = 'bkbg-mcc-ref-char'; charEl.style.color = accent; charEl.textContent = c;
184 var codeEl = document.createElement('div'); codeEl.className = 'bkbg-mcc-ref-code'; codeEl.textContent = MORSE_MAP[c];
185 cell.appendChild(charEl); cell.appendChild(codeEl); refGrid.appendChild(cell);
186 });
187 refDetails.appendChild(refSummary); refDetails.appendChild(refGrid); wrap.appendChild(refDetails);
188 }
189
190 function updateOutput() {
191 var val = textarea.value;
192 var result;
193 if (state.mode === 'encode') {
194 result = toMorse(val);
195 outputLabel.textContent = 'Morse Code';
196 inputLabel.textContent = 'Enter Text';
197 } else {
198 result = fromMorse(val);
199 outputLabel.textContent = 'Decoded Text';
200 inputLabel.textContent = 'Enter Morse Code (use / between words)';
201 }
202 if (result) {
203 outputText.textContent = result;
204 outputText.classList.remove('empty');
205 } else {
206 outputText.textContent = 'Output will appear here…';
207 outputText.classList.add('empty');
208 }
209 }
210
211 // Set typography CSS vars on the blockProps wrapper
212 var bpWrap = app.parentNode;
213 typoCssVarsForEl(bpWrap, opts.titleTypo, '--bkbg-mcc-tt-');
214 typoCssVarsForEl(bpWrap, opts.subtitleTypo, '--bkbg-mcc-st-');
215 typoCssVarsForEl(bpWrap, opts.outputTypo, '--bkbg-mcc-ot-');
216
217 function setMode(mode) {
218 state.mode = mode;
219 var defText = opts.defaultText || 'Hello World';
220 textarea.value = mode === 'encode' ? defText : toMorse(defText);
221 styleTab(tabEncode, mode === 'encode');
222 styleTab(tabDecode, mode === 'decode');
223 updateOutput();
224 }
225
226 tabEncode.addEventListener('click', function(){ setMode('encode'); });
227 tabDecode.addEventListener('click', function(){ setMode('decode'); });
228 textarea.addEventListener('input', updateOutput);
229
230 setMode(state.mode);
231 }
232
233 function init() { document.querySelectorAll('.bkbg-mcc-app').forEach(initBlock); }
234 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); }
235 })();
236