1<?php
2
3/**
4 * XHTML 1.1 Forms module, defines all form-related elements found in HTML 4.
5 */
6class HTMLPurifier_HTMLModule_Forms extends HTMLPurifier_HTMLModule
7{
8    /**
9     * @type string
10     */
11    public $name = 'Forms';
12
13    /**
14     * @type bool
15     */
16    public $safe = false;
17
18    /**
19     * @type array
20     */
21    public $content_sets = array(
22        'Block' => 'Form',
23        'Inline' => 'Formctrl',
24    );
25
26    /**
27     * @param HTMLPurifier_Config $config
28     */
29    public function setup($config)
30    {
31        if ($config->get('HTML.Forms')) {
32            $this->safe = true;
33        }
34
35        $form = $this->addElement(
36            'form',
37            'Form',
38            'Required: Heading | List | Block | fieldset',
39            'Common',
40            array(
41                'accept' => 'ContentTypes',
42                'accept-charset' => 'Charsets',
43                'action*' => 'URI',
44                'method' => 'Enum#get,post',
45                // really ContentType, but these two are the only ones used today
46                'enctype' => 'Enum#application/x-www-form-urlencoded,multipart/form-data',
47            )
48        );
49        $form->excludes = array('form' => true);
50
51        $input = $this->addElement(
52            'input',
53            'Formctrl',
54            'Empty',
55            'Common',
56            array(
57                'accept' => 'ContentTypes',
58                'accesskey' => 'Character',
59                'alt' => 'Text',
60                'checked' => 'Bool#checked',
61                'disabled' => 'Bool#disabled',
62                'maxlength' => 'Number',
63                'name' => 'CDATA',
64                'readonly' => 'Bool#readonly',
65                'size' => 'Number',
66                'src' => 'URI#embedded',
67                'tabindex' => 'Number',
68                'type' => 'Enum#text,password,checkbox,button,radio,submit,reset,file,hidden,image',
69                'value' => 'CDATA',
70            )
71        );
72        $input->attr_transform_post[] = new HTMLPurifier_AttrTransform_Input();
73
74        $this->addElement(
75            'select',
76            'Formctrl',
77            'Required: optgroup | option',
78            'Common',
79            array(
80                'disabled' => 'Bool#disabled',
81                'multiple' => 'Bool#multiple',
82                'name' => 'CDATA',
83                'size' => 'Number',
84                'tabindex' => 'Number',
85            )
86        );
87
88        $this->addElement(
89            'option',
90            false,
91            'Optional: #PCDATA',
92            'Common',
93            array(
94                'disabled' => 'Bool#disabled',
95                'label' => 'Text',
96                'selected' => 'Bool#selected',
97                'value' => 'CDATA',
98            )
99        );
100        // It's illegal for there to be more than one selected, but not
101        // be multiple. Also, no selected means undefined behavior. This might
102        // be difficult to implement; perhaps an injector, or a context variable.
103
104        $textarea = $this->addElement(
105            'textarea',
106            'Formctrl',
107            'Optional: #PCDATA',
108            'Common',
109            array(
110                'accesskey' => 'Character',
111                'cols*' => 'Number',
112                'disabled' => 'Bool#disabled',
113                'name' => 'CDATA',
114                'readonly' => 'Bool#readonly',
115                'rows*' => 'Number',
116                'tabindex' => 'Number',
117            )
118        );
119        $textarea->attr_transform_pre[] = new HTMLPurifier_AttrTransform_Textarea();
120
121        $button = $this->addElement(
122            'button',
123            'Formctrl',
124            'Optional: #PCDATA | Heading | List | Block | Inline',
125            'Common',
126            array(
127                'accesskey' => 'Character',
128                'disabled' => 'Bool#disabled',
129                'name' => 'CDATA',
130                'tabindex' => 'Number',
131                'type' => 'Enum#button,submit,reset',
132                'value' => 'CDATA',
133            )
134        );
135
136        // For exclusions, ideally we'd specify content sets, not literal elements
137        $button->excludes = $this->makeLookup(
138            'form',
139            'fieldset', // Form
140            'input',
141            'select',
142            'textarea',
143            'label',
144            'button', // Formctrl
145            'a', // as per HTML 4.01 spec, this is omitted by modularization
146            'isindex',
147            'iframe' // legacy items
148        );
149
150        // Extra exclusion: img usemap="" is not permitted within this element.
151        // We'll omit this for now, since we don't have any good way of
152        // indicating it yet.
153
154        // This is HIGHLY user-unfriendly; we need a custom child-def for this
155        $this->addElement('fieldset', 'Form', 'Custom: (#WS?,legend,(Flow|#PCDATA)*)', 'Common');
156
157        $label = $this->addElement(
158            'label',
159            'Formctrl',
160            'Optional: #PCDATA | Inline',
161            'Common',
162            array(
163                'accesskey' => 'Character',
164                // 'for' => 'IDREF', // IDREF not implemented, cannot allow
165            )
166        );
167        $label->excludes = array('label' => true);
168
169        $this->addElement(
170            'legend',
171            false,
172            'Optional: #PCDATA | Inline',
173            'Common',
174            array(
175                'accesskey' => 'Character',
176            )
177        );
178
179        $this->addElement(
180            'optgroup',
181            false,
182            'Required: option',
183            'Common',
184            array(
185                'disabled' => 'Bool#disabled',
186                'label*' => 'Text',
187            )
188        );
189        // Don't forget an injector for <isindex>. This one's a little complex
190        // because it maps to multiple elements.
191    }
192}
193
194// vim: et sw=4 sts=4
195