1<?php 2 3namespace dokuwiki\Form; 4 5/** 6 * Class InputElement 7 * 8 * Base class for all input elements. Uses a wrapping label when label 9 * text is given. 10 * 11 * @todo figure out how to make wrapping or related label configurable 12 * @package dokuwiki\Form 13 */ 14class InputElement extends Element 15{ 16 /** 17 * @var LabelElement 18 */ 19 protected $label; 20 21 /** 22 * @var bool if the element should reflect posted values 23 */ 24 protected $useInput = true; 25 26 /** 27 * @param string $type The type of this element 28 * @param string $name The name of this form element 29 * @param string $label The label text for this element (will be autoescaped) 30 */ 31 public function __construct($type, $name, $label = '') 32 { 33 parent::__construct($type, ['name' => $name]); 34 $this->attr('name', $name); 35 $this->attr('type', $type); 36 if ($label) $this->label = new LabelElement($label); 37 } 38 39 /** 40 * Returns the label element if there's one set 41 * 42 * @return LabelElement|null 43 */ 44 public function getLabel() 45 { 46 return $this->label; 47 } 48 49 /** 50 * Should the user sent input be used to initialize the input field 51 * 52 * The default is true. Any set values will be overwritten by the INPUT 53 * provided values. 54 * 55 * @param bool $useinput 56 * @return $this 57 */ 58 public function useInput($useinput) 59 { 60 $this->useInput = (bool) $useinput; 61 return $this; 62 } 63 64 /** 65 * Get or set the element's ID 66 * 67 * @param null|string $id 68 * @return string|$this 69 */ 70 public function id($id = null) 71 { 72 if ($this->label) $this->label->attr('for', $id); 73 return parent::id($id); 74 } 75 76 /** 77 * Adds a class to the class attribute 78 * 79 * This is the preferred method of setting the element's class 80 * 81 * @param string $class the new class to add 82 * @return $this 83 */ 84 public function addClass($class) 85 { 86 if ($this->label) $this->label->addClass($class); 87 return parent::addClass($class); 88 } 89 90 /** 91 * Figures out how to access the value for this field from INPUT data 92 * 93 * The element's name could have been given as a simple string ('foo') 94 * or in array notation ('foo[bar]'). 95 * 96 * Note: this function only handles one level of arrays. If your data 97 * is nested deeper, you should call useInput(false) and set the 98 * correct value yourself 99 * 100 * @return array name and array key (null if not an array) 101 */ 102 protected function getInputName() 103 { 104 $name = $this->attr('name'); 105 parse_str("$name=1", $parsed); 106 107 $name = array_keys($parsed); 108 $name = array_shift($name); 109 110 if (isset($parsed[$name]) && is_array($parsed[$name])) { 111 $key = array_keys($parsed[$name]); 112 $key = array_shift($key); 113 } else { 114 $key = null; 115 } 116 117 return [$name, $key]; 118 } 119 120 /** 121 * Handles the useInput flag and set the value attribute accordingly 122 */ 123 protected function prefillInput() 124 { 125 global $INPUT; 126 127 [$name, $key] = $this->getInputName(); 128 if (!$INPUT->has($name)) return; 129 130 if ($key === null) { 131 $value = $INPUT->str($name); 132 } else { 133 $value = $INPUT->arr($name); 134 if (isset($value[$key])) { 135 $value = $value[$key]; 136 } else { 137 $value = ''; 138 } 139 } 140 $this->val($value); 141 } 142 143 /** 144 * The HTML representation of this element 145 * 146 * @return string 147 */ 148 protected function mainElementHTML() 149 { 150 if ($this->useInput) $this->prefillInput(); 151 return '<input ' . buildAttributes($this->attrs()) . ' />'; 152 } 153 154 /** 155 * The HTML representation of this element wrapped in a label 156 * 157 * @return string 158 */ 159 public function toHTML() 160 { 161 if ($this->label) { 162 return '<label ' . buildAttributes($this->label->attrs()) . '>' . DOKU_LF 163 . '<span>' . hsc($this->label->val()) . '</span>' . DOKU_LF 164 . $this->mainElementHTML() . DOKU_LF 165 . '</label>'; 166 } else { 167 return $this->mainElementHTML(); 168 } 169 } 170} 171