Yaffs site version 1.1
[yaffs-website] / vendor / ezyang / htmlpurifier / library / HTMLPurifier / ElementDef.php
1 <?php
2
3 /**
4  * Structure that stores an HTML element definition. Used by
5  * HTMLPurifier_HTMLDefinition and HTMLPurifier_HTMLModule.
6  * @note This class is inspected by HTMLPurifier_Printer_HTMLDefinition.
7  *       Please update that class too.
8  * @warning If you add new properties to this class, you MUST update
9  *          the mergeIn() method.
10  */
11 class HTMLPurifier_ElementDef
12 {
13     /**
14      * Does the definition work by itself, or is it created solely
15      * for the purpose of merging into another definition?
16      * @type bool
17      */
18     public $standalone = true;
19
20     /**
21      * Associative array of attribute name to HTMLPurifier_AttrDef.
22      * @type array
23      * @note Before being processed by HTMLPurifier_AttrCollections
24      *       when modules are finalized during
25      *       HTMLPurifier_HTMLDefinition->setup(), this array may also
26      *       contain an array at index 0 that indicates which attribute
27      *       collections to load into the full array. It may also
28      *       contain string indentifiers in lieu of HTMLPurifier_AttrDef,
29      *       see HTMLPurifier_AttrTypes on how they are expanded during
30      *       HTMLPurifier_HTMLDefinition->setup() processing.
31      */
32     public $attr = array();
33
34     // XXX: Design note: currently, it's not possible to override
35     // previously defined AttrTransforms without messing around with
36     // the final generated config. This is by design; a previous version
37     // used an associated list of attr_transform, but it was extremely
38     // easy to accidentally override other attribute transforms by
39     // forgetting to specify an index (and just using 0.)  While we
40     // could check this by checking the index number and complaining,
41     // there is a second problem which is that it is not at all easy to
42     // tell when something is getting overridden. Combine this with a
43     // codebase where this isn't really being used, and it's perfect for
44     // nuking.
45
46     /**
47      * List of tags HTMLPurifier_AttrTransform to be done before validation.
48      * @type array
49      */
50     public $attr_transform_pre = array();
51
52     /**
53      * List of tags HTMLPurifier_AttrTransform to be done after validation.
54      * @type array
55      */
56     public $attr_transform_post = array();
57
58     /**
59      * HTMLPurifier_ChildDef of this tag.
60      * @type HTMLPurifier_ChildDef
61      */
62     public $child;
63
64     /**
65      * Abstract string representation of internal ChildDef rules.
66      * @see HTMLPurifier_ContentSets for how this is parsed and then transformed
67      * into an HTMLPurifier_ChildDef.
68      * @warning This is a temporary variable that is not available after
69      *      being processed by HTMLDefinition
70      * @type string
71      */
72     public $content_model;
73
74     /**
75      * Value of $child->type, used to determine which ChildDef to use,
76      * used in combination with $content_model.
77      * @warning This must be lowercase
78      * @warning This is a temporary variable that is not available after
79      *      being processed by HTMLDefinition
80      * @type string
81      */
82     public $content_model_type;
83
84     /**
85      * Does the element have a content model (#PCDATA | Inline)*? This
86      * is important for chameleon ins and del processing in
87      * HTMLPurifier_ChildDef_Chameleon. Dynamically set: modules don't
88      * have to worry about this one.
89      * @type bool
90      */
91     public $descendants_are_inline = false;
92
93     /**
94      * List of the names of required attributes this element has.
95      * Dynamically populated by HTMLPurifier_HTMLDefinition::getElement()
96      * @type array
97      */
98     public $required_attr = array();
99
100     /**
101      * Lookup table of tags excluded from all descendants of this tag.
102      * @type array
103      * @note SGML permits exclusions for all descendants, but this is
104      *       not possible with DTDs or XML Schemas. W3C has elected to
105      *       use complicated compositions of content_models to simulate
106      *       exclusion for children, but we go the simpler, SGML-style
107      *       route of flat-out exclusions, which correctly apply to
108      *       all descendants and not just children. Note that the XHTML
109      *       Modularization Abstract Modules are blithely unaware of such
110      *       distinctions.
111      */
112     public $excludes = array();
113
114     /**
115      * This tag is explicitly auto-closed by the following tags.
116      * @type array
117      */
118     public $autoclose = array();
119
120     /**
121      * If a foreign element is found in this element, test if it is
122      * allowed by this sub-element; if it is, instead of closing the
123      * current element, place it inside this element.
124      * @type string
125      */
126     public $wrap;
127
128     /**
129      * Whether or not this is a formatting element affected by the
130      * "Active Formatting Elements" algorithm.
131      * @type bool
132      */
133     public $formatting;
134
135     /**
136      * Low-level factory constructor for creating new standalone element defs
137      */
138     public static function create($content_model, $content_model_type, $attr)
139     {
140         $def = new HTMLPurifier_ElementDef();
141         $def->content_model = $content_model;
142         $def->content_model_type = $content_model_type;
143         $def->attr = $attr;
144         return $def;
145     }
146
147     /**
148      * Merges the values of another element definition into this one.
149      * Values from the new element def take precedence if a value is
150      * not mergeable.
151      * @param HTMLPurifier_ElementDef $def
152      */
153     public function mergeIn($def)
154     {
155         // later keys takes precedence
156         foreach ($def->attr as $k => $v) {
157             if ($k === 0) {
158                 // merge in the includes
159                 // sorry, no way to override an include
160                 foreach ($v as $v2) {
161                     $this->attr[0][] = $v2;
162                 }
163                 continue;
164             }
165             if ($v === false) {
166                 if (isset($this->attr[$k])) {
167                     unset($this->attr[$k]);
168                 }
169                 continue;
170             }
171             $this->attr[$k] = $v;
172         }
173         $this->_mergeAssocArray($this->excludes, $def->excludes);
174         $this->attr_transform_pre = array_merge($this->attr_transform_pre, $def->attr_transform_pre);
175         $this->attr_transform_post = array_merge($this->attr_transform_post, $def->attr_transform_post);
176
177         if (!empty($def->content_model)) {
178             $this->content_model =
179                 str_replace("#SUPER", $this->content_model, $def->content_model);
180             $this->child = false;
181         }
182         if (!empty($def->content_model_type)) {
183             $this->content_model_type = $def->content_model_type;
184             $this->child = false;
185         }
186         if (!is_null($def->child)) {
187             $this->child = $def->child;
188         }
189         if (!is_null($def->formatting)) {
190             $this->formatting = $def->formatting;
191         }
192         if ($def->descendants_are_inline) {
193             $this->descendants_are_inline = $def->descendants_are_inline;
194         }
195     }
196
197     /**
198      * Merges one array into another, removes values which equal false
199      * @param $a1 Array by reference that is merged into
200      * @param $a2 Array that merges into $a1
201      */
202     private function _mergeAssocArray(&$a1, $a2)
203     {
204         foreach ($a2 as $k => $v) {
205             if ($v === false) {
206                 if (isset($a1[$k])) {
207                     unset($a1[$k]);
208                 }
209                 continue;
210             }
211             $a1[$k] = $v;
212         }
213     }
214 }
215
216 // vim: et sw=4 sts=4