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 / terminal-mockup / frontend.js

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

124 lines 4.8 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 splitGraphemes(str) {
5 try {
6 if (window.Intl && Intl.Segmenter) {
7 var seg = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
8 return Array.from(seg.segment(str), function (s) { return s.segment; });
9 }
10 } catch (e) {}
11 return Array.from(str);
12 }
13
14 // WordPress's emoji script (twemoji) may replace some symbols (e.g. ✔) with <img>.
15 // For Terminal Mockup we want to render text as text. U+FE0E forces text presentation.
16 function forceTextPresentation(str) {
17 if (!str) return str;
18 return String(str).replace(/\u2714(?![\uFE0E\uFE0F])/g, '\u2714\uFE0E');
19 }
20
21 function initTerminal(el) {
22 var typewriterOn = el.dataset.typewriter === '1';
23 if (!typewriterOn) return;
24
25 var speed = parseInt(el.dataset.speed, 10) || 35;
26 var showCursor = el.dataset.cursor === '1';
27 var lines = Array.from(el.querySelectorAll('.bkbg-term-line:not(.bkbg-term-line--blank), .bkbg-terminal-line:not(.bkbg-terminal-line--blank)'));
28 var blanks = Array.from(el.querySelectorAll('.bkbg-term-line--blank, .bkbg-terminal-line--blank'));
29
30 /* Hide all lines initially */
31 lines.forEach(function (line) { line.classList.add('bkbg-tw-hidden'); });
32 blanks.forEach(function (b) { b.style.visibility = 'hidden'; });
33
34 var allNodes = Array.from(el.querySelectorAll('.bkbg-term-line, .bkbg-terminal-line'));
35 var cursor = showCursor ? (el.querySelector('.bkbg-term-cursor') || el.querySelector('.bkbg-terminal-cursor')) : null;
36 if (showCursor && !cursor) {
37 cursor = document.createElement('span');
38 cursor.className = 'bkbg-term-cursor';
39 }
40
41 function typeLine(lineEl, cb) {
42 lineEl.classList.remove('bkbg-tw-hidden');
43 lineEl.classList.add('bkbg-tw-typing');
44 var textSpan = lineEl.querySelector('.bkbg-term-text') || lineEl.querySelector('.bkbg-terminal-text');
45 if (!textSpan) {
46 lineEl.classList.remove('bkbg-tw-typing');
47 cb();
48 return;
49 }
50
51 var fullText = textSpan.getAttribute('data-bkbg-fulltext');
52 if (fullText === null) {
53 fullText = textSpan.textContent;
54 textSpan.setAttribute('data-bkbg-fulltext', fullText);
55 }
56
57 // Prevent ✔ -> <img class="emoji"> conversion.
58 fullText = forceTextPresentation(fullText);
59
60 var chars = splitGraphemes(fullText);
61
62 textSpan.textContent = '';
63 if (cursor) {
64 if (cursor.parentNode) cursor.parentNode.removeChild(cursor);
65 try {
66 var col = window.getComputedStyle(textSpan).color;
67 cursor.style.background = col;
68 cursor.style.color = col;
69 } catch (e) {}
70 lineEl.appendChild(cursor);
71 }
72
73 var i = 0;
74 function tick() {
75 if (i < chars.length) {
76 textSpan.textContent += chars[i];
77 i++;
78 setTimeout(tick, speed + Math.random() * 12);
79 } else {
80 lineEl.classList.remove('bkbg-tw-typing');
81 // Ensure the final rendered text is exact (no missing glyphs).
82 textSpan.textContent = fullText;
83 if (cursor && lineEl !== allNodes[allNodes.length - 1]) lineEl.removeChild(cursor);
84 cb();
85 }
86 }
87 tick();
88 }
89
90 function playNode(idx) {
91 if (idx >= allNodes.length) return;
92 var node = allNodes[idx];
93 if (node.classList.contains('bkbg-term-line--blank') || node.classList.contains('bkbg-terminal-line--blank')) {
94 node.style.visibility = '';
95 setTimeout(function () { playNode(idx + 1); }, speed * 2);
96 return;
97 }
98 typeLine(node, function () {
99 setTimeout(function () { playNode(idx + 1); }, speed * 3);
100 });
101 }
102
103 playNode(0);
104 }
105
106 function observe(el) {
107 if ('IntersectionObserver' in window) {
108 var io = new IntersectionObserver(function (entries) {
109 entries.forEach(function (entry) {
110 if (entry.isIntersecting) {
111 io.unobserve(entry.target);
112 initTerminal(entry.target);
113 }
114 });
115 }, { threshold: 0.2 });
116 io.observe(el);
117 } else {
118 initTerminal(el);
119 }
120 }
121
122 document.querySelectorAll('.bkbg-terminal, .bkbg-terminal-window').forEach(observe);
123 }());
124