0e880e7f693507e58f555388b985476ac1268829
[yaffs-website] / vendor / masterminds / html5 / src / HTML5 / Elements.php
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 }