Forms.php 5.7 KB

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