1<?php 2namespace dokuwiki\Form; 3 4/** 5 * Class Form 6 * 7 * Represents the whole Form. This is what you work on, and add Elements to 8 * 9 * @package dokuwiki\Form 10 */ 11class Form extends Element { 12 13 /** 14 * @var array name value pairs for hidden values 15 */ 16 protected $hidden = array(); 17 18 /** 19 * @var Element[] the elements of the form 20 */ 21 protected $elements = array(); 22 23 /** 24 * Creates a new, empty form with some default attributes 25 * 26 * @param array $attributes 27 */ 28 public function __construct($attributes = array()) { 29 global $ID; 30 31 parent::__construct('form', $attributes); 32 33 // use the current URL as default action 34 if(!$this->attr('action')) { 35 $get = $_GET; 36 if(isset($get['id'])) unset($get['id']); 37 $self = wl($ID, $get, false, '&'); //attributes are escaped later 38 $this->attr('action', $self); 39 } 40 41 // post is default 42 if(!$this->attr('method')) { 43 $this->attr('method', 'post'); 44 } 45 46 // we like UTF-8 47 if(!$this->attr('accept-charset')) { 48 $this->attr('accept-charset', 'utf-8'); 49 } 50 51 // add the security token by default 52 $this->setHiddenField('sectok', getSecurityToken()); 53 54 // identify this as a new form based form in HTML 55 $this->addClass('doku_form'); 56 } 57 58 /** 59 * Sets a hidden field 60 * 61 * @param $name 62 * @param $value 63 * @return $this 64 */ 65 public function setHiddenField($name, $value) { 66 $this->hidden[$name] = $value; 67 return $this; 68 } 69 70 #region Element adding functions 71 72 /** 73 * Adds an element to the end of the form 74 * 75 * @param Element $element 76 * @param int $pos 0-based position in the form, -1 for at the end 77 * @return Element 78 */ 79 public function addElement(Element $element, $pos = -1) { 80 if(is_a($element, 'Doku_Form2')) throw new \InvalidArgumentException('You can\'t add a form to a form'); 81 if($pos < 0) { 82 $this->elements[] = $element; 83 } else { 84 array_splice($this->elements, $pos, 0, array($element)); 85 } 86 return $element; 87 } 88 89 /** 90 * Adds a text input field 91 * 92 * @param $name 93 * @param $label 94 * @param int $pos 95 * @return InputElement 96 */ 97 public function addTextInput($name, $label = '', $pos = -1) { 98 return $this->addElement(new InputElement('text', $name, $label), $pos); 99 } 100 101 /** 102 * Adds a password input field 103 * 104 * @param $name 105 * @param $label 106 * @param int $pos 107 * @return InputElement 108 */ 109 public function addPasswordInput($name, $label = '', $pos = -1) { 110 return $this->addElement(new InputElement('password', $name, $label), $pos); 111 } 112 113 /** 114 * Adds a radio button field 115 * 116 * @param $name 117 * @param $label 118 * @param int $pos 119 * @return CheckableElement 120 */ 121 public function addRadioButton($name, $label = '', $pos = -1) { 122 return $this->addElement(new CheckableElement('radio', $name, $label), $pos); 123 } 124 125 /** 126 * Adds a checkbox field 127 * 128 * @param $name 129 * @param $label 130 * @param int $pos 131 * @return CheckableElement 132 */ 133 public function addCheckbox($name, $label = '', $pos = -1) { 134 return $this->addElement(new CheckableElement('checkbox', $name, $label), $pos); 135 } 136 137 /** 138 * Adds a textarea field 139 * 140 * @param $name 141 * @param $label 142 * @param int $pos 143 * @return TextareaElement 144 */ 145 public function addTextarea($name, $label = '', $pos = -1) { 146 return $this->addElement(new TextareaElement($name, $label), $pos); 147 } 148 149 /** 150 * Add fixed HTML to the form 151 * 152 * @param $html 153 * @param int $pos 154 * @return HTMLElement 155 */ 156 public function addHTML($html, $pos = -1) { 157 return $this->addElement(new HTMLElement($html), $pos); 158 } 159 160 /** 161 * Add a closed HTML tag to the form 162 * 163 * @param $tag 164 * @param int $pos 165 * @return TagElement 166 */ 167 public function addTag($tag, $pos = -1) { 168 return $this->addElement(new TagElement($tag), $pos); 169 } 170 171 /** 172 * Add an open HTML tag to the form 173 * 174 * Be sure to close it again! 175 * 176 * @param $tag 177 * @param int $pos 178 * @return TagOpenElement 179 */ 180 public function addTagOpen($tag, $pos = -1) { 181 return $this->addElement(new TagOpenElement($tag), $pos); 182 } 183 184 /** 185 * Add a closing HTML tag to the form 186 * 187 * Be sure it had been opened before 188 * 189 * @param $tag 190 * @param int $pos 191 * @return TagCloseElement 192 */ 193 public function addTagClose($tag, $pos = -1) { 194 return $this->addElement(new TagCloseElement($tag), $pos); 195 } 196 197 /** 198 * Open a Fieldset 199 * 200 * @param $legend 201 * @param int $pos 202 * @return FieldsetOpenElement 203 */ 204 public function addFieldsetOpen($legend = '', $pos = -1) { 205 return $this->addElement(new FieldsetOpenElement($legend), $pos); 206 } 207 208 /** 209 * Close a fieldset 210 * 211 * @param int $pos 212 * @return TagCloseElement 213 */ 214 public function addFieldsetClose($pos = -1) { 215 return $this->addElement(new FieldsetCloseElement(), $pos); 216 } 217 218 #endregion 219 220 /** 221 * Adjust the elements so that fieldset open and closes are matching 222 */ 223 protected function balanceFieldsets() { 224 $lastclose = 0; 225 $isopen = false; 226 $len = count($this->elements); 227 228 for($pos = 0; $pos < $len; $pos++) { 229 $type = $this->elements[$pos]->getType(); 230 if($type == 'fieldsetopen') { 231 if($isopen) { 232 //close previous feldset 233 $this->addFieldsetClose($pos); 234 $lastclose = $pos + 1; 235 $pos++; 236 $len++; 237 } 238 $isopen = true; 239 } else if($type == 'fieldsetclose') { 240 if(!$isopen) { 241 // make sure there was a fieldsetopen 242 // either right after the last close or at the begining 243 $this->addFieldsetOpen('', $lastclose); 244 $len++; 245 $pos++; 246 } 247 $lastclose = $pos; 248 $isopen = false; 249 } 250 } 251 252 // close open fieldset at the end 253 if($isopen) { 254 $this->addFieldsetClose(); 255 } 256 } 257 258 /** 259 * The HTML representation of the whole form 260 * 261 * @return string 262 */ 263 public function toHTML() { 264 $this->balanceFieldsets(); 265 266 $html = '<form ' . buildAttributes($this->attrs()) . '>' . DOKU_LF; 267 268 foreach($this->hidden as $name => $value) { 269 $html .= '<input type="hidden" name="' . $name . '" value="' . formText($value) . '" />' . DOKU_LF; 270 } 271 272 foreach($this->elements as $element) { 273 $html .= $element->toHTML() . DOKU_LF; 274 } 275 276 $html .= '</form>' . DOKU_LF; 277 278 return $html; 279 } 280} 281