comparison vendor/masterminds/html5/src/HTML5/Elements.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 129ea1e6d783
comparison
equal deleted inserted replaced
-1:000000000000 0:4c8ae668cc8c
1 <?php
2 /**
3 * Provide general element functions.
4 */
5 namespace Masterminds\HTML5;
6
7 /**
8 * This class provides general information about HTML5 elements,
9 * including syntactic and semantic issues.
10 * Parsers and serializers can
11 * use this class as a reference point for information about the rules
12 * of various HTML5 elements.
13 *
14 * @todo consider using a bitmask table lookup. There is enough overlap in
15 * naming that this could significantly shrink the size and maybe make it
16 * faster. See the Go teams implementation at https://code.google.com/p/go/source/browse/html/atom.
17 */
18 class Elements
19 {
20
21 /**
22 * Indicates an element is described in the specification.
23 */
24 const KNOWN_ELEMENT = 1;
25
26 // From section 8.1.2: "script", "style"
27 // From 8.2.5.4.7 ("in body" insertion mode): "noembed"
28 // From 8.4 "style", "xmp", "iframe", "noembed", "noframes"
29 /**
30 * Indicates the contained text should be processed as raw text.
31 */
32 const TEXT_RAW = 2;
33
34 // From section 8.1.2: "textarea", "title"
35 /**
36 * Indicates the contained text should be processed as RCDATA.
37 */
38 const TEXT_RCDATA = 4;
39
40 /**
41 * Indicates the tag cannot have content.
42 */
43 const VOID_TAG = 8;
44
45 // "address", "article", "aside", "blockquote", "center", "details", "dialog", "dir", "div", "dl",
46 // "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "menu",
47 // "nav", "ol", "p", "section", "summary", "ul"
48 // "h1", "h2", "h3", "h4", "h5", "h6"
49 // "pre", "listing"
50 // "form"
51 // "plaintext"
52 /**
53 * Indicates that if a previous event is for a P tag, that element
54 * should be considered closed.
55 */
56 const AUTOCLOSE_P = 16;
57
58 /**
59 * Indicates that the text inside is plaintext (pre).
60 */
61 const TEXT_PLAINTEXT = 32;
62
63 // See https://developer.mozilla.org/en-US/docs/HTML/Block-level_elements
64 /**
65 * Indicates that the tag is a block.
66 */
67 const BLOCK_TAG = 64;
68
69 /**
70 * Indicates that the tag allows only inline elements as child nodes.
71 */
72 const BLOCK_ONLY_INLINE = 128;
73
74 /**
75 * The HTML5 elements as defined in http://dev.w3.org/html5/markup/elements.html.
76 *
77 * @var array
78 */
79 public static $html5 = array(
80 "a" => 1,
81 "abbr" => 1,
82 "address" => 65, // NORMAL | BLOCK_TAG
83 "area" => 9, // NORMAL | VOID_TAG
84 "article" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
85 "aside" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
86 "audio" => 65, // NORMAL | BLOCK_TAG
87 "b" => 1,
88 "base" => 9, // NORMAL | VOID_TAG
89 "bdi" => 1,
90 "bdo" => 1,
91 "blockquote" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
92 "body" => 1,
93 "br" => 9, // NORMAL | VOID_TAG
94 "button" => 1,
95 "canvas" => 65, // NORMAL | BLOCK_TAG
96 "caption" => 1,
97 "cite" => 1,
98 "code" => 1,
99 "col" => 9, // NORMAL | VOID_TAG
100 "colgroup" => 1,
101 "command" => 9, // NORMAL | VOID_TAG
102 // "data" => 1, // This is highly experimental and only part of the whatwg spec (not w3c). See https://developer.mozilla.org/en-US/docs/HTML/Element/data
103 "datalist" => 1,
104 "dd" => 65, // NORMAL | BLOCK_TAG
105 "del" => 1,
106 "details" => 17, // NORMAL | AUTOCLOSE_P,
107 "dfn" => 1,
108 "dialog" => 17, // NORMAL | AUTOCLOSE_P,
109 "div" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
110 "dl" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
111 "dt" => 1,
112 "em" => 1,
113 "embed" => 9, // NORMAL | VOID_TAG
114 "fieldset" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
115 "figcaption" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
116 "figure" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
117 "footer" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
118 "form" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
119 "h1" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
120 "h2" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
121 "h3" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
122 "h4" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
123 "h5" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
124 "h6" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
125 "head" => 1,
126 "header" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
127 "hgroup" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
128 "hr" => 73, // NORMAL | VOID_TAG
129 "html" => 1,
130 "i" => 1,
131 "iframe" => 3, // NORMAL | TEXT_RAW
132 "img" => 9, // NORMAL | VOID_TAG
133 "input" => 9, // NORMAL | VOID_TAG
134 "kbd" => 1,
135 "ins" => 1,
136 "keygen" => 9, // NORMAL | VOID_TAG
137 "label" => 1,
138 "legend" => 1,
139 "li" => 1,
140 "link" => 9, // NORMAL | VOID_TAG
141 "map" => 1,
142 "mark" => 1,
143 "menu" => 17, // NORMAL | AUTOCLOSE_P,
144 "meta" => 9, // NORMAL | VOID_TAG
145 "meter" => 1,
146 "nav" => 17, // NORMAL | AUTOCLOSE_P,
147 "noscript" => 65, // NORMAL | BLOCK_TAG
148 "object" => 1,
149 "ol" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
150 "optgroup" => 1,
151 "option" => 1,
152 "output" => 65, // NORMAL | BLOCK_TAG
153 "p" => 209, // NORMAL | AUTOCLOSE_P | BLOCK_TAG | BLOCK_ONLY_INLINE
154 "param" => 9, // NORMAL | VOID_TAG
155 "pre" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
156 "progress" => 1,
157 "q" => 1,
158 "rp" => 1,
159 "rt" => 1,
160 "ruby" => 1,
161 "s" => 1,
162 "samp" => 1,
163 "script" => 3, // NORMAL | TEXT_RAW
164 "section" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
165 "select" => 1,
166 "small" => 1,
167 "source" => 9, // NORMAL | VOID_TAG
168 "span" => 1,
169 "strong" => 1,
170 "style" => 3, // NORMAL | TEXT_RAW
171 "sub" => 1,
172 "summary" => 17, // NORMAL | AUTOCLOSE_P,
173 "sup" => 1,
174 "table" => 65, // NORMAL | BLOCK_TAG
175 "tbody" => 1,
176 "td" => 1,
177 "textarea" => 5, // NORMAL | TEXT_RCDATA
178 "tfoot" => 65, // NORMAL | BLOCK_TAG
179 "th" => 1,
180 "thead" => 1,
181 "time" => 1,
182 "title" => 5, // NORMAL | TEXT_RCDATA
183 "tr" => 1,
184 "track" => 9, // NORMAL | VOID_TAG
185 "u" => 1,
186 "ul" => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
187 "var" => 1,
188 "video" => 65, // NORMAL | BLOCK_TAG
189 "wbr" => 9, // NORMAL | VOID_TAG
190
191 // Legacy?
192 'basefont' => 8, // VOID_TAG
193 'bgsound' => 8, // VOID_TAG
194 'noframes' => 2, // RAW_TEXT
195 'frame' => 9, // NORMAL | VOID_TAG
196 'frameset' => 1,
197 'center' => 16,
198 'dir' => 16,
199 'listing' => 16, // AUTOCLOSE_P
200 'plaintext' => 48, // AUTOCLOSE_P | TEXT_PLAINTEXT
201 'applet' => 0,
202 'marquee' => 0,
203 'isindex' => 8, // VOID_TAG
204 'xmp' => 20, // AUTOCLOSE_P | VOID_TAG | RAW_TEXT
205 'noembed' => 2 // RAW_TEXT
206 );
207
208 /**
209 * The MathML elements.
210 * See http://www.w3.org/wiki/MathML/Elements.
211 *
212 * In our case we are only concerned with presentation MathML and not content
213 * MathML. There is a nice list of this subset at https://developer.mozilla.org/en-US/docs/MathML/Element.
214 *
215 * @var array
216 */
217 public static $mathml = array(
218 "maction" => 1,
219 "maligngroup" => 1,
220 "malignmark" => 1,
221 "math" => 1,
222 "menclose" => 1,
223 "merror" => 1,
224 "mfenced" => 1,
225 "mfrac" => 1,
226 "mglyph" => 1,
227 "mi" => 1,
228 "mlabeledtr" => 1,
229 "mlongdiv" => 1,
230 "mmultiscripts" => 1,
231 "mn" => 1,
232 "mo" => 1,
233 "mover" => 1,
234 "mpadded" => 1,
235 "mphantom" => 1,
236 "mroot" => 1,
237 "mrow" => 1,
238 "ms" => 1,
239 "mscarries" => 1,
240 "mscarry" => 1,
241 "msgroup" => 1,
242 "msline" => 1,
243 "mspace" => 1,
244 "msqrt" => 1,
245 "msrow" => 1,
246 "mstack" => 1,
247 "mstyle" => 1,
248 "msub" => 1,
249 "msup" => 1,
250 "msubsup" => 1,
251 "mtable" => 1,
252 "mtd" => 1,
253 "mtext" => 1,
254 "mtr" => 1,
255 "munder" => 1,
256 "munderover" => 1
257 );
258
259 /**
260 * The svg elements.
261 *
262 * The Mozilla documentation has a good list at https://developer.mozilla.org/en-US/docs/SVG/Element.
263 * The w3c list appears to be lacking in some areas like filter effect elements.
264 * That list can be found at http://www.w3.org/wiki/SVG/Elements.
265 *
266 * Note, FireFox appears to do a better job rendering filter effects than chrome.
267 * While they are in the spec I'm not sure how widely implemented they are.
268 *
269 * @var array
270 */
271 public static $svg = array(
272 "a" => 1,
273 "altGlyph" => 1,
274 "altGlyphDef" => 1,
275 "altGlyphItem" => 1,
276 "animate" => 1,
277 "animateColor" => 1,
278 "animateMotion" => 1,
279 "animateTransform" => 1,
280 "circle" => 1,
281 "clipPath" => 1,
282 "color-profile" => 1,
283 "cursor" => 1,
284 "defs" => 1,
285 "desc" => 1,
286 "ellipse" => 1,
287 "feBlend" => 1,
288 "feColorMatrix" => 1,
289 "feComponentTransfer" => 1,
290 "feComposite" => 1,
291 "feConvolveMatrix" => 1,
292 "feDiffuseLighting" => 1,
293 "feDisplacementMap" => 1,
294 "feDistantLight" => 1,
295 "feFlood" => 1,
296 "feFuncA" => 1,
297 "feFuncB" => 1,
298 "feFuncG" => 1,
299 "feFuncR" => 1,
300 "feGaussianBlur" => 1,
301 "feImage" => 1,
302 "feMerge" => 1,
303 "feMergeNode" => 1,
304 "feMorphology" => 1,
305 "feOffset" => 1,
306 "fePointLight" => 1,
307 "feSpecularLighting" => 1,
308 "feSpotLight" => 1,
309 "feTile" => 1,
310 "feTurbulence" => 1,
311 "filter" => 1,
312 "font" => 1,
313 "font-face" => 1,
314 "font-face-format" => 1,
315 "font-face-name" => 1,
316 "font-face-src" => 1,
317 "font-face-uri" => 1,
318 "foreignObject" => 1,
319 "g" => 1,
320 "glyph" => 1,
321 "glyphRef" => 1,
322 "hkern" => 1,
323 "image" => 1,
324 "line" => 1,
325 "linearGradient" => 1,
326 "marker" => 1,
327 "mask" => 1,
328 "metadata" => 1,
329 "missing-glyph" => 1,
330 "mpath" => 1,
331 "path" => 1,
332 "pattern" => 1,
333 "polygon" => 1,
334 "polyline" => 1,
335 "radialGradient" => 1,
336 "rect" => 1,
337 "script" => 3, // NORMAL | RAW_TEXT
338 "set" => 1,
339 "stop" => 1,
340 "style" => 3, // NORMAL | RAW_TEXT
341 "svg" => 1,
342 "switch" => 1,
343 "symbol" => 1,
344 "text" => 1,
345 "textPath" => 1,
346 "title" => 1,
347 "tref" => 1,
348 "tspan" => 1,
349 "use" => 1,
350 "view" => 1,
351 "vkern" => 1
352 );
353
354 /**
355 * Some attributes in SVG are case sensetitive.
356 *
357 * This map contains key/value pairs with the key as the lowercase attribute
358 * name and the value with the correct casing.
359 */
360 public static $svgCaseSensitiveAttributeMap = array(
361 'attributename' => 'attributeName',
362 'attributetype' => 'attributeType',
363 'basefrequency' => 'baseFrequency',
364 'baseprofile' => 'baseProfile',
365 'calcmode' => 'calcMode',
366 'clippathunits' => 'clipPathUnits',
367 'contentscripttype' => 'contentScriptType',
368 'contentstyletype' => 'contentStyleType',
369 'diffuseconstant' => 'diffuseConstant',
370 'edgemode' => 'edgeMode',
371 'externalresourcesrequired' => 'externalResourcesRequired',
372 'filterres' => 'filterRes',
373 'filterunits' => 'filterUnits',
374 'glyphref' => 'glyphRef',
375 'gradienttransform' => 'gradientTransform',
376 'gradientunits' => 'gradientUnits',
377 'kernelmatrix' => 'kernelMatrix',
378 'kernelunitlength' => 'kernelUnitLength',
379 'keypoints' => 'keyPoints',
380 'keysplines' => 'keySplines',
381 'keytimes' => 'keyTimes',
382 'lengthadjust' => 'lengthAdjust',
383 'limitingconeangle' => 'limitingConeAngle',
384 'markerheight' => 'markerHeight',
385 'markerunits' => 'markerUnits',
386 'markerwidth' => 'markerWidth',
387 'maskcontentunits' => 'maskContentUnits',
388 'maskunits' => 'maskUnits',
389 'numoctaves' => 'numOctaves',
390 'pathlength' => 'pathLength',
391 'patterncontentunits' => 'patternContentUnits',
392 'patterntransform' => 'patternTransform',
393 'patternunits' => 'patternUnits',
394 'pointsatx' => 'pointsAtX',
395 'pointsaty' => 'pointsAtY',
396 'pointsatz' => 'pointsAtZ',
397 'preservealpha' => 'preserveAlpha',
398 'preserveaspectratio' => 'preserveAspectRatio',
399 'primitiveunits' => 'primitiveUnits',
400 'refx' => 'refX',
401 'refy' => 'refY',
402 'repeatcount' => 'repeatCount',
403 'repeatdur' => 'repeatDur',
404 'requiredextensions' => 'requiredExtensions',
405 'requiredfeatures' => 'requiredFeatures',
406 'specularconstant' => 'specularConstant',
407 'specularexponent' => 'specularExponent',
408 'spreadmethod' => 'spreadMethod',
409 'startoffset' => 'startOffset',
410 'stddeviation' => 'stdDeviation',
411 'stitchtiles' => 'stitchTiles',
412 'surfacescale' => 'surfaceScale',
413 'systemlanguage' => 'systemLanguage',
414 'tablevalues' => 'tableValues',
415 'targetx' => 'targetX',
416 'targety' => 'targetY',
417 'textlength' => 'textLength',
418 'viewbox' => 'viewBox',
419 'viewtarget' => 'viewTarget',
420 'xchannelselector' => 'xChannelSelector',
421 'ychannelselector' => 'yChannelSelector',
422 'zoomandpan' => 'zoomAndPan'
423 );
424
425 /**
426 * Some SVG elements are case sensetitive.
427 * This map contains these.
428 *
429 * The map contains key/value store of the name is lowercase as the keys and
430 * the correct casing as the value.
431 */
432 public static $svgCaseSensitiveElementMap = array(
433 'altglyph' => 'altGlyph',
434 'altglyphdef' => 'altGlyphDef',
435 'altglyphitem' => 'altGlyphItem',
436 'animatecolor' => 'animateColor',
437 'animatemotion' => 'animateMotion',
438 'animatetransform' => 'animateTransform',
439 'clippath' => 'clipPath',
440 'feblend' => 'feBlend',
441 'fecolormatrix' => 'feColorMatrix',
442 'fecomponenttransfer' => 'feComponentTransfer',
443 'fecomposite' => 'feComposite',
444 'feconvolvematrix' => 'feConvolveMatrix',
445 'fediffuselighting' => 'feDiffuseLighting',
446 'fedisplacementmap' => 'feDisplacementMap',
447 'fedistantlight' => 'feDistantLight',
448 'feflood' => 'feFlood',
449 'fefunca' => 'feFuncA',
450 'fefuncb' => 'feFuncB',
451 'fefuncg' => 'feFuncG',
452 'fefuncr' => 'feFuncR',
453 'fegaussianblur' => 'feGaussianBlur',
454 'feimage' => 'feImage',
455 'femerge' => 'feMerge',
456 'femergenode' => 'feMergeNode',
457 'femorphology' => 'feMorphology',
458 'feoffset' => 'feOffset',
459 'fepointlight' => 'fePointLight',
460 'fespecularlighting' => 'feSpecularLighting',
461 'fespotlight' => 'feSpotLight',
462 'fetile' => 'feTile',
463 'feturbulence' => 'feTurbulence',
464 'foreignobject' => 'foreignObject',
465 'glyphref' => 'glyphRef',
466 'lineargradient' => 'linearGradient',
467 'radialgradient' => 'radialGradient',
468 'textpath' => 'textPath'
469 );
470
471 /**
472 * Check whether the given element meets the given criterion.
473 *
474 * Example:
475 *
476 * Elements::isA('script', Elements::TEXT_RAW); // Returns true.
477 *
478 * Elements::isA('script', Elements::TEXT_RCDATA); // Returns false.
479 *
480 * @param string $name
481 * The element name.
482 * @param int $mask
483 * One of the constants on this class.
484 * @return boolean true if the element matches the mask, false otherwise.
485 */
486 public static function isA($name, $mask)
487 {
488 if (! static::isElement($name)) {
489 return false;
490 }
491
492 return (static::element($name) & $mask) == $mask;
493 }
494
495 /**
496 * Test if an element is a valid html5 element.
497 *
498 * @param string $name
499 * The name of the element.
500 *
501 * @return bool True if a html5 element and false otherwise.
502 */
503 public static function isHtml5Element($name)
504 {
505 // html5 element names are case insensetitive. Forcing lowercase for the check.
506 // Do we need this check or will all data passed here already be lowercase?
507 return isset(static::$html5[strtolower($name)]);
508 }
509
510 /**
511 * Test if an element name is a valid MathML presentation element.
512 *
513 * @param string $name
514 * The name of the element.
515 *
516 * @return bool True if a MathML name and false otherwise.
517 */
518 public static function isMathMLElement($name)
519 {
520 // MathML is case-sensetitive unlike html5 elements.
521 return isset(static::$mathml[$name]);
522 }
523
524 /**
525 * Test if an element is a valid SVG element.
526 *
527 * @param string $name
528 * The name of the element.
529 *
530 * @return boolean True if a SVG element and false otherise.
531 */
532 public static function isSvgElement($name)
533 {
534 // SVG is case-sensetitive unlike html5 elements.
535 return isset(static::$svg[$name]);
536 }
537
538 /**
539 * Is an element name valid in an html5 document.
540 *
541 * This includes html5 elements along with other allowed embedded content
542 * such as svg and mathml.
543 *
544 * @param string $name
545 * The name of the element.
546 *
547 * @return bool True if valid and false otherwise.
548 */
549 public static function isElement($name)
550 {
551 return static::isHtml5Element($name) || static::isMathMLElement($name) || static::isSvgElement($name);
552 }
553
554 /**
555 * Get the element mask for the given element name.
556 *
557 * @param string $name
558 * The name of the element.
559 *
560 * @return int|bool The element mask or false if element does not exist.
561 */
562 public static function element($name)
563 {
564 if (isset(static::$html5[$name])) {
565 return static::$html5[$name];
566 }
567 if (isset(static::$svg[$name])) {
568 return static::$svg[$name];
569 }
570 if (isset(static::$mathml[$name])) {
571 return static::$mathml[$name];
572 }
573
574 return false;
575 }
576
577 /**
578 * Normalize a SVG element name to its proper case and form.
579 *
580 * @param string $name
581 * The name of the element.
582 *
583 * @return string The normalized form of the element name.
584 */
585 public static function normalizeSvgElement($name)
586 {
587 $name = strtolower($name);
588 if (isset(static::$svgCaseSensitiveElementMap[$name])) {
589 $name = static::$svgCaseSensitiveElementMap[$name];
590 }
591
592 return $name;
593 }
594
595 /**
596 * Normalize a SVG attribute name to its proper case and form.
597 *
598 * @param string $name
599 * The name of the attribute.
600 *
601 * @return string The normalized form of the attribute name.
602 */
603 public static function normalizeSvgAttribute($name)
604 {
605 $name = strtolower($name);
606 if (isset(static::$svgCaseSensitiveAttributeMap[$name])) {
607 $name = static::$svgCaseSensitiveAttributeMap[$name];
608 }
609
610 return $name;
611 }
612
613 /**
614 * Normalize a MathML attribute name to its proper case and form.
615 *
616 * Note, all MathML element names are lowercase.
617 *
618 * @param string $name
619 * The name of the attribute.
620 *
621 * @return string The normalized form of the attribute name.
622 */
623 public static function normalizeMathMlAttribute($name)
624 {
625 $name = strtolower($name);
626
627 // Only one attribute has a mixed case form for MathML.
628 if ($name == 'definitionurl') {
629 $name = 'definitionURL';
630 }
631
632 return $name;
633 }
634 }