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 / word-counter / frontend.js

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

194 lines 10.1 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 analyzeText(text, readingWPM, speakingWPM) {
5 var words = text.trim() === '' ? 0 : text.trim().split(/\s+/).length;
6 var chars = text.length;
7 var charsNoSp = text.replace(/\s/g, '').length;
8 var sentences = text.trim() === '' ? 0 : (text.match(/[^.!?]+[.!?]+/g) || []).length;
9 var paras = text.trim() === '' ? 0 : (text.trim().split(/\n\s*\n+/).filter(function(p) { return p.trim() !== ''; }).length || (text.trim() !== '' ? 1 : 0));
10 var readSec = words > 0 ? Math.ceil((words / readingWPM) * 60) : 0;
11 var speakSec = words > 0 ? Math.ceil((words / speakingWPM) * 60) : 0;
12 return { words: words, chars: chars, charsNoSp: charsNoSp, sentences: sentences, paragraphs: paras, readSec: readSec, speakSec: speakSec };
13 }
14
15 function fmtTime(secs) {
16 if (secs < 60) return secs + 's';
17 var m = Math.floor(secs / 60);
18 var s = secs % 60;
19 return m + 'm' + (s ? ' ' + s + 's' : '');
20 }
21
22 function buildApp(app) {
23 var opts = {};
24 try { opts = JSON.parse(app.getAttribute('data-opts') || '{}'); } catch (e) {}
25
26 var o = opts;
27 var rWPM = parseInt(o.readingWPM) || 238;
28 var sWPM = parseInt(o.speakingWPM) || 130;
29 var radius = (o.cardRadius || 16) + 'px';
30 var inpRad = (o.inputRadius || 8) + 'px';
31 var accentC = o.accentColor || '#6c3fb5';
32 var labelC = o.labelColor || '#374151';
33 var wrdC = o.wordCountColor || '#6c3fb5';
34 var charC = o.charCountColor || '#3b82f6';
35 var sentC = o.sentenceColor || '#10b981';
36 var paraC = o.paragraphColor || '#f59e0b';
37 var readC = o.readingColor || '#8b5cf6';
38 var speakC = o.speakingColor || '#ec4899';
39 var barFillC = o.limitBarFill || '#6c3fb5';
40 var barOverC = o.limitBarOver || '#ef4444';
41 var barBgC = o.limitBarBg || '#e5e7eb';
42 var statBg = o.statCardBg || '#f5f3ff';
43 var statBdr = o.statCardBorder || '#ede9fe';
44 var txtaBg = o.textareaBg || '#f9fafb';
45 var txtaBdr = o.textareaBorder || '#e5e7eb';
46 var valSz = o.statValueSize || 36;
47 var charLimit = parseInt(o.charLimit) || 500;
48
49 app.innerHTML = '';
50 app.style.fontFamily = 'inherit';
51 app.style.boxSizing = 'border-box';
52
53 // Section wrapper
54 var section = document.createElement('div');
55 section.style.paddingTop = (o.paddingTop || 60) + 'px';
56 section.style.paddingBottom = (o.paddingBottom || 60) + 'px';
57 section.style.background = o.sectionBg || '';
58 app.appendChild(section);
59
60 var card = document.createElement('div');
61 card.style.cssText = 'background:' + (o.cardBg || '#fff') + ';border-radius:' + radius + ';padding:36px 32px;max-width:' + (o.maxWidth || 680) + 'px;margin:0 auto;box-shadow:0 4px 24px rgba(0,0,0,.09);box-sizing:border-box;';
62 section.appendChild(card);
63
64 // Title / subtitle
65 if (o.showTitle || o.showSubtitle) {
66 var hdr = document.createElement('div');
67 hdr.style.marginBottom = '20px';
68 if (o.showTitle) {
69 var ttl = document.createElement('div');
70 ttl.className = 'bkbg-wrd-title';
71 ttl.textContent = o.title || 'Word Counter';
72 ttl.style.color = o.titleColor || '#1e1b4b';
73 hdr.appendChild(ttl);
74 }
75 if (o.showSubtitle && o.subtitle) {
76 var sub = document.createElement('div');
77 sub.className = 'bkbg-wrd-subtitle';
78 sub.textContent = o.subtitle;
79 sub.style.color = o.subtitleColor || '#6b7280';
80 hdr.appendChild(sub);
81 }
82 card.appendChild(hdr);
83 }
84
85 // Textarea
86 var textarea = document.createElement('textarea');
87 textarea.className = 'bkbg-wrd-textarea';
88 textarea.placeholder = o.placeholder || 'Start typing or paste your text here\u2026';
89 textarea.value = o.defaultText || '';
90 textarea.style.cssText = 'width:100%;height:' + (o.textareaHeight || 200) + 'px;padding:14px 16px;border-radius:' + inpRad + ';border:2px solid ' + txtaBdr + ';background:' + txtaBg + ';font-size:15px;line-height:1.6;resize:vertical;outline:none;box-sizing:border-box;margin-bottom:16px;font-family:inherit;transition:border-color .2s;';
91 textarea.addEventListener('focus', function () { textarea.style.borderColor = accentC; textarea.style.boxShadow = '0 0 0 3px rgba(108,63,181,.15)'; });
92 textarea.addEventListener('blur', function () {
93 var over = o.showCharLimit && textarea.value.length > charLimit;
94 textarea.style.borderColor = over ? barOverC : txtaBdr;
95 textarea.style.boxShadow = '';
96 });
97 textarea.addEventListener('input', update);
98 card.appendChild(textarea);
99
100 // Char limit bar
101 var limitSection = null;
102 var limitLabel = null;
103 var limitFill = null;
104 if (o.showCharLimit) {
105 limitSection = document.createElement('div');
106 limitSection.style.marginBottom = '16px';
107 var limitRow = document.createElement('div');
108 limitRow.style.cssText = 'display:flex;justify-content:space-between;font-size:12px;color:' + labelC + ';margin-bottom:5px;';
109 var limitTitle = document.createElement('span'); limitTitle.textContent = 'Character Limit';
110 limitLabel = document.createElement('span');
111 limitRow.appendChild(limitTitle); limitRow.appendChild(limitLabel);
112 limitSection.appendChild(limitRow);
113 var limitTrack = document.createElement('div');
114 limitTrack.className = 'bkbg-wrd-limit-bar-track';
115 limitTrack.style.cssText = 'height:8px;border-radius:100px;background:' + barBgC + ';overflow:hidden;';
116 limitFill = document.createElement('div');
117 limitFill.className = 'bkbg-wrd-limit-bar-fill';
118 limitFill.style.cssText = 'height:100%;width:0%;background:' + barFillC + ';border-radius:100px;transition:width .3s,background .3s;';
119 limitTrack.appendChild(limitFill);
120 limitSection.appendChild(limitTrack);
121 card.appendChild(limitSection);
122 }
123
124 // Stats grid
125 var statsGrid = document.createElement('div');
126 statsGrid.className = 'bkbg-wrd-stats-grid';
127 statsGrid.style.cssText = 'display:grid;grid-template-columns:repeat(auto-fill,minmax(130px,1fr));gap:10px;';
128 card.appendChild(statsGrid);
129
130 // Stat definitions
131 var statDefs = [
132 { key: 'words', label: 'Words', val: 0, color: wrdC, show: true },
133 { key: 'chars', label: 'Characters', val: 0, color: charC, show: true },
134 { key: 'charsNoSp', label: 'Chars (no spaces)', val: 0, color: charC, show: !!o.showCharNoSpaces },
135 { key: 'sentences', label: 'Sentences', val: 0, color: sentC, show: !!o.showSentences },
136 { key: 'paragraphs', label: 'Paragraphs', val: 0, color: paraC, show: !!o.showParagraphs },
137 { key: 'readTime', label: 'Reading Time', val: 0, color: readC, show: !!o.showReadingTime },
138 { key: 'speakTime', label: 'Speaking Time', val: 0, color: speakC, show: !!o.showSpeakingTime }
139 ].filter(function(s) { return s.show; });
140
141 var statEls = {};
142 statDefs.forEach(function (s) {
143 var card2 = document.createElement('div');
144 card2.className = 'bkbg-wrd-stat-card';
145 card2.style.cssText = 'background:' + statBg + ';border:1.5px solid ' + statBdr + ';border-radius:' + radius + ';padding:16px 14px;text-align:center;transition:transform .18s,box-shadow .18s;';
146 var valEl = document.createElement('div');
147 valEl.className = 'bkbg-wrd-stat-value';
148 valEl.textContent = '0';
149 valEl.style.cssText = 'font-size:' + valSz + 'px;font-weight:800;color:' + s.color + ';line-height:1.1;';
150 var lblEl = document.createElement('div');
151 lblEl.textContent = s.label;
152 lblEl.style.cssText = 'font-size:12px;color:' + labelC + ';margin-top:4px;font-weight:600;';
153 card2.appendChild(valEl);
154 card2.appendChild(lblEl);
155 statsGrid.appendChild(card2);
156 statEls[s.key] = valEl;
157 });
158
159 function update() {
160 var text = textarea.value;
161 var stats = analyzeText(text, rWPM, sWPM);
162 var over = o.showCharLimit && stats.chars > charLimit;
163
164 // Update textarea border
165 if (document.activeElement !== textarea) {
166 textarea.style.borderColor = over ? barOverC : txtaBdr;
167 }
168
169 // Update stat cards
170 if (statEls.words) statEls.words.textContent = stats.words;
171 if (statEls.chars) statEls.chars.textContent = stats.chars;
172 if (statEls.charsNoSp) statEls.charsNoSp.textContent = stats.charsNoSp;
173 if (statEls.sentences) statEls.sentences.textContent = stats.sentences;
174 if (statEls.paragraphs) statEls.paragraphs.textContent= stats.paragraphs;
175 if (statEls.readTime) statEls.readTime.textContent = fmtTime(stats.readSec);
176 if (statEls.speakTime) statEls.speakTime.textContent = fmtTime(stats.speakSec);
177
178 // Update limit bar
179 if (o.showCharLimit && limitFill && limitLabel) {
180 var pct = Math.min(100, (stats.chars / charLimit) * 100);
181 limitFill.style.width = pct.toFixed(1) + '%';
182 limitFill.style.background = over ? barOverC : barFillC;
183 limitLabel.textContent = stats.chars + ' / ' + charLimit;
184 limitLabel.style.color = over ? barOverC : labelC;
185 limitLabel.style.fontWeight= over ? '700' : '400';
186 }
187 }
188
189 update();
190 }
191
192 document.querySelectorAll('.bkbg-wrd-app').forEach(buildApp);
193 })();
194