HTMLTextField.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <?php
  2. /**
  3. * <input> field.
  4. *
  5. * Besides the parameters recognized by HTMLFormField, the following are
  6. * recognized:
  7. * autocomplete - HTML autocomplete value (a boolean for on/off or a string according to
  8. * https://html.spec.whatwg.org/multipage/forms.html#autofill )
  9. */
  10. class HTMLTextField extends HTMLFormField {
  11. protected $mPlaceholder = '';
  12. /** @var bool HTML autocomplete attribute */
  13. protected $autocomplete;
  14. /**
  15. * @param array $params
  16. * - type: HTML textfield type
  17. * - size: field size in characters (defaults to 45)
  18. * - placeholder/placeholder-message: set HTML placeholder attribute
  19. * - spellcheck: set HTML spellcheck attribute
  20. * - persistent: upon unsuccessful requests, retain the value (defaults to true, except
  21. * for password fields)
  22. */
  23. public function __construct( $params ) {
  24. if ( isset( $params['autocomplete'] ) && is_bool( $params['autocomplete'] ) ) {
  25. $params['autocomplete'] = $params['autocomplete'] ? 'on' : 'off';
  26. }
  27. parent::__construct( $params );
  28. if ( isset( $params['placeholder-message'] ) ) {
  29. $this->mPlaceholder = $this->getMessage( $params['placeholder-message'] )->text();
  30. } elseif ( isset( $params['placeholder'] ) ) {
  31. $this->mPlaceholder = $params['placeholder'];
  32. }
  33. }
  34. public function getSize() {
  35. return $this->mParams['size'] ?? 45;
  36. }
  37. public function getSpellCheck() {
  38. $val = $this->mParams['spellcheck'] ?? null;
  39. if ( is_bool( $val ) ) {
  40. // "spellcheck" attribute literally requires "true" or "false" to work.
  41. return $val === true ? 'true' : 'false';
  42. }
  43. return null;
  44. }
  45. public function isPersistent() {
  46. if ( isset( $this->mParams['persistent'] ) ) {
  47. return $this->mParams['persistent'];
  48. }
  49. // don't put passwords into the HTML body, they could get cached or otherwise leaked
  50. return !( isset( $this->mParams['type'] ) && $this->mParams['type'] === 'password' );
  51. }
  52. public function getInputHTML( $value ) {
  53. if ( !$this->isPersistent() ) {
  54. $value = '';
  55. }
  56. $attribs = [
  57. 'id' => $this->mID,
  58. 'name' => $this->mName,
  59. 'size' => $this->getSize(),
  60. 'value' => $value,
  61. 'dir' => $this->mDir,
  62. 'spellcheck' => $this->getSpellCheck(),
  63. ] + $this->getTooltipAndAccessKey() + $this->getDataAttribs();
  64. if ( $this->mClass !== '' ) {
  65. $attribs['class'] = $this->mClass;
  66. }
  67. if ( $this->mPlaceholder !== '' ) {
  68. $attribs['placeholder'] = $this->mPlaceholder;
  69. }
  70. # @todo Enforce pattern, step, required, readonly on the server side as
  71. # well
  72. $allowedParams = [
  73. 'type',
  74. 'min',
  75. 'max',
  76. 'step',
  77. 'title',
  78. 'maxlength',
  79. 'tabindex',
  80. 'disabled',
  81. 'required',
  82. 'autofocus',
  83. 'readonly',
  84. 'autocomplete',
  85. // Only used in HTML mode:
  86. 'pattern',
  87. 'list',
  88. 'multiple',
  89. ];
  90. $attribs += $this->getAttributes( $allowedParams );
  91. # Extract 'type'
  92. $type = $this->getType( $attribs );
  93. return Html::input( $this->mName, $value, $type, $attribs );
  94. }
  95. protected function getType( &$attribs ) {
  96. $type = $attribs['type'] ?? 'text';
  97. unset( $attribs['type'] );
  98. # Implement tiny differences between some field variants
  99. # here, rather than creating a new class for each one which
  100. # is essentially just a clone of this one.
  101. if ( isset( $this->mParams['type'] ) ) {
  102. switch ( $this->mParams['type'] ) {
  103. case 'int':
  104. $type = 'number';
  105. $attribs['step'] = 1;
  106. break;
  107. case 'float':
  108. $type = 'number';
  109. $attribs['step'] = 'any';
  110. break;
  111. # Pass through
  112. case 'email':
  113. case 'password':
  114. case 'file':
  115. case 'url':
  116. $type = $this->mParams['type'];
  117. break;
  118. case 'textwithbutton':
  119. $type = $this->mParams['inputtype'] ?? 'text';
  120. break;
  121. }
  122. }
  123. return $type;
  124. }
  125. public function getInputOOUI( $value ) {
  126. if ( !$this->isPersistent() ) {
  127. $value = '';
  128. }
  129. $attribs = $this->getTooltipAndAccessKeyOOUI();
  130. if ( $this->mClass !== '' ) {
  131. $attribs['classes'] = [ $this->mClass ];
  132. }
  133. if ( $this->mPlaceholder !== '' ) {
  134. $attribs['placeholder'] = $this->mPlaceholder;
  135. }
  136. # @todo Enforce pattern, step, required, readonly on the server side as
  137. # well
  138. $allowedParams = [
  139. 'type',
  140. 'min',
  141. 'max',
  142. 'step',
  143. 'title',
  144. 'maxlength',
  145. 'tabindex',
  146. 'disabled',
  147. 'required',
  148. 'autofocus',
  149. 'readonly',
  150. 'autocomplete',
  151. // Only used in OOUI mode:
  152. 'autosize',
  153. 'flags',
  154. 'indicator',
  155. ];
  156. $attribs += OOUI\Element::configFromHtmlAttributes(
  157. $this->getAttributes( $allowedParams )
  158. );
  159. // FIXME T150983 downgrade autocomplete
  160. if ( isset( $attribs['autocomplete'] ) ) {
  161. if ( $attribs['autocomplete'] === 'on' ) {
  162. $attribs['autocomplete'] = true;
  163. } elseif ( $attribs['autocomplete'] === 'off' ) {
  164. $attribs['autocomplete'] = false;
  165. } else {
  166. unset( $attribs['autocomplete'] );
  167. }
  168. }
  169. $type = $this->getType( $attribs );
  170. if ( isset( $attribs['step'] ) && $attribs['step'] === 'any' ) {
  171. $attribs['step'] = null;
  172. }
  173. return $this->getInputWidget( [
  174. 'id' => $this->mID,
  175. 'name' => $this->mName,
  176. 'value' => $value,
  177. 'type' => $type,
  178. 'dir' => $this->mDir,
  179. ] + $attribs );
  180. }
  181. protected function getInputWidget( $params ) {
  182. return new OOUI\TextInputWidget( $params );
  183. }
  184. /**
  185. * Returns an array of data-* attributes to add to the field.
  186. *
  187. * @return array
  188. */
  189. protected function getDataAttribs() {
  190. return [];
  191. }
  192. }