PluginProbe
Code Block Pro – Beautiful Syntax Highlighting / 1.18.0
Code Block Pro – Beautiful Syntax Highlighting v1.18.0
1.27.1 1.27.2 1.27.3 1.27.4 1.27.5 1.27.6 1.27.7 1.28.0 1.3.0 1.4.0 1.5.0 1.5.1 1.5.2 1.6.0 1.7.0 1.8.0 1.9.0 1.9.1 1.9.2 1.9.3 trunk 1.1.0 1.10.0 1.11.0 1.11.1 All 63 releases
code-block-pro / src / front / front.js

front.js in Code Block Pro – Beautiful Syntax Highlighting 1.18.0, at src/front/front.js

190 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import copy from 'copy-to-clipboard';
2
3 const containerClass = '.wp-block-kevinbatdorf-code-block-pro';
4
5 const handleCopyButton = () => {
6 const buttons = Array.from(
7 document.querySelectorAll(
8 '.code-block-pro-copy-button:not(.cbp-cb-loaded)',
9 ),
10 );
11 buttons.forEach((button) => {
12 button.classList.add('cbp-cb-loaded');
13 // Setting it to block here lets users deactivate the plugin safely
14 button.style.display = 'block';
15 const handler = (event) => {
16 const { type, key, target } = event;
17 // if keydown event, make sure it's enter or space
18 if (type === 'keydown' && !['Enter', ' '].includes(key)) return;
19 event.preventDefault();
20 const b = target?.closest('span');
21 const code = b?.dataset?.encoded
22 ? decodeURIComponent(decodeURIComponent(b?.dataset?.code))
23 : b?.dataset?.code;
24 copy(code ?? '', {
25 format: 'text/plain',
26 });
27 b.classList.add('cbp-copying');
28 setTimeout(() => {
29 b.classList.remove('cbp-copying');
30 }, 2000);
31 };
32 ['click', 'keydown'].forEach((evt) =>
33 button.addEventListener(evt, handler),
34 );
35 });
36 };
37
38 const handleHighlighter = () => {
39 const codeBlocks = Array.from(
40 document.querySelectorAll(`${containerClass}:not(.cbp-hl-loaded)`),
41 );
42
43 codeBlocks.forEach((codeBlock) => {
44 codeBlock.classList.add('cbp-hl-loaded');
45 // Search for highlights
46 const highlighters = new Set(
47 codeBlock.querySelectorAll('.cbp-line-highlight'),
48 );
49 // If the codeblock has .cbp-highlight-hover, then get all lines
50 if (codeBlock.classList.contains('cbp-highlight-hover')) {
51 codeBlock
52 .querySelectorAll('span.line')
53 .forEach((line) => console.log(line) || highlighters.add(line));
54 }
55
56 if (!highlighters.size) return;
57
58 // We need to track the block width so we can adjust the
59 // highlighter width in case of overflow
60 const resizeObserver = new ResizeObserver((entries) => {
61 entries.forEach((entry) => {
62 // get width of inner code block
63 codeBlock.style.setProperty('--cbp-block-width', '0');
64 const codeWidth =
65 entry.target.querySelector('code').offsetWidth;
66 const computed =
67 codeWidth + 16 === entry.target.scrollWidth
68 ? codeWidth + 16
69 : entry.target.scrollWidth + 16;
70 codeBlock.style.setProperty(
71 '--cbp-block-width',
72 `${computed}px`,
73 );
74 });
75 });
76 resizeObserver.observe(codeBlock);
77
78 console.log(highlighters);
79
80 // add the highlighter
81 highlighters.forEach((highlighter) => {
82 highlighter.insertAdjacentHTML(
83 'beforeend',
84 '<span aria-hidden="true" class="cbp-line-highlighter"></span>',
85 );
86 });
87 });
88 };
89
90 const handleFontLoading = () => {
91 if (!window.codeBlockPro?.pluginUrl) return;
92 const elements = Array.from(
93 document.querySelectorAll(
94 '[data-code-block-pro-font-family]:not(.cbp-ff-loaded)',
95 ) || [],
96 );
97 elements.forEach((e) => e.classList.add('cbp-ff-loaded'));
98 const fontsToLoad = new Set(
99 elements.map((f) => f.dataset.codeBlockProFontFamily).filter(Boolean),
100 );
101 [...fontsToLoad].forEach(async (fontName) => {
102 const font = new FontFace(
103 fontName,
104 `url(${window.codeBlockPro.pluginUrl}/build/fonts/${fontName}.woff2)`,
105 );
106 await font.load();
107 document.fonts.add(font);
108 });
109 };
110
111 const handleSeeMore = () => {
112 const seeMoreLines = Array.from(
113 document.querySelectorAll(
114 `${containerClass}:not(.cbp-see-more-loaded) .cbp-see-more-line`,
115 ),
116 );
117 seeMoreLines.forEach((line) => {
118 const currentContainer = line.closest(containerClass);
119 currentContainer.classList.add('cbp-see-more-loaded');
120 const pre = line.closest('pre');
121 const initialHeight = pre.offsetHeight;
122 let animationSpeed = 0;
123
124 if (line.classList.contains('cbp-see-more-transition')) {
125 const lineCount = pre.querySelectorAll('code > *').length;
126 const linesBeforeCurrent = Array.from(
127 line.closest('code').children,
128 ).filter((l) => l.offsetTop < line.offsetTop)?.length;
129 animationSpeed = 0.5 + (lineCount - linesBeforeCurrent) * 0.01;
130 pre.style.transition = `max-height ${animationSpeed}s ease-out`;
131 }
132
133 // if the first child it a span then get the height of that span
134 const headerHeight =
135 currentContainer.children[0].tagName === 'SPAN'
136 ? currentContainer.children[0].offsetHeight
137 : 0;
138 const lineHeight = parseFloat(window.getComputedStyle(line).lineHeight);
139 pre.style.maxHeight = `${line.offsetTop + lineHeight - headerHeight}px`;
140
141 const buttonContainer = line
142 .closest(containerClass)
143 .querySelector('.cbp-see-more-container');
144 if (!buttonContainer) return;
145 buttonContainer.style.display = 'flex';
146 const button = buttonContainer.querySelector(
147 '.cbp-see-more-simple-btn',
148 );
149 if (!button) return;
150 if (currentContainer.classList.contains('padding-disabled')) {
151 button.classList.remove('cbp-see-more-simple-btn-hover');
152 }
153 button.style.transition = `all ${
154 Math.max(animationSpeed, 1) / 1.5
155 }s linear`;
156
157 const handle = (event) => {
158 event.preventDefault();
159 button.classList.remove('cbp-see-more-simple-btn-hover');
160 pre.style.maxHeight = initialHeight + 'px';
161 setTimeout(() => {
162 button.style.opacity = 0;
163 button.style.transform = 'translateY(-100%)';
164 setTimeout(
165 () => button.remove(),
166 Math.max(animationSpeed, 1) * 1000,
167 );
168 }, animationSpeed * 1000);
169 };
170 button.addEventListener('click', handle);
171 button.addEventListener('keydown', (event) => {
172 if (event.key === 'Enter') handle(event);
173 });
174 });
175 };
176
177 const init = () => {
178 handleSeeMore();
179 handleCopyButton();
180 handleHighlighter();
181 handleFontLoading();
182 };
183
184 // Functions are idempotent, so we can run them on load and DOMContentLoaded
185 init();
186 // Useful for when the DOM is modified or loaded in late
187 window.codeBlockProInit = init;
188 window.addEventListener('DOMContentLoaded', init);
189 window.addEventListener('load', init);
190