1: <?php
2:
3: /**
4: * XHTML 1.1 Forms module, defines all form-related elements found in HTML 4.
5: */
6: class 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: