PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.5.1
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.5.1
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
visualizer / vendor / phpoffice / phpspreadsheet / src / PhpSpreadsheet / Helper / Html.php

Html.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.5.1, at vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/Html.php

842 lines 24.8 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 protected static $colourMap = [
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 protected $face;
536
537 protected $size;
538
539 protected $color;
540
541 protected $bold = false;
542
543 protected $italic = false;
544
545 protected $underline = false;
546
547 protected $superscript = false;
548
549 protected $subscript = false;
550
551 protected $strikethrough = false;
552
553 protected $startTagCallbacks = [
554 'font' => 'startFontTag',
555 'b' => 'startBoldTag',
556 'strong' => 'startBoldTag',
557 'i' => 'startItalicTag',
558 'em' => 'startItalicTag',
559 'u' => 'startUnderlineTag',
560 'ins' => 'startUnderlineTag',
561 'del' => 'startStrikethruTag',
562 'sup' => 'startSuperscriptTag',
563 'sub' => 'startSubscriptTag',
564 ];
565
566 protected $endTagCallbacks = [
567 'font' => 'endFontTag',
568 'b' => 'endBoldTag',
569 'strong' => 'endBoldTag',
570 'i' => 'endItalicTag',
571 'em' => 'endItalicTag',
572 'u' => 'endUnderlineTag',
573 'ins' => 'endUnderlineTag',
574 'del' => 'endStrikethruTag',
575 'sup' => 'endSuperscriptTag',
576 'sub' => 'endSubscriptTag',
577 'br' => 'breakTag',
578 'p' => 'breakTag',
579 'h1' => 'breakTag',
580 'h2' => 'breakTag',
581 'h3' => 'breakTag',
582 'h4' => 'breakTag',
583 'h5' => 'breakTag',
584 'h6' => 'breakTag',
585 ];
586
587 protected $stack = [];
588
589 protected $stringData = '';
590
591 /**
592 * @var RichText
593 */
594 protected $richTextObject;
595
596 protected function initialise()
597 {
598 $this->face = $this->size = $this->color = null;
599 $this->bold = $this->italic = $this->underline = $this->superscript = $this->subscript = $this->strikethrough = false;
600
601 $this->stack = [];
602
603 $this->stringData = '';
604 }
605
606 /**
607 * Parse HTML formatting and return the resulting RichText.
608 *
609 * @param string $html
610 *
611 * @return RichText
612 */
613 public function toRichTextObject($html)
614 {
615 $this->initialise();
616
617 // Create a new DOM object
618 $dom = new DOMDocument();
619 // Load the HTML file into the DOM object
620 // Note the use of error suppression, because typically this will be an html fragment, so not fully valid markup
621 $prefix = '<?xml encoding="UTF-8">';
622 @$dom->loadHTML($prefix . $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
623 // Discard excess white space
624 $dom->preserveWhiteSpace = false;
625
626 $this->richTextObject = new RichText();
627 $this->parseElements($dom);
628
629 // Clean any further spurious whitespace
630 $this->cleanWhitespace();
631
632 return $this->richTextObject;
633 }
634
635 protected function cleanWhitespace()
636 {
637 foreach ($this->richTextObject->getRichTextElements() as $key => $element) {
638 $text = $element->getText();
639 // Trim any leading spaces on the first run
640 if ($key == 0) {
641 $text = ltrim($text);
642 }
643 // Trim any spaces immediately after a line break
644 $text = preg_replace('/\n */mu', "\n", $text);
645 $element->setText($text);
646 }
647 }
648
649 protected function buildTextRun()
650 {
651 $text = $this->stringData;
652 if (trim($text) === '') {
653 return;
654 }
655
656 $richtextRun = $this->richTextObject->createTextRun($this->stringData);
657 if ($this->face) {
658 $richtextRun->getFont()->setName($this->face);
659 }
660 if ($this->size) {
661 $richtextRun->getFont()->setSize($this->size);
662 }
663 if ($this->color) {
664 $richtextRun->getFont()->setColor(new Color('ff' . $this->color));
665 }
666 if ($this->bold) {
667 $richtextRun->getFont()->setBold(true);
668 }
669 if ($this->italic) {
670 $richtextRun->getFont()->setItalic(true);
671 }
672 if ($this->underline) {
673 $richtextRun->getFont()->setUnderline(Font::UNDERLINE_SINGLE);
674 }
675 if ($this->superscript) {
676 $richtextRun->getFont()->setSuperscript(true);
677 }
678 if ($this->subscript) {
679 $richtextRun->getFont()->setSubscript(true);
680 }
681 if ($this->strikethrough) {
682 $richtextRun->getFont()->setStrikethrough(true);
683 }
684 $this->stringData = '';
685 }
686
687 protected function rgbToColour($rgb)
688 {
689 preg_match_all('/\d+/', $rgb, $values);
690 foreach ($values[0] as &$value) {
691 $value = str_pad(dechex($value), 2, '0', STR_PAD_LEFT);
692 }
693
694 return implode($values[0]);
695 }
696
697 protected function colourNameLookup($rgb)
698 {
699 return self::$colourMap[$rgb];
700 }
701
702 protected function startFontTag($tag)
703 {
704 foreach ($tag->attributes as $attribute) {
705 $attributeName = strtolower($attribute->name);
706 $attributeValue = $attribute->value;
707
708 if ($attributeName == 'color') {
709 if (preg_match('/rgb\s*\(/', $attributeValue)) {
710 $this->$attributeName = $this->rgbToColour($attributeValue);
711 } elseif (strpos(trim($attributeValue), '#') === 0) {
712 $this->$attributeName = ltrim($attributeValue, '#');
713 } else {
714 $this->$attributeName = $this->colourNameLookup($attributeValue);
715 }
716 } else {
717 $this->$attributeName = $attributeValue;
718 }
719 }
720 }
721
722 protected function endFontTag()
723 {
724 $this->face = $this->size = $this->color = null;
725 }
726
727 protected function startBoldTag()
728 {
729 $this->bold = true;
730 }
731
732 protected function endBoldTag()
733 {
734 $this->bold = false;
735 }
736
737 protected function startItalicTag()
738 {
739 $this->italic = true;
740 }
741
742 protected function endItalicTag()
743 {
744 $this->italic = false;
745 }
746
747 protected function startUnderlineTag()
748 {
749 $this->underline = true;
750 }
751
752 protected function endUnderlineTag()
753 {
754 $this->underline = false;
755 }
756
757 protected function startSubscriptTag()
758 {
759 $this->subscript = true;
760 }
761
762 protected function endSubscriptTag()
763 {
764 $this->subscript = false;
765 }
766
767 protected function startSuperscriptTag()
768 {
769 $this->superscript = true;
770 }
771
772 protected function endSuperscriptTag()
773 {
774 $this->superscript = false;
775 }
776
777 protected function startStrikethruTag()
778 {
779 $this->strikethrough = true;
780 }
781
782 protected function endStrikethruTag()
783 {
784 $this->strikethrough = false;
785 }
786
787 protected function breakTag()
788 {
789 $this->stringData .= "\n";
790 }
791
792 protected function parseTextNode(DOMText $textNode)
793 {
794 $domText = preg_replace(
795 '/\s+/u',
796 ' ',
797 str_replace(["\r", "\n"], ' ', $textNode->nodeValue)
798 );
799 $this->stringData .= $domText;
800 $this->buildTextRun();
801 }
802
803 /**
804 * @param DOMElement $element
805 * @param string $callbackTag
806 * @param array $callbacks
807 */
808 protected function handleCallback(DOMElement $element, $callbackTag, array $callbacks)
809 {
810 if (isset($callbacks[$callbackTag])) {
811 $elementHandler = $callbacks[$callbackTag];
812 if (method_exists($this, $elementHandler)) {
813 call_user_func([$this, $elementHandler], $element);
814 }
815 }
816 }
817
818 protected function parseElementNode(DOMElement $element)
819 {
820 $callbackTag = strtolower($element->nodeName);
821 $this->stack[] = $callbackTag;
822
823 $this->handleCallback($element, $callbackTag, $this->startTagCallbacks);
824
825 $this->parseElements($element);
826 array_pop($this->stack);
827
828 $this->handleCallback($element, $callbackTag, $this->endTagCallbacks);
829 }
830
831 protected function parseElements(DOMNode $element)
832 {
833 foreach ($element->childNodes as $child) {
834 if ($child instanceof DOMText) {
835 $this->parseTextNode($child);
836 } elseif ($child instanceof DOMElement) {
837 $this->parseElementNode($child);
838 }
839 }
840 }
841 }
842