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
← All changes | src/editor/Edit.tsx +131 -28 1.7.01.13.0 View file →
@@ -1,11 +1,22 @@
1 -import { useEffect, useLayoutEffect, useRef } from '@wordpress/element';
1 +import {
2 + useCallback,
3 + useEffect,
4 + useLayoutEffect,
5 + useRef,
6 +} from '@wordpress/element';
7 +import { escapeHTML } from '@wordpress/escape-html';
2 8 import { applyFilters } from '@wordpress/hooks';
9 +import { decodeEntities } from '@wordpress/html-entities';
10 +import { sprintf, __ } from '@wordpress/i18n';
11 +import { colord } from 'colord';
3 12 import Editor from 'react-simple-code-editor';
4 13 import { useDefaults } from '../hooks/useDefaults';
5 14 import { useTheme } from '../hooks/useTheme';
6 15 import { useLanguageStore } from '../state/language';
7 -import { AttributesPropsAndSetter } from '../types';
16 +import { AttributesPropsAndSetter, Lang } from '../types';
17 +import { parseJSONArrayWithRanges } from '../util/arrayHelpers';
18 +import { getEditorLanguage } from '../util/languages';
8 19
9 20 export const Edit = ({
10 21 attributes,
11 22 setAttributes,
@@ -19,18 +30,52 @@
19 30 disablePadding,
20 31 lineNumbersWidth,
21 32 lineNumbers,
22 33 startingLineNumber,
34 + footerType,
35 + fontSize,
36 + fontFamily,
37 + lineHeight,
38 + lineBlurs,
39 + lineHighlights,
40 + enableBlurring,
41 + enableHighlighting,
42 + seeMoreAfterLine,
43 + seeMoreTransition,
44 + enableMaxHeight,
45 + editorHeight,
23 46 } = attributes;
47 +
24 48 const textAreaRef = useRef<HTMLDivElement>(null);
25 - const handleChange = (code: string) => setAttributes({ code });
49 + const handleChange = (code: string) =>
50 + setAttributes({ code: escapeHTML(code) });
26 51 const { previousLanguage } = useLanguageStore();
27 52 const { highlighter, error, loading } = useTheme({
28 53 theme,
29 54 lang: language ?? previousLanguage,
30 55 });
56 + const hasFooter = footerType && footerType !== 'none';
31 57 useDefaults({ attributes, setAttributes });
32 58
59 + const getHighlights = useCallback(() => {
60 + if (!enableHighlighting) return [];
61 + return parseJSONArrayWithRanges(lineHighlights, startingLineNumber).map(
62 + (line: number) => ({
63 + line,
64 + classes: ['cbp-line-highlight'],
65 + }),
66 + );
67 + }, [enableHighlighting, lineHighlights, startingLineNumber]);
68 + const getBlurs = useCallback(() => {
69 + if (!enableBlurring) return [];
70 + return parseJSONArrayWithRanges(lineBlurs, startingLineNumber).map(
71 + (line: number) => ({
72 + line,
73 + classes: ['cbp-no-blur'],
74 + }),
75 + );
76 + }, [enableBlurring, lineBlurs, startingLineNumber]);
77 +
33 78 useEffect(() => {
34 79 if (!highlighter) return;
35 80 setAttributes({
36 81 bgColor: highlighter.getBackgroundColor(),
@@ -39,24 +84,53 @@
39 84 }, [theme, highlighter, setAttributes]);
40 85
41 86 useEffect(() => {
42 87 if (!highlighter) return;
43 - setAttributes({
44 - codeHTML: applyFilters(
45 - 'blocks.codeBlockPro.codeHTML',
46 - highlighter.codeToHtml(code, {
47 - lang: language ?? previousLanguage,
48 - }),
49 - attributes,
50 - ) as string,
51 - });
88 + const l = (language ?? previousLanguage) as Lang | 'ansi';
89 + const lang = getEditorLanguage(l);
90 + const c = decodeEntities(code);
91 + const lineOptions = [
92 + ...getHighlights(),
93 + ...getBlurs(),
94 + enableMaxHeight && !Number.isNaN(seeMoreAfterLine)
95 + ? {
96 + line: Number(seeMoreAfterLine),
97 + classes: [
98 + 'cbp-see-more-line',
99 + seeMoreTransition ? 'cbp-see-more-transition' : '',
100 + ],
101 + }
102 + : {},
103 + ];
104 + const rendered =
105 + l === 'ansi'
106 + ? highlighter.ansiToHtml(c, { lineOptions })
107 + : highlighter.codeToHtml(c, { lang, lineOptions });
108 + const codeHTML = applyFilters(
109 + 'blocks.codeBlockPro.codeHTML',
110 + rendered,
111 + attributes,
112 + ) as string;
113 + const lineHighlightColor = colord(color)
114 + .saturate(0.5)
115 + .alpha(0.2)
116 + .toRgbString();
117 + setAttributes({ codeHTML, lineHighlightColor });
52 118 }, [
53 119 highlighter,
120 + seeMoreAfterLine,
121 + seeMoreTransition,
122 + color,
54 123 code,
124 + enableMaxHeight,
55 125 language,
56 126 setAttributes,
57 127 previousLanguage,
58 128 attributes,
129 + lineHighlights,
130 + lineBlurs,
131 + getBlurs,
132 + getHighlights,
59 133 ]);
60 134
61 135 useLayoutEffect(() => {
62 136 if (!textAreaRef.current) return;
@@ -70,16 +144,15 @@
70 144 )?.at(-1) as HTMLElement;
71 145 // Make sure there are no width constraints
72 146 lastLine?.classList?.add('cbp-line-number-width-forced');
73 147 const lastLineWidth = lastLine?.getBoundingClientRect()?.width ?? 0;
74 - // Remove the width constraints
75 - lastLine?.classList?.remove('cbp-line-number-width-forced');
76 - // Add .cbp-line-number-disabled to disable th eline number
148 + // Add .cbp-line-number-disabled to disable the line number
77 149 lastLine?.classList.add('cbp-line-number-disabled');
78 150 // Re calculate the width of the last line
79 151 const newWidth = lastLine?.getBoundingClientRect()?.width ?? 0;
80 - // Remove the class
152 + // Remove the classes
81 153 lastLine?.classList.remove('cbp-line-number-disabled');
154 + lastLine?.classList?.remove('cbp-line-number-width-forced');
82 155 // Calculate the difference
83 156 if (lastLineWidth - newWidth > 0) {
84 157 setAttributes({ lineNumbersWidth: lastLineWidth - newWidth - 12 });
85 158 }
@@ -90,14 +163,33 @@
90 163 loading,
91 164 error,
92 165 textAreaRef,
93 166 setAttributes,
167 + fontSize,
168 + fontFamily,
169 + lineHeight,
94 170 ]);
95 171
172 + if (!loading && !highlighter) {
173 + return (
174 + <div
175 + className="p-8 px-4 text-left"
176 + style={{ backgroundColor, color }}>
177 + {sprintf(
178 + __(
179 + 'Theme %s not found. Please select a different theme.',
180 + 'code-block-pro',
181 + ),
182 + theme,
183 + )}
184 + </div>
185 + );
186 + }
187 +
96 188 if ((loading && code) || error) {
97 189 return (
98 190 <div
99 - className="p-8 px-4 text-left"
191 + className="p-6 px-4 text-left"
100 192 style={{ backgroundColor, color }}>
101 193 {error?.message ?? ''}
102 194 </div>
103 195 );
@@ -103,21 +195,29 @@
103 195 );
104 196 }
105 197
106 198 return (
107 - <div ref={textAreaRef}>
199 + <div
200 + ref={textAreaRef}
201 + style={{
202 + maxHeight: Number(editorHeight)
203 + ? Number(editorHeight)
204 + : undefined,
205 + overflow: Number(editorHeight) ? 'auto' : undefined,
206 + }}>
108 207 <Editor
109 - value={code}
208 + value={decodeEntities(code)}
110 209 onValueChange={handleChange}
111 210 padding={{
112 211 top: disablePadding ? 0 : 16,
113 - bottom: disablePadding ? 0 : 16,
114 - left:
115 - (disablePadding ? 0 : 16) +
116 - // If line numbers are disabled, just offset the 12px padding
117 - (lineNumbersWidth ?? -12) +
118 - 12,
119 - right: disablePadding ? 0 : 16,
212 + bottom: disablePadding || hasFooter ? 0 : 16,
213 + left: (() => {
214 + if (!lineNumbers && disablePadding) return 0;
215 + if (!lineNumbers) return 16;
216 + if (disablePadding) return (lineNumbersWidth ?? 0) + 16;
217 + return (lineNumbersWidth ?? 0) + 32;
218 + })(),
219 + right: 0,
120 220 }}
121 221 style={{ backgroundColor, color }}
122 222 // eslint-disable-next-line
123 223 onKeyDown={(e: any) =>
@@ -126,10 +226,13 @@
126 226 textAreaRef.current?.querySelector('textarea')?.focus()
127 227 }
128 228 highlight={(code: string) =>
129 229 highlighter
130 - ?.codeToHtml(code, {
131 - lang: language ?? previousLanguage,
230 + ?.codeToHtml(decodeEntities(code), {
231 + lang: getEditorLanguage(
232 + language ?? previousLanguage,
233 + ),
234 + lineOptions: [...getHighlights(), ...getBlurs()],
132 235 })
133 236 ?.replace(/<\/?[pre|code][^>]*>/g, '')
134 237 }
135 238 />