PluginProbe
wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin / 6.5.1.7
wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin v6.5.1.7
6.5.1.7 6.5.1.6 6.5.1.5 6.5.1.4 6.5.1.3 6.5.1.2 6.5.1.1 6.5.0.9 6.5.0.8 6.5.0.7 6.5.0.6 trunk 3.4.2.40 3.4.2.41 3.4.2.42 3.4.2.43 3.4.2.44 3.4.2.45 3.4.2.46 3.4.2.47 3.4.2.48 3.4.2.49 3.4.2.50 6.3.2 6.3.3.1 All 47 releases
wpdatatables / lib / phpoffice / phpspreadsheet / src / PhpSpreadsheet / Helper / Html.php

Html.php in wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin 6.5.1.7, at lib/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/Html.php

860 lines 25.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace PhpOffice\PhpSpreadsheet\Helper;
4
5 use DOMDocument;
6 use DOMElement;
7 use DOMNode;
8 use DOMText;
9 use PhpOffice\PhpSpreadsheet\RichText\RichText;
10 use PhpOffice\PhpSpreadsheet\Style\Color;
11 use PhpOffice\PhpSpreadsheet\Style\Font;
12
13 class Html
14 {
15 private const COLOUR_MAP = [
16 'aliceblue' => 'f0f8ff',
17 'antiquewhite' => 'faebd7',
18 'antiquewhite1' => 'ffefdb',
19 'antiquewhite2' => 'eedfcc',
20 'antiquewhite3' => 'cdc0b0',
21 'antiquewhite4' => '8b8378',
22 'aqua' => '00ffff',
23 'aquamarine1' => '7fffd4',
24 'aquamarine2' => '76eec6',
25 'aquamarine4' => '458b74',
26 'azure1' => 'f0ffff',
27 'azure2' => 'e0eeee',
28 'azure3' => 'c1cdcd',
29 'azure4' => '838b8b',
30 'beige' => 'f5f5dc',
31 'bisque1' => 'ffe4c4',
32 'bisque2' => 'eed5b7',
33 'bisque3' => 'cdb79e',
34 'bisque4' => '8b7d6b',
35 'black' => '000000',
36 'blanchedalmond' => 'ffebcd',
37 'blue' => '0000ff',
38 'blue1' => '0000ff',
39 'blue2' => '0000ee',
40 'blue4' => '00008b',
41 'blueviolet' => '8a2be2',
42 'brown' => 'a52a2a',
43 'brown1' => 'ff4040',
44 'brown2' => 'ee3b3b',
45 'brown3' => 'cd3333',
46 'brown4' => '8b2323',
47 'burlywood' => 'deb887',
48 'burlywood1' => 'ffd39b',
49 'burlywood2' => 'eec591',
50 'burlywood3' => 'cdaa7d',
51 'burlywood4' => '8b7355',
52 'cadetblue' => '5f9ea0',
53 'cadetblue1' => '98f5ff',
54 'cadetblue2' => '8ee5ee',
55 'cadetblue3' => '7ac5cd',
56 'cadetblue4' => '53868b',
57 'chartreuse1' => '7fff00',
58 'chartreuse2' => '76ee00',
59 'chartreuse3' => '66cd00',
60 'chartreuse4' => '458b00',
61 'chocolate' => 'd2691e',
62 'chocolate1' => 'ff7f24',
63 'chocolate2' => 'ee7621',
64 'chocolate3' => 'cd661d',
65 'coral' => 'ff7f50',
66 'coral1' => 'ff7256',
67 'coral2' => 'ee6a50',
68 'coral3' => 'cd5b45',
69 'coral4' => '8b3e2f',
70 'cornflowerblue' => '6495ed',
71 'cornsilk1' => 'fff8dc',
72 'cornsilk2' => 'eee8cd',
73 'cornsilk3' => 'cdc8b1',
74 'cornsilk4' => '8b8878',
75 'cyan1' => '00ffff',
76 'cyan2' => '00eeee',
77 'cyan3' => '00cdcd',
78 'cyan4' => '008b8b',
79 'darkgoldenrod' => 'b8860b',
80 'darkgoldenrod1' => 'ffb90f',
81 'darkgoldenrod2' => 'eead0e',
82 'darkgoldenrod3' => 'cd950c',
83 'darkgoldenrod4' => '8b6508',
84 'darkgreen' => '006400',
85 'darkkhaki' => 'bdb76b',
86 'darkolivegreen' => '556b2f',
87 'darkolivegreen1' => 'caff70',
88 'darkolivegreen2' => 'bcee68',
89 'darkolivegreen3' => 'a2cd5a',
90 'darkolivegreen4' => '6e8b3d',
91 'darkorange' => 'ff8c00',
92 'darkorange1' => 'ff7f00',
93 'darkorange2' => 'ee7600',
94 'darkorange3' => 'cd6600',
95 'darkorange4' => '8b4500',
96 'darkorchid' => '9932cc',
97 'darkorchid1' => 'bf3eff',
98 'darkorchid2' => 'b23aee',
99 'darkorchid3' => '9a32cd',
100 'darkorchid4' => '68228b',
101 'darksalmon' => 'e9967a',
102 'darkseagreen' => '8fbc8f',
103 'darkseagreen1' => 'c1ffc1',
104 'darkseagreen2' => 'b4eeb4',
105 'darkseagreen3' => '9bcd9b',
106 'darkseagreen4' => '698b69',
107 'darkslateblue' => '483d8b',
108 'darkslategray' => '2f4f4f',
109 'darkslategray1' => '97ffff',
110 'darkslategray2' => '8deeee',
111 'darkslategray3' => '79cdcd',
112 'darkslategray4' => '528b8b',
113 'darkturquoise' => '00ced1',
114 'darkviolet' => '9400d3',
115 'deeppink1' => 'ff1493',
116 'deeppink2' => 'ee1289',
117 'deeppink3' => 'cd1076',
118 'deeppink4' => '8b0a50',
119 'deepskyblue1' => '00bfff',
120 'deepskyblue2' => '00b2ee',
121 'deepskyblue3' => '009acd',
122 'deepskyblue4' => '00688b',
123 'dimgray' => '696969',
124 'dodgerblue1' => '1e90ff',
125 'dodgerblue2' => '1c86ee',
126 'dodgerblue3' => '1874cd',
127 'dodgerblue4' => '104e8b',
128 'firebrick' => 'b22222',
129 'firebrick1' => 'ff3030',
130 'firebrick2' => 'ee2c2c',
131 'firebrick3' => 'cd2626',
132 'firebrick4' => '8b1a1a',
133 'floralwhite' => 'fffaf0',
134 'forestgreen' => '228b22',
135 'fuchsia' => 'ff00ff',
136 'gainsboro' => 'dcdcdc',
137 'ghostwhite' => 'f8f8ff',
138 'gold1' => 'ffd700',
139 'gold2' => 'eec900',
140 'gold3' => 'cdad00',
141 'gold4' => '8b7500',
142 'goldenrod' => 'daa520',
143 'goldenrod1' => 'ffc125',
144 'goldenrod2' => 'eeb422',
145 'goldenrod3' => 'cd9b1d',
146 'goldenrod4' => '8b6914',
147 'gray' => 'bebebe',
148 'gray1' => '030303',
149 'gray10' => '1a1a1a',
150 'gray11' => '1c1c1c',
151 'gray12' => '1f1f1f',
152 'gray13' => '212121',
153 'gray14' => '242424',
154 'gray15' => '262626',
155 'gray16' => '292929',
156 'gray17' => '2b2b2b',
157 'gray18' => '2e2e2e',
158 'gray19' => '303030',
159 'gray2' => '050505',
160 'gray20' => '333333',
161 'gray21' => '363636',
162 'gray22' => '383838',
163 'gray23' => '3b3b3b',
164 'gray24' => '3d3d3d',
165 'gray25' => '404040',
166 'gray26' => '424242',
167 'gray27' => '454545',
168 'gray28' => '474747',
169 'gray29' => '4a4a4a',
170 'gray3' => '080808',
171 'gray30' => '4d4d4d',
172 'gray31' => '4f4f4f',
173 'gray32' => '525252',
174 'gray33' => '545454',
175 'gray34' => '575757',
176 'gray35' => '595959',
177 'gray36' => '5c5c5c',
178 'gray37' => '5e5e5e',
179 'gray38' => '616161',
180 'gray39' => '636363',
181 'gray4' => '0a0a0a',
182 'gray40' => '666666',
183 'gray41' => '696969',
184 'gray42' => '6b6b6b',
185 'gray43' => '6e6e6e',
186 'gray44' => '707070',
187 'gray45' => '737373',
188 'gray46' => '757575',
189 'gray47' => '787878',
190 'gray48' => '7a7a7a',
191 'gray49' => '7d7d7d',
192 'gray5' => '0d0d0d',
193 'gray50' => '7f7f7f',
194 'gray51' => '828282',
195 'gray52' => '858585',
196 'gray53' => '878787',
197 'gray54' => '8a8a8a',
198 'gray55' => '8c8c8c',
199 'gray56' => '8f8f8f',
200 'gray57' => '919191',
201 'gray58' => '949494',
202 'gray59' => '969696',
203 'gray6' => '0f0f0f',
204 'gray60' => '999999',
205 'gray61' => '9c9c9c',
206 'gray62' => '9e9e9e',
207 'gray63' => 'a1a1a1',
208 'gray64' => 'a3a3a3',
209 'gray65' => 'a6a6a6',
210 'gray66' => 'a8a8a8',
211 'gray67' => 'ababab',
212 'gray68' => 'adadad',
213 'gray69' => 'b0b0b0',
214 'gray7' => '121212',
215 'gray70' => 'b3b3b3',
216 'gray71' => 'b5b5b5',
217 'gray72' => 'b8b8b8',
218 'gray73' => 'bababa',
219 'gray74' => 'bdbdbd',
220 'gray75' => 'bfbfbf',
221 'gray76' => 'c2c2c2',
222 'gray77' => 'c4c4c4',
223 'gray78' => 'c7c7c7',
224 'gray79' => 'c9c9c9',
225 'gray8' => '141414',
226 'gray80' => 'cccccc',
227 'gray81' => 'cfcfcf',
228 'gray82' => 'd1d1d1',
229 'gray83' => 'd4d4d4',
230 'gray84' => 'd6d6d6',
231 'gray85' => 'd9d9d9',
232 'gray86' => 'dbdbdb',
233 'gray87' => 'dedede',
234 'gray88' => 'e0e0e0',
235 'gray89' => 'e3e3e3',
236 'gray9' => '171717',
237 'gray90' => 'e5e5e5',
238 'gray91' => 'e8e8e8',
239 'gray92' => 'ebebeb',
240 'gray93' => 'ededed',
241 'gray94' => 'f0f0f0',
242 'gray95' => 'f2f2f2',
243 'gray97' => 'f7f7f7',
244 'gray98' => 'fafafa',
245 'gray99' => 'fcfcfc',
246 'green' => '00ff00',
247 'green1' => '00ff00',
248 'green2' => '00ee00',
249 'green3' => '00cd00',
250 'green4' => '008b00',
251 'greenyellow' => 'adff2f',
252 'honeydew1' => 'f0fff0',
253 'honeydew2' => 'e0eee0',
254 'honeydew3' => 'c1cdc1',
255 'honeydew4' => '838b83',
256 'hotpink' => 'ff69b4',
257 'hotpink1' => 'ff6eb4',
258 'hotpink2' => 'ee6aa7',
259 'hotpink3' => 'cd6090',
260 'hotpink4' => '8b3a62',
261 'indianred' => 'cd5c5c',
262 'indianred1' => 'ff6a6a',
263 'indianred2' => 'ee6363',
264 'indianred3' => 'cd5555',
265 'indianred4' => '8b3a3a',
266 'ivory1' => 'fffff0',
267 'ivory2' => 'eeeee0',
268 'ivory3' => 'cdcdc1',
269 'ivory4' => '8b8b83',
270 'khaki' => 'f0e68c',
271 'khaki1' => 'fff68f',
272 'khaki2' => 'eee685',
273 'khaki3' => 'cdc673',
274 'khaki4' => '8b864e',
275 'lavender' => 'e6e6fa',
276 'lavenderblush1' => 'fff0f5',
277 'lavenderblush2' => 'eee0e5',
278 'lavenderblush3' => 'cdc1c5',
279 'lavenderblush4' => '8b8386',
280 'lawngreen' => '7cfc00',
281 'lemonchiffon1' => 'fffacd',
282 'lemonchiffon2' => 'eee9bf',
283 'lemonchiffon3' => 'cdc9a5',
284 'lemonchiffon4' => '8b8970',
285 'light' => 'eedd82',
286 'lightblue' => 'add8e6',
287 'lightblue1' => 'bfefff',
288 'lightblue2' => 'b2dfee',
289 'lightblue3' => '9ac0cd',
290 'lightblue4' => '68838b',
291 'lightcoral' => 'f08080',
292 'lightcyan1' => 'e0ffff',
293 'lightcyan2' => 'd1eeee',
294 'lightcyan3' => 'b4cdcd',
295 'lightcyan4' => '7a8b8b',
296 'lightgoldenrod1' => 'ffec8b',
297 'lightgoldenrod2' => 'eedc82',
298 'lightgoldenrod3' => 'cdbe70',
299 'lightgoldenrod4' => '8b814c',
300 'lightgoldenrodyellow' => 'fafad2',
301 'lightgray' => 'd3d3d3',
302 'lightpink' => 'ffb6c1',
303 'lightpink1' => 'ffaeb9',
304 'lightpink2' => 'eea2ad',
305 'lightpink3' => 'cd8c95',
306 'lightpink4' => '8b5f65',
307 'lightsalmon1' => 'ffa07a',
308 'lightsalmon2' => 'ee9572',
309 'lightsalmon3' => 'cd8162',
310 'lightsalmon4' => '8b5742',
311 'lightseagreen' => '20b2aa',
312 'lightskyblue' => '87cefa',
313 'lightskyblue1' => 'b0e2ff',
314 'lightskyblue2' => 'a4d3ee',
315 'lightskyblue3' => '8db6cd',
316 'lightskyblue4' => '607b8b',
317 'lightslateblue' => '8470ff',
318 'lightslategray' => '778899',
319 'lightsteelblue' => 'b0c4de',
320 'lightsteelblue1' => 'cae1ff',
321 'lightsteelblue2' => 'bcd2ee',
322 'lightsteelblue3' => 'a2b5cd',
323 'lightsteelblue4' => '6e7b8b',
324 'lightyellow1' => 'ffffe0',
325 'lightyellow2' => 'eeeed1',
326 'lightyellow3' => 'cdcdb4',
327 'lightyellow4' => '8b8b7a',
328 'lime' => '00ff00',
329 'limegreen' => '32cd32',
330 'linen' => 'faf0e6',
331 'magenta' => 'ff00ff',
332 'magenta2' => 'ee00ee',
333 'magenta3' => 'cd00cd',
334 'magenta4' => '8b008b',
335 'maroon' => 'b03060',
336 'maroon1' => 'ff34b3',
337 'maroon2' => 'ee30a7',
338 'maroon3' => 'cd2990',
339 'maroon4' => '8b1c62',
340 'medium' => '66cdaa',
341 'mediumaquamarine' => '66cdaa',
342 'mediumblue' => '0000cd',
343 'mediumorchid' => 'ba55d3',
344 'mediumorchid1' => 'e066ff',
345 'mediumorchid2' => 'd15fee',
346 'mediumorchid3' => 'b452cd',
347 'mediumorchid4' => '7a378b',
348 'mediumpurple' => '9370db',
349 'mediumpurple1' => 'ab82ff',
350 'mediumpurple2' => '9f79ee',
351 'mediumpurple3' => '8968cd',
352 'mediumpurple4' => '5d478b',
353 'mediumseagreen' => '3cb371',
354 'mediumslateblue' => '7b68ee',
355 'mediumspringgreen' => '00fa9a',
356 'mediumturquoise' => '48d1cc',
357 'mediumvioletred' => 'c71585',
358 'midnightblue' => '191970',
359 'mintcream' => 'f5fffa',
360 'mistyrose1' => 'ffe4e1',
361 'mistyrose2' => 'eed5d2',
362 'mistyrose3' => 'cdb7b5',
363 'mistyrose4' => '8b7d7b',
364 'moccasin' => 'ffe4b5',
365 'navajowhite1' => 'ffdead',
366 'navajowhite2' => 'eecfa1',
367 'navajowhite3' => 'cdb38b',
368 'navajowhite4' => '8b795e',
369 'navy' => '000080',
370 'navyblue' => '000080',
371 'oldlace' => 'fdf5e6',
372 'olive' => '808000',
373 'olivedrab' => '6b8e23',
374 'olivedrab1' => 'c0ff3e',
375 'olivedrab2' => 'b3ee3a',
376 'olivedrab4' => '698b22',
377 'orange' => 'ffa500',
378 'orange1' => 'ffa500',
379 'orange2' => 'ee9a00',
380 'orange3' => 'cd8500',
381 'orange4' => '8b5a00',
382 'orangered1' => 'ff4500',
383 'orangered2' => 'ee4000',
384 'orangered3' => 'cd3700',
385 'orangered4' => '8b2500',
386 'orchid' => 'da70d6',
387 'orchid1' => 'ff83fa',
388 'orchid2' => 'ee7ae9',
389 'orchid3' => 'cd69c9',
390 'orchid4' => '8b4789',
391 'pale' => 'db7093',
392 'palegoldenrod' => 'eee8aa',
393 'palegreen' => '98fb98',
394 'palegreen1' => '9aff9a',
395 'palegreen2' => '90ee90',
396 'palegreen3' => '7ccd7c',
397 'palegreen4' => '548b54',
398 'paleturquoise' => 'afeeee',
399 'paleturquoise1' => 'bbffff',
400 'paleturquoise2' => 'aeeeee',
401 'paleturquoise3' => '96cdcd',
402 'paleturquoise4' => '668b8b',
403 'palevioletred' => 'db7093',
404 'palevioletred1' => 'ff82ab',
405 'palevioletred2' => 'ee799f',
406 'palevioletred3' => 'cd6889',
407 'palevioletred4' => '8b475d',
408 'papayawhip' => 'ffefd5',
409 'peachpuff1' => 'ffdab9',
410 'peachpuff2' => 'eecbad',
411 'peachpuff3' => 'cdaf95',
412 'peachpuff4' => '8b7765',
413 'pink' => 'ffc0cb',
414 'pink1' => 'ffb5c5',
415 'pink2' => 'eea9b8',
416 'pink3' => 'cd919e',
417 'pink4' => '8b636c',
418 'plum' => 'dda0dd',
419 'plum1' => 'ffbbff',
420 'plum2' => 'eeaeee',
421 'plum3' => 'cd96cd',
422 'plum4' => '8b668b',
423 'powderblue' => 'b0e0e6',
424 'purple' => 'a020f0',
425 'rebeccapurple' => '663399',
426 'purple1' => '9b30ff',
427 'purple2' => '912cee',
428 'purple3' => '7d26cd',
429 'purple4' => '551a8b',
430 'red' => 'ff0000',
431 'red1' => 'ff0000',
432 'red2' => 'ee0000',
433 'red3' => 'cd0000',
434 'red4' => '8b0000',
435 'rosybrown' => 'bc8f8f',
436 'rosybrown1' => 'ffc1c1',
437 'rosybrown2' => 'eeb4b4',
438 'rosybrown3' => 'cd9b9b',
439 'rosybrown4' => '8b6969',
440 'royalblue' => '4169e1',
441 'royalblue1' => '4876ff',
442 'royalblue2' => '436eee',
443 'royalblue3' => '3a5fcd',
444 'royalblue4' => '27408b',
445 'saddlebrown' => '8b4513',
446 'salmon' => 'fa8072',
447 'salmon1' => 'ff8c69',
448 'salmon2' => 'ee8262',
449 'salmon3' => 'cd7054',
450 'salmon4' => '8b4c39',
451 'sandybrown' => 'f4a460',
452 'seagreen1' => '54ff9f',
453 'seagreen2' => '4eee94',
454 'seagreen3' => '43cd80',
455 'seagreen4' => '2e8b57',
456 'seashell1' => 'fff5ee',
457 'seashell2' => 'eee5de',
458 'seashell3' => 'cdc5bf',
459 'seashell4' => '8b8682',
460 'sienna' => 'a0522d',
461 'sienna1' => 'ff8247',
462 'sienna2' => 'ee7942',
463 'sienna3' => 'cd6839',
464 'sienna4' => '8b4726',
465 'silver' => 'c0c0c0',
466 'skyblue' => '87ceeb',
467 'skyblue1' => '87ceff',
468 'skyblue2' => '7ec0ee',
469 'skyblue3' => '6ca6cd',
470 'skyblue4' => '4a708b',
471 'slateblue' => '6a5acd',
472 'slateblue1' => '836fff',
473 'slateblue2' => '7a67ee',
474 'slateblue3' => '6959cd',
475 'slateblue4' => '473c8b',
476 'slategray' => '708090',
477 'slategray1' => 'c6e2ff',
478 'slategray2' => 'b9d3ee',
479 'slategray3' => '9fb6cd',
480 'slategray4' => '6c7b8b',
481 'snow1' => 'fffafa',
482 'snow2' => 'eee9e9',
483 'snow3' => 'cdc9c9',
484 'snow4' => '8b8989',
485 'springgreen1' => '00ff7f',
486 'springgreen2' => '00ee76',
487 'springgreen3' => '00cd66',
488 'springgreen4' => '008b45',
489 'steelblue' => '4682b4',
490 'steelblue1' => '63b8ff',
491 'steelblue2' => '5cacee',
492 'steelblue3' => '4f94cd',
493 'steelblue4' => '36648b',
494 'tan' => 'd2b48c',
495 'tan1' => 'ffa54f',
496 'tan2' => 'ee9a49',
497 'tan3' => 'cd853f',
498 'tan4' => '8b5a2b',
499 'teal' => '008080',
500 'thistle' => 'd8bfd8',
501 'thistle1' => 'ffe1ff',
502 'thistle2' => 'eed2ee',
503 'thistle3' => 'cdb5cd',
504 'thistle4' => '8b7b8b',
505 'tomato1' => 'ff6347',
506 'tomato2' => 'ee5c42',
507 'tomato3' => 'cd4f39',
508 'tomato4' => '8b3626',
509 'turquoise' => '40e0d0',
510 'turquoise1' => '00f5ff',
511 'turquoise2' => '00e5ee',
512 'turquoise3' => '00c5cd',
513 'turquoise4' => '00868b',
514 'violet' => 'ee82ee',
515 'violetred' => 'd02090',
516 'violetred1' => 'ff3e96',
517 'violetred2' => 'ee3a8c',
518 'violetred3' => 'cd3278',
519 'violetred4' => '8b2252',
520 'wheat' => 'f5deb3',
521 'wheat1' => 'ffe7ba',
522 'wheat2' => 'eed8ae',
523 'wheat3' => 'cdba96',
524 'wheat4' => '8b7e66',
525 'white' => 'ffffff',
526 'whitesmoke' => 'f5f5f5',
527 'yellow' => 'ffff00',
528 'yellow1' => 'ffff00',
529 'yellow2' => 'eeee00',
530 'yellow3' => 'cdcd00',
531 'yellow4' => '8b8b00',
532 'yellowgreen' => '9acd32',
533 ];
534
535 /** @var ?string */
536 private $face;
537
538 /** @var ?string */
539 private $size;
540
541 /** @var ?string */
542 private $color;
543
544 /** @var bool */
545 private $bold = false;
546
547 /** @var bool */
548 private $italic = false;
549
550 /** @var bool */
551 private $underline = false;
552
553 /** @var bool */
554 private $superscript = false;
555
556 /** @var bool */
557 private $subscript = false;
558
559 /** @var bool */
560 private $strikethrough = false;
561
562 private const START_TAG_CALLBACKS = [
563 'font' => 'startFontTag',
564 'b' => 'startBoldTag',
565 'strong' => 'startBoldTag',
566 'i' => 'startItalicTag',
567 'em' => 'startItalicTag',
568 'u' => 'startUnderlineTag',
569 'ins' => 'startUnderlineTag',
570 'del' => 'startStrikethruTag',
571 'sup' => 'startSuperscriptTag',
572 'sub' => 'startSubscriptTag',
573 ];
574
575 private const END_TAG_CALLBACKS = [
576 'font' => 'endFontTag',
577 'b' => 'endBoldTag',
578 'strong' => 'endBoldTag',
579 'i' => 'endItalicTag',
580 'em' => 'endItalicTag',
581 'u' => 'endUnderlineTag',
582 'ins' => 'endUnderlineTag',
583 'del' => 'endStrikethruTag',
584 'sup' => 'endSuperscriptTag',
585 'sub' => 'endSubscriptTag',
586 'br' => 'breakTag',
587 'p' => 'breakTag',
588 'h1' => 'breakTag',
589 'h2' => 'breakTag',
590 'h3' => 'breakTag',
591 'h4' => 'breakTag',
592 'h5' => 'breakTag',
593 'h6' => 'breakTag',
594 ];
595
596 /** @var array */
597 private $stack = [];
598
599 /** @var string */
600 private $stringData = '';
601
602 /**
603 * @var RichText
604 */
605 private $richTextObject;
606
607 private function initialise(): void
608 {
609 $this->face = $this->size = $this->color = null;
610 $this->bold = $this->italic = $this->underline = $this->superscript = $this->subscript = $this->strikethrough = false;
611
612 $this->stack = [];
613
614 $this->stringData = '';
615 }
616
617 /**
618 * Parse HTML formatting and return the resulting RichText.
619 *
620 * @param string $html
621 *
622 * @return RichText
623 */
624 public function toRichTextObject($html)
625 {
626 $this->initialise();
627
628 // Create a new DOM object
629 $dom = new DOMDocument();
630 // Load the HTML file into the DOM object
631 // Note the use of error suppression, because typically this will be an html fragment, so not fully valid markup
632 $prefix = '<?xml encoding="UTF-8">';
633 /** @scrutinizer ignore-unhandled */
634 @$dom->loadHTML($prefix . $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
635 // Discard excess white space
636 $dom->preserveWhiteSpace = false;
637
638 $this->richTextObject = new RichText();
639 $this->parseElements($dom);
640
641 // Clean any further spurious whitespace
642 $this->cleanWhitespace();
643
644 return $this->richTextObject;
645 }
646
647 private function cleanWhitespace(): void
648 {
649 foreach ($this->richTextObject->getRichTextElements() as $key => $element) {
650 $text = $element->getText();
651 // Trim any leading spaces on the first run
652 if ($key == 0) {
653 $text = ltrim($text);
654 }
655 // Trim any spaces immediately after a line break
656 $text = (string) preg_replace('/\n */mu', "\n", $text);
657 $element->setText($text);
658 }
659 }
660
661 private function buildTextRun(): void
662 {
663 $text = $this->stringData;
664 if (trim($text) === '') {
665 return;
666 }
667
668 $richtextRun = $this->richTextObject->createTextRun($this->stringData);
669 $font = $richtextRun->getFont();
670 if ($font !== null) {
671 if ($this->face) {
672 $font->setName($this->face);
673 }
674 if ($this->size) {
675 $font->setSize($this->size);
676 }
677 if ($this->color) {
678 $font->setColor(new Color('ff' . $this->color));
679 }
680 if ($this->bold) {
681 $font->setBold(true);
682 }
683 if ($this->italic) {
684 $font->setItalic(true);
685 }
686 if ($this->underline) {
687 $font->setUnderline(Font::UNDERLINE_SINGLE);
688 }
689 if ($this->superscript) {
690 $font->setSuperscript(true);
691 }
692 if ($this->subscript) {
693 $font->setSubscript(true);
694 }
695 if ($this->strikethrough) {
696 $font->setStrikethrough(true);
697 }
698 }
699 $this->stringData = '';
700 }
701
702 private function rgbToColour(string $rgbValue): string
703 {
704 preg_match_all('/\d+/', $rgbValue, $values);
705 foreach ($values[0] as &$value) {
706 $value = str_pad(dechex($value), 2, '0', STR_PAD_LEFT);
707 }
708
709 return implode('', $values[0]);
710 }
711
712 public static function colourNameLookup(string $colorName): string
713 {
714 return self::COLOUR_MAP[$colorName] ?? '';
715 }
716
717 protected function startFontTag(DOMElement $tag): void
718 {
719 $attrs = $tag->attributes;
720 if ($attrs !== null) {
721 foreach ($attrs as $attribute) {
722 $attributeName = strtolower($attribute->name);
723 $attributeValue = $attribute->value;
724
725 if ($attributeName == 'color') {
726 if (preg_match('/rgb\s*\(/', $attributeValue)) {
727 $this->$attributeName = $this->rgbToColour($attributeValue);
728 } elseif (strpos(trim($attributeValue), '#') === 0) {
729 $this->$attributeName = ltrim($attributeValue, '#');
730 } else {
731 $this->$attributeName = static::colourNameLookup($attributeValue);
732 }
733 } else {
734 $this->$attributeName = $attributeValue;
735 }
736 }
737 }
738 }
739
740 protected function endFontTag(): void
741 {
742 $this->face = $this->size = $this->color = null;
743 }
744
745 protected function startBoldTag(): void
746 {
747 $this->bold = true;
748 }
749
750 protected function endBoldTag(): void
751 {
752 $this->bold = false;
753 }
754
755 protected function startItalicTag(): void
756 {
757 $this->italic = true;
758 }
759
760 protected function endItalicTag(): void
761 {
762 $this->italic = false;
763 }
764
765 protected function startUnderlineTag(): void
766 {
767 $this->underline = true;
768 }
769
770 protected function endUnderlineTag(): void
771 {
772 $this->underline = false;
773 }
774
775 protected function startSubscriptTag(): void
776 {
777 $this->subscript = true;
778 }
779
780 protected function endSubscriptTag(): void
781 {
782 $this->subscript = false;
783 }
784
785 protected function startSuperscriptTag(): void
786 {
787 $this->superscript = true;
788 }
789
790 protected function endSuperscriptTag(): void
791 {
792 $this->superscript = false;
793 }
794
795 protected function startStrikethruTag(): void
796 {
797 $this->strikethrough = true;
798 }
799
800 protected function endStrikethruTag(): void
801 {
802 $this->strikethrough = false;
803 }
804
805 protected function breakTag(): void
806 {
807 $this->stringData .= "\n";
808 }
809
810 private function parseTextNode(DOMText $textNode): void
811 {
812 $domText = (string) preg_replace(
813 '/\s+/u',
814 ' ',
815 str_replace(["\r", "\n"], ' ', $textNode->nodeValue ?? '')
816 );
817 $this->stringData .= $domText;
818 $this->buildTextRun();
819 }
820
821 /**
822 * @param string $callbackTag
823 */
824 private function handleCallback(DOMElement $element, $callbackTag, array $callbacks): void
825 {
826 if (isset($callbacks[$callbackTag])) {
827 $elementHandler = $callbacks[$callbackTag];
828 if (method_exists($this, $elementHandler)) {
829 /** @var callable */
830 $callable = [$this, $elementHandler];
831 call_user_func($callable, $element);
832 }
833 }
834 }
835
836 private function parseElementNode(DOMElement $element): void
837 {
838 $callbackTag = strtolower($element->nodeName);
839 $this->stack[] = $callbackTag;
840
841 $this->handleCallback($element, $callbackTag, self::START_TAG_CALLBACKS);
842
843 $this->parseElements($element);
844 array_pop($this->stack);
845
846 $this->handleCallback($element, $callbackTag, self::END_TAG_CALLBACKS);
847 }
848
849 private function parseElements(DOMNode $element): void
850 {
851 foreach ($element->childNodes as $child) {
852 if ($child instanceof DOMText) {
853 $this->parseTextNode($child);
854 } elseif ($child instanceof DOMElement) {
855 $this->parseElementNode($child);
856 }
857 }
858 }
859 }
860