112a4e4d1SAndreas Gohr<?php 212a4e4d1SAndreas Gohrnamespace dokuwiki\Form; 312a4e4d1SAndreas Gohr 412a4e4d1SAndreas Gohr/** 512a4e4d1SAndreas Gohr * Class Form 612a4e4d1SAndreas Gohr * 712a4e4d1SAndreas Gohr * Represents the whole Form. This is what you work on, and add Elements to 812a4e4d1SAndreas Gohr * 912a4e4d1SAndreas Gohr * @package dokuwiki\Form 1012a4e4d1SAndreas Gohr */ 1112a4e4d1SAndreas Gohrclass Form extends Element { 1212a4e4d1SAndreas Gohr 1312a4e4d1SAndreas Gohr /** 1412a4e4d1SAndreas Gohr * @var array name value pairs for hidden values 1512a4e4d1SAndreas Gohr */ 1612a4e4d1SAndreas Gohr protected $hidden = array(); 1712a4e4d1SAndreas Gohr 1812a4e4d1SAndreas Gohr /** 1912a4e4d1SAndreas Gohr * @var Element[] the elements of the form 2012a4e4d1SAndreas Gohr */ 2112a4e4d1SAndreas Gohr protected $elements = array(); 2212a4e4d1SAndreas Gohr 2312a4e4d1SAndreas Gohr /** 2412a4e4d1SAndreas Gohr * Creates a new, empty form with some default attributes 2512a4e4d1SAndreas Gohr * 2612a4e4d1SAndreas Gohr * @param array $attributes 2712a4e4d1SAndreas Gohr */ 2812a4e4d1SAndreas Gohr public function __construct($attributes = array()) { 2912a4e4d1SAndreas Gohr global $ID; 3012a4e4d1SAndreas Gohr 3112a4e4d1SAndreas Gohr parent::__construct('form', $attributes); 3212a4e4d1SAndreas Gohr 3312a4e4d1SAndreas Gohr // use the current URL as default action 3412a4e4d1SAndreas Gohr if(!$this->attr('action')) { 3512a4e4d1SAndreas Gohr $get = $_GET; 3612a4e4d1SAndreas Gohr if(isset($get['id'])) unset($get['id']); 376d0ceaf9SAndreas Gohr $self = wl($ID, $get, false, '&'); //attributes are escaped later 3812a4e4d1SAndreas Gohr $this->attr('action', $self); 3912a4e4d1SAndreas Gohr } 4012a4e4d1SAndreas Gohr 4112a4e4d1SAndreas Gohr // post is default 4212a4e4d1SAndreas Gohr if(!$this->attr('method')) { 4312a4e4d1SAndreas Gohr $this->attr('method', 'post'); 4412a4e4d1SAndreas Gohr } 4512a4e4d1SAndreas Gohr 4612a4e4d1SAndreas Gohr // we like UTF-8 4712a4e4d1SAndreas Gohr if(!$this->attr('accept-charset')) { 4812a4e4d1SAndreas Gohr $this->attr('accept-charset', 'utf-8'); 4912a4e4d1SAndreas Gohr } 5012a4e4d1SAndreas Gohr 5112a4e4d1SAndreas Gohr // add the security token by default 5212a4e4d1SAndreas Gohr $this->setHiddenField('sectok', getSecurityToken()); 5312a4e4d1SAndreas Gohr 546d0ceaf9SAndreas Gohr // identify this as a new form based form in HTML 556d0ceaf9SAndreas Gohr $this->addClass('doku_form'); 5612a4e4d1SAndreas Gohr } 5712a4e4d1SAndreas Gohr 5812a4e4d1SAndreas Gohr /** 5912a4e4d1SAndreas Gohr * Sets a hidden field 6012a4e4d1SAndreas Gohr * 6112a4e4d1SAndreas Gohr * @param $name 6212a4e4d1SAndreas Gohr * @param $value 6312a4e4d1SAndreas Gohr * @return $this 6412a4e4d1SAndreas Gohr */ 6512a4e4d1SAndreas Gohr public function setHiddenField($name, $value) { 6612a4e4d1SAndreas Gohr $this->hidden[$name] = $value; 6712a4e4d1SAndreas Gohr return $this; 6812a4e4d1SAndreas Gohr } 6912a4e4d1SAndreas Gohr 7064744a10SAndreas Gohr #region Element adding functions 7164744a10SAndreas Gohr 7212a4e4d1SAndreas Gohr /** 7312a4e4d1SAndreas Gohr * Adds an element to the end of the form 7412a4e4d1SAndreas Gohr * 7512a4e4d1SAndreas Gohr * @param Element $element 7612a4e4d1SAndreas Gohr * @param int $pos 0-based position in the form, -1 for at the end 7712a4e4d1SAndreas Gohr * @return Element 7812a4e4d1SAndreas Gohr */ 7912a4e4d1SAndreas Gohr public function addElement(Element $element, $pos = -1) { 8012a4e4d1SAndreas Gohr if(is_a($element, 'Doku_Form2')) throw new \InvalidArgumentException('You can\'t add a form to a form'); 8112a4e4d1SAndreas Gohr if($pos < 0) { 8212a4e4d1SAndreas Gohr $this->elements[] = $element; 8312a4e4d1SAndreas Gohr } else { 8412a4e4d1SAndreas Gohr array_splice($this->elements, $pos, 0, array($element)); 8512a4e4d1SAndreas Gohr } 8612a4e4d1SAndreas Gohr return $element; 8712a4e4d1SAndreas Gohr } 8812a4e4d1SAndreas Gohr 8912a4e4d1SAndreas Gohr /** 9012a4e4d1SAndreas Gohr * Adds a text input field 9112a4e4d1SAndreas Gohr * 9212a4e4d1SAndreas Gohr * @param $name 9312a4e4d1SAndreas Gohr * @param $label 9412a4e4d1SAndreas Gohr * @param int $pos 9512a4e4d1SAndreas Gohr * @return InputElement 9612a4e4d1SAndreas Gohr */ 97de19515fSAndreas Gohr public function addTextInput($name, $label = '', $pos = -1) { 9812a4e4d1SAndreas Gohr return $this->addElement(new InputElement('text', $name, $label), $pos); 9912a4e4d1SAndreas Gohr } 10012a4e4d1SAndreas Gohr 10112a4e4d1SAndreas Gohr /** 10212a4e4d1SAndreas Gohr * Adds a password input field 10312a4e4d1SAndreas Gohr * 10412a4e4d1SAndreas Gohr * @param $name 10512a4e4d1SAndreas Gohr * @param $label 10612a4e4d1SAndreas Gohr * @param int $pos 10712a4e4d1SAndreas Gohr * @return InputElement 10812a4e4d1SAndreas Gohr */ 109de19515fSAndreas Gohr public function addPasswordInput($name, $label = '', $pos = -1) { 11012a4e4d1SAndreas Gohr return $this->addElement(new InputElement('password', $name, $label), $pos); 11112a4e4d1SAndreas Gohr } 11212a4e4d1SAndreas Gohr 11312a4e4d1SAndreas Gohr /** 11412a4e4d1SAndreas Gohr * Adds a radio button field 11512a4e4d1SAndreas Gohr * 11612a4e4d1SAndreas Gohr * @param $name 11712a4e4d1SAndreas Gohr * @param $label 11812a4e4d1SAndreas Gohr * @param int $pos 11912a4e4d1SAndreas Gohr * @return CheckableElement 12012a4e4d1SAndreas Gohr */ 121de19515fSAndreas Gohr public function addRadioButton($name, $label = '', $pos = -1) { 12212a4e4d1SAndreas Gohr return $this->addElement(new CheckableElement('radio', $name, $label), $pos); 12312a4e4d1SAndreas Gohr } 12412a4e4d1SAndreas Gohr 12512a4e4d1SAndreas Gohr /** 12612a4e4d1SAndreas Gohr * Adds a checkbox field 12712a4e4d1SAndreas Gohr * 12812a4e4d1SAndreas Gohr * @param $name 12912a4e4d1SAndreas Gohr * @param $label 13012a4e4d1SAndreas Gohr * @param int $pos 13112a4e4d1SAndreas Gohr * @return CheckableElement 13212a4e4d1SAndreas Gohr */ 133de19515fSAndreas Gohr public function addCheckbox($name, $label = '', $pos = -1) { 13412a4e4d1SAndreas Gohr return $this->addElement(new CheckableElement('checkbox', $name, $label), $pos); 13512a4e4d1SAndreas Gohr } 13612a4e4d1SAndreas Gohr 13712a4e4d1SAndreas Gohr /** 13812a4e4d1SAndreas Gohr * Adds a textarea field 13912a4e4d1SAndreas Gohr * 14012a4e4d1SAndreas Gohr * @param $name 14112a4e4d1SAndreas Gohr * @param $label 14212a4e4d1SAndreas Gohr * @param int $pos 14312a4e4d1SAndreas Gohr * @return TextareaElement 14412a4e4d1SAndreas Gohr */ 145de19515fSAndreas Gohr public function addTextarea($name, $label = '', $pos = -1) { 14612a4e4d1SAndreas Gohr return $this->addElement(new TextareaElement($name, $label), $pos); 14712a4e4d1SAndreas Gohr } 14812a4e4d1SAndreas Gohr 14912a4e4d1SAndreas Gohr /** 150de19515fSAndreas Gohr * Add fixed HTML to the form 151de19515fSAndreas Gohr * 152de19515fSAndreas Gohr * @param $html 153de19515fSAndreas Gohr * @param int $pos 15464744a10SAndreas Gohr * @return HTMLElement 155de19515fSAndreas Gohr */ 156de19515fSAndreas Gohr public function addHTML($html, $pos = -1) { 157de19515fSAndreas Gohr return $this->addElement(new HTMLElement($html), $pos); 158de19515fSAndreas Gohr } 159de19515fSAndreas Gohr 16064744a10SAndreas Gohr /** 16164744a10SAndreas Gohr * Add a closed HTML tag to the form 16264744a10SAndreas Gohr * 16364744a10SAndreas Gohr * @param $tag 16464744a10SAndreas Gohr * @param int $pos 16564744a10SAndreas Gohr * @return TagElement 16664744a10SAndreas Gohr */ 16764744a10SAndreas Gohr public function addTag($tag, $pos = -1) { 16864744a10SAndreas Gohr return $this->addElement(new TagElement($tag), $pos); 16964744a10SAndreas Gohr } 17064744a10SAndreas Gohr 17164744a10SAndreas Gohr /** 17264744a10SAndreas Gohr * Add an open HTML tag to the form 17364744a10SAndreas Gohr * 17464744a10SAndreas Gohr * Be sure to close it again! 17564744a10SAndreas Gohr * 17664744a10SAndreas Gohr * @param $tag 17764744a10SAndreas Gohr * @param int $pos 17864744a10SAndreas Gohr * @return TagOpenElement 17964744a10SAndreas Gohr */ 18064744a10SAndreas Gohr public function addTagOpen($tag, $pos = -1) { 18164744a10SAndreas Gohr return $this->addElement(new TagOpenElement($tag), $pos); 18264744a10SAndreas Gohr } 18364744a10SAndreas Gohr 18464744a10SAndreas Gohr /** 18564744a10SAndreas Gohr * Add a closing HTML tag to the form 18664744a10SAndreas Gohr * 18764744a10SAndreas Gohr * Be sure it had been opened before 18864744a10SAndreas Gohr * 18964744a10SAndreas Gohr * @param $tag 19064744a10SAndreas Gohr * @param int $pos 19164744a10SAndreas Gohr * @return TagCloseElement 19264744a10SAndreas Gohr */ 19364744a10SAndreas Gohr public function addTagClose($tag, $pos = -1) { 19464744a10SAndreas Gohr return $this->addElement(new TagCloseElement($tag), $pos); 19564744a10SAndreas Gohr } 19664744a10SAndreas Gohr 19764744a10SAndreas Gohr /** 19864744a10SAndreas Gohr * Open a Fieldset 19964744a10SAndreas Gohr * 20064744a10SAndreas Gohr * @param $legend 20164744a10SAndreas Gohr * @param int $pos 20264744a10SAndreas Gohr * @return FieldsetOpenElement 20364744a10SAndreas Gohr */ 20464744a10SAndreas Gohr public function addFieldsetOpen($legend = '', $pos = -1) { 20564744a10SAndreas Gohr return $this->addElement(new FieldsetOpenElement($legend), $pos); 20664744a10SAndreas Gohr } 20764744a10SAndreas Gohr 20864744a10SAndreas Gohr /** 20964744a10SAndreas Gohr * Close a fieldset 21064744a10SAndreas Gohr * 21164744a10SAndreas Gohr * @param int $pos 21264744a10SAndreas Gohr * @return TagCloseElement 21364744a10SAndreas Gohr */ 21464744a10SAndreas Gohr public function addFieldsetClose($pos = -1) { 21564744a10SAndreas Gohr return $this->addElement(new FieldsetCloseElement(), $pos); 21664744a10SAndreas Gohr } 21764744a10SAndreas Gohr 21864744a10SAndreas Gohr #endregion 21964744a10SAndreas Gohr 220*1f5d8b65SAndreas Gohr /** 221*1f5d8b65SAndreas Gohr * Adjust the elements so that fieldset open and closes are matching 222*1f5d8b65SAndreas Gohr */ 223de19515fSAndreas Gohr protected function balanceFieldsets() { 224*1f5d8b65SAndreas Gohr $lastclose = 0; 225*1f5d8b65SAndreas Gohr $isopen = false; 226*1f5d8b65SAndreas Gohr $len = count($this->elements); 227*1f5d8b65SAndreas Gohr 228*1f5d8b65SAndreas Gohr for($pos = 0; $pos < $len; $pos++) { 229*1f5d8b65SAndreas Gohr $type = $this->elements[$pos]->getType(); 230*1f5d8b65SAndreas Gohr if($type == 'fieldsetopen') { 231*1f5d8b65SAndreas Gohr if($isopen) { 232*1f5d8b65SAndreas Gohr //close previous feldset 233*1f5d8b65SAndreas Gohr $this->addFieldsetClose($pos); 234*1f5d8b65SAndreas Gohr $lastclose = $pos + 1; 235*1f5d8b65SAndreas Gohr $pos++; 236*1f5d8b65SAndreas Gohr $len++; 237*1f5d8b65SAndreas Gohr } 238*1f5d8b65SAndreas Gohr $isopen = true; 239*1f5d8b65SAndreas Gohr } else if($type == 'fieldsetclose') { 240*1f5d8b65SAndreas Gohr if(!$isopen) { 241*1f5d8b65SAndreas Gohr // make sure there was a fieldsetopen 242*1f5d8b65SAndreas Gohr // either right after the last close or at the begining 243*1f5d8b65SAndreas Gohr $this->addFieldsetOpen('', $lastclose); 244*1f5d8b65SAndreas Gohr $len++; 245*1f5d8b65SAndreas Gohr $pos++; 246*1f5d8b65SAndreas Gohr } 247*1f5d8b65SAndreas Gohr $lastclose = $pos; 248*1f5d8b65SAndreas Gohr $isopen = false; 249*1f5d8b65SAndreas Gohr } 250*1f5d8b65SAndreas Gohr } 251*1f5d8b65SAndreas Gohr 252*1f5d8b65SAndreas Gohr // close open fieldset at the end 253*1f5d8b65SAndreas Gohr if($isopen) { 254*1f5d8b65SAndreas Gohr $this->addFieldsetClose(); 255*1f5d8b65SAndreas Gohr } 256de19515fSAndreas Gohr } 257de19515fSAndreas Gohr 258de19515fSAndreas Gohr /** 25912a4e4d1SAndreas Gohr * The HTML representation of the whole form 26012a4e4d1SAndreas Gohr * 26112a4e4d1SAndreas Gohr * @return string 26212a4e4d1SAndreas Gohr */ 26312a4e4d1SAndreas Gohr public function toHTML() { 264de19515fSAndreas Gohr $this->balanceFieldsets(); 265de19515fSAndreas Gohr 26612a4e4d1SAndreas Gohr $html = '<form ' . buildAttributes($this->attrs()) . '>' . DOKU_LF; 26712a4e4d1SAndreas Gohr 26812a4e4d1SAndreas Gohr foreach($this->hidden as $name => $value) { 26912a4e4d1SAndreas Gohr $html .= '<input type="hidden" name="' . $name . '" value="' . formText($value) . '" />' . DOKU_LF; 27012a4e4d1SAndreas Gohr } 27112a4e4d1SAndreas Gohr 27212a4e4d1SAndreas Gohr foreach($this->elements as $element) { 27312a4e4d1SAndreas Gohr $html .= $element->toHTML() . DOKU_LF; 27412a4e4d1SAndreas Gohr } 27512a4e4d1SAndreas Gohr 27612a4e4d1SAndreas Gohr $html .= '</form>' . DOKU_LF; 27712a4e4d1SAndreas Gohr 27812a4e4d1SAndreas Gohr return $html; 27912a4e4d1SAndreas Gohr } 28012a4e4d1SAndreas Gohr} 281