PluginProbe
Code Block Pro – Beautiful Syntax Highlighting / 1.13.0
Code Block Pro – Beautiful Syntax Highlighting v1.13.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.13.0, at src/front/front.js

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