Textpattern PHP Cross Reference Content Management Systems

Source: /textpattern/lib/txplib_forms.php - 792 lines - 22695 bytes - Summary - Text - Print

Description: Collection of HTML form widgets.

   1  <?php
   2  
   3  /*
   4   * Textpattern Content Management System
   5   * https://textpattern.com/
   6   *
   7   * Copyright (C) 2020 The Textpattern Development Team
   8   *
   9   * This file is part of Textpattern.
  10   *
  11   * Textpattern is free software; you can redistribute it and/or
  12   * modify it under the terms of the GNU General Public License
  13   * as published by the Free Software Foundation, version 2.
  14   *
  15   * Textpattern is distributed in the hope that it will be useful,
  16   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18   * GNU General Public License for more details.
  19   *
  20   * You should have received a copy of the GNU General Public License
  21   * along with Textpattern. If not, see <https://www.gnu.org/licenses/>.
  22   */
  23  
  24  /**
  25   * Collection of HTML form widgets.
  26   *
  27   * @package Form
  28   */
  29  
  30  /**
  31   * Generates a radio button toggle.
  32   *
  33   * @param  array  $values   The values as an array
  34   * @param  string $field    The field name
  35   * @param  string $checked  The checked button, takes a value from $vals
  36   * @param  int    $tabindex The HTML tabindex
  37   * @param  string $id       The HTML id
  38   * @return string A HTML radio button set
  39   * @example
  40   * echo radioSet(array(
  41   *     'value1' => 'Label1',
  42   *     'value2' => 'Label2',
  43   * ), 'myInput', 'value1');
  44   */
  45  
  46  function radioSet($values, $field, $checked = '', $tabindex = 0, $id = '')
  47  {
  48      if ($id) {
  49          $id = $id.'-'.$field;
  50      } else {
  51          $id = $field;
  52      }
  53  
  54      $out = array();
  55  
  56      foreach ((array) $values as $value => $label) {
  57          $out[] = radio($field, $value, (string) $value === (string) $checked, $id.'-'.$value, $tabindex);
  58          $out[] = n.tag($label, 'label', array('for' => $id.'-'.$value));
  59      }
  60  
  61      return join('', $out);
  62  }
  63  
  64  /**
  65   * Generates a Yes/No radio button toggle.
  66   *
  67   * These buttons are booleans. 'Yes' will have a value of 1 and 'No' is 0.
  68   *
  69   * @param  string $field    The field name
  70   * @param  string $checked  The checked button, either '1', '0'
  71   * @param  int    $tabindex The HTML tabindex
  72   * @param  string $id       The HTML id
  73   * @return string HTML
  74   * @see    radioSet()
  75   * @example
  76   * echo form(
  77   *     'Is this an example?'.
  78   *     yesnoRadio('is_example', 1)
  79   * );
  80   */
  81  
  82  function yesnoRadio($field, $checked = '', $tabindex = 0, $id = '')
  83  {
  84      $vals = array(
  85          '0' => gTxt('no'),
  86          '1' => gTxt('yes'),
  87      );
  88  
  89      return radioSet($vals, $field, $checked, $tabindex, $id);
  90  }
  91  
  92  /**
  93   * Generates an On/Off radio button toggle.
  94   *
  95   * @param  string $field    The field name
  96   * @param  string $checked  The checked button, either '1', '0'
  97   * @param  int    $tabindex The HTML tabindex
  98   * @param  string $id       The HTML id
  99   * @return string HTML
 100   * @see    radioSet()
 101   */
 102  
 103  function onoffRadio($field, $checked = '', $tabindex = 0, $id = '')
 104  {
 105      $vals = array(
 106          '0' => gTxt('off'),
 107          '1' => gTxt('on'),
 108      );
 109  
 110      return radioSet($vals, $field, $checked, $tabindex, $id);
 111  }
 112  
 113  /**
 114   * Generates a select field.
 115   *
 116   * @param  string $name        The field
 117   * @param  array  $array       The values as an array array( 'value' => 'label' )
 118   * @param  mixed  $value       The selected option(s). If an array, renders the select multiple
 119   * @param  bool   $blank_first If TRUE, prepends an empty option to the list
 120   * @param  mixed  $onchange    If TRUE submits the form when an option is changed. If a string, inserts it to the select tag
 121   * @param  string $select_id   The HTML id
 122   * @param  bool   $check_type  Type-agnostic comparison
 123   * @param  bool   $disabled    If TRUE renders the select disabled
 124   * @return string HTML
 125   * @example
 126   * echo selectInput('myInput', array(
 127   *     'value1' => 'Label1',
 128   *     'value2' => 'Label2',
 129   * ));
 130   */
 131  
 132  function selectInput($name = '', $array = array(), $value = '', $blank_first = false, $onchange = '', $select_id = '', $check_type = false, $disabled = false)
 133  {
 134      $out = array();
 135  
 136      $selected = false;
 137      $multiple = is_array($value);
 138      $multiple or $value = (string) $value;
 139  
 140      if (is_array($disabled)) {
 141          $disable = $disabled;
 142          $disabled = false;
 143      } else {
 144          $disable = array();
 145      }
 146  
 147      if (is_array($blank_first)) {
 148          $array = $blank_first + $array;
 149          $blank_first = false;
 150      }
 151  
 152      foreach ($array as $avalue => $alabel) {
 153          $atts = array('value' => $avalue, 'dir' => 'auto', 'disabled' => in_array($avalue, $disable));
 154  
 155          if (!$multiple && $value === (string) $avalue || $multiple && in_array($avalue, $value)) {
 156              $atts['selected'] = $selected = true;
 157          }
 158  
 159          if (is_array($alabel)) {
 160              $atts = $alabel + $atts;
 161              $alabel = isset($atts['title']) ? $atts['title'] : $avalue;
 162              unset($atts['title']);
 163          }
 164  
 165          $atts = join_atts($atts, TEXTPATTERN_STRIP_NONE);
 166          $out[] = '<option'.$atts.'>'.txpspecialchars($alabel).'</option>';
 167      }
 168  
 169      if ($blank_first) {
 170          array_unshift($out, '<option value=""'.($selected === false ? ' selected="selected"' : '').'>&#160;</option>');
 171      }
 172  
 173      $name_m = (is_array($name) ? $name['name'] : $name).($multiple ? '[]' : '');
 174  
 175      $atts = join_atts((is_array($name) ? $name : array(
 176          'name' => $name.($multiple ? '[]' : '')
 177      )) + array(
 178          'id'       => $select_id,
 179          'disabled' => (bool) $disabled,
 180          'multiple' => $multiple
 181      ), TEXTPATTERN_STRIP_EMPTY);
 182  
 183      if ((string) $onchange === '1') {
 184          $atts .= ' data-submit-on="change"';
 185      } elseif ($onchange) {
 186          $atts .= ' '.trim($onchange);
 187      }
 188  
 189      return n.'<select'.$atts.'>'.n.join(n, $out).n.'</select>'.n
 190          .($multiple ? hInput($name_m, '').n : ''); // TODO: use jQuery UI selectmenu?
 191  }
 192  
 193  /**
 194   * Generates a tree structured select field.
 195   *
 196   * This field takes a NSTREE structure as an associative array. This is mainly
 197   * used for categories.
 198   *
 199   * @param  string $select_name The field
 200   * @param  array  $array       The values as an array
 201   * @param  string $value       The selected option. Takes a value from $value
 202   * @param  string $select_id   The HTML id
 203   * @param  int    $truncate    Truncate labels to certain length. Disabled if set <4.
 204   * @return string HTML
 205   * @see    getTree()
 206   */
 207  
 208  function treeSelectInput($select_name = '', $array = array(), $value = '', $select_id = '', $truncate = 0, $atts = array())
 209  {
 210      $out = array();
 211  
 212      $doctype = get_pref('doctype');
 213      $selected = false;
 214  
 215      foreach ($array as $a) {
 216          if ($a['name'] == 'root') {
 217              continue;
 218          }
 219  
 220          if ((string) $a['name'] === (string) $value) {
 221              $sel = ' selected="selected"';
 222              $selected = true;
 223          } else {
 224              $sel = '';
 225          }
 226  
 227          $sp = str_repeat(sp.sp, $a['level']);
 228  
 229          if (($truncate > 3) && (strlen(utf8_decode($a['title'])) > $truncate)) {
 230              $htmltitle = ' title="'.txpspecialchars($a['title']).'"';
 231              $a['title'] = preg_replace('/^(.{0,'.($truncate - 3).'}).*$/su', '$1', $a['title']);
 232              $hellip = '&#8230;';
 233          } else {
 234              $htmltitle = $hellip = '';
 235          }
 236  
 237          $data_level = '';
 238          if ($doctype !== 'xhtml') {
 239              $data_level = ' data-level="'.$a['level'].'"';
 240          }
 241  
 242          $out[] = '<option value="'.txpspecialchars($a['name']).'"'.$htmltitle.$sel.$data_level.' dir="auto">'.$sp.txpspecialchars($a['title']).$hellip.'</option>';
 243      }
 244  
 245      array_unshift($out, '<option value=""'.($selected === false ? ' selected="selected"' : '').'>&#160;</option>');
 246  
 247      return n.tag(n.join(n, $out).n, 'select', array(
 248          'id'   => $select_id,
 249          'name' => $select_name,
 250      ) + $atts);
 251  }
 252  
 253  /**
 254   * Render HTML &lt;select&gt; element for choosing a timezone.
 255   *
 256   * @param  string      $name        Element name
 257   * @param  string      $value       Selected timezone
 258   * @param  bool        $blank_first Add empty first option
 259   * @param  bool|string $onchange
 260   * @param  string      $select_id   HTML id attribute
 261   * @return string HTML markup
 262   * @since  4.7.0
 263   * @todo   Might be a better way of doing this, perhaps introducing optgroup to selectInput()
 264   */
 265  
 266  function timezoneSelectInput($name = '', $value = '', $blank_first = '', $onchange = '', $select_id = '')
 267  {
 268      if ($details = Txp::get('\Textpattern\Date\Timezone')->getTimeZones()) {
 269          $thiscontinent = '';
 270          $selected = false;
 271  
 272          foreach ($details as $timezone_id => $tz) {
 273              extract($tz);
 274  
 275              if ($value == $timezone_id) {
 276                  $selected = true;
 277              }
 278  
 279              if ($continent !== $thiscontinent) {
 280                  if ($thiscontinent !== '') {
 281                      $out[] = n.'</optgroup>';
 282                  }
 283  
 284                  $out[] = n.'<optgroup label="'.gTxt($continent).'">';
 285                  $thiscontinent = $continent;
 286              }
 287  
 288              $where = gTxt(str_replace('_', ' ', $city))
 289                  .(!empty($subcity) ? '/'.gTxt(str_replace('_', ' ', $subcity)) : '').t
 290                  /*."($abbr)"*/;
 291  
 292              $out[] = n.'<option value="'.txpspecialchars($timezone_id).'"'.($value == $timezone_id ? ' selected="selected"' : '').' dir="auto">'.$where.'</option>';
 293          }
 294  
 295          $out[] = n.'</optgroup>';
 296  
 297          return n.'<select'.($select_id ? ' id="'.$select_id.'"' : '').' name="'.$name.'"'.
 298              ($onchange == 1 ? ' onchange="submit(this.form);"' : $onchange).
 299              '>'.
 300              ($blank_first ? n.'<option value=""'.($selected == false ? ' selected="selected"' : '').'>&#160;</option>' : '').
 301              join('', $out).
 302              n.'</select>';
 303      }
 304  
 305      return '';
 306  }
 307  
 308  /**
 309   * Generic form input.
 310   *
 311   * @param  string       $type         The input type
 312   * @param  string       $name         The input name
 313   * @param  string       $value        The value
 314   * @param  string       $class        The HTML class
 315   * @param  string       $title        The tooltip
 316   * @param  string       $onClick      Inline JavaScript attached to the click event
 317   * @param  int          $size         The input size
 318   * @param  int          $tab          The HTML tabindex
 319   * @param  string       $id           The HTML id
 320   * @param  bool         $disabled     If TRUE renders the input disabled
 321   * @param  bool         $required     If TRUE the field is marked as required
 322   * @param  string       $placeholder  The placeholder value displayed when the field is empty
 323   * @return string HTML input
 324   * @example
 325   * echo fInput('text', 'myInput', 'My example value');
 326   */
 327  
 328  function fInput($type, $name, $value, $class = '', $title = '', $onClick = '', $size = 0, $tab = 0, $id = '', $disabled = false, $required = false, $placeholder = null)
 329  {
 330      $atts = (is_array($name) ? $name : array('name' => $name)) + array(
 331          'class'        => $class,
 332          'id'           => $id,
 333          'type'         => $type,
 334          'size'         => (int) $size,
 335          'title'        => $title,
 336          'onclick'      => $onClick,
 337          'tabindex'     => (int) $tab,
 338          'disabled'     => (bool) $disabled,
 339          'required'     => (bool) $required,
 340          'placeholder'  => $placeholder,
 341      );
 342  
 343      if ($atts['required'] && !isset($atts['placeholder'])
 344          && in_array($atts['type'], array('email', 'password', 'search', 'tel', 'text', 'url'))
 345      ) {
 346          $atts['placeholder'] = gTxt('required');
 347      }
 348  
 349      $atts = join_atts($atts, TEXTPATTERN_STRIP_EMPTY);
 350  
 351      if ($type != 'file' && $type != 'image') {
 352          $atts .= join_atts(array('value' => (string) $value), TEXTPATTERN_STRIP_NONE);
 353      }
 354  
 355      return n.tag_void('input', $atts);
 356  }
 357  
 358  /**
 359   * Hidden form input.
 360   *
 361   * @param  string/array $name  The name
 362   * @param  string       $value The value
 363   * @return string       HTML input
 364   * @example
 365   * echo hInput('myInput', 'hidden value');
 366   */
 367  
 368  function hInput($name, $value = null, $glue = ',')
 369  {
 370      if (!is_array($name)) {
 371          return fInput('hidden', $name, $value);
 372      }
 373  
 374      return array_walk($name, function (&$v, $n, $glue) {
 375          $v = fInput('hidden', $n, is_array($v) ? implode($glue, $v) : $v);
 376      }, $glue) ? implode($name) : false;
 377  }
 378  
 379  /**
 380   * Hidden step input.
 381   *
 382   * @param  string $step The step
 383   * @return string HTML input
 384   * @see    form()
 385   * @see    eInput()
 386   * @example
 387   * echo form(
 388   *     eInput('event').
 389   *     sInput('step')
 390   * );
 391   */
 392  
 393  function sInput($step)
 394  {
 395      return hInput('step', $step);
 396  }
 397  
 398  /**
 399   * Hidden event input.
 400   *
 401   * @param  string $event The event
 402   * @return string HTML input
 403   * @see    form()
 404   * @see    sInput()
 405   * @example
 406   * echo form(
 407   *     eInput('event').
 408   *     sInput('step')
 409   * );
 410   */
 411  
 412  function eInput($event)
 413  {
 414      return hInput('event', $event);
 415  }
 416  
 417  /**
 418   * Hidden form token input.
 419   *
 420   * @return string A hidden HTML input containing a CSRF token
 421   * @see    bouncer()
 422   * @see    form_token()
 423   */
 424  
 425  function tInput()
 426  {
 427      return hInput('_txp_token', form_token());
 428  }
 429  
 430  /**
 431   * A checkbox.
 432   *
 433   * @param  string $name     The field
 434   * @param  string $value    The value
 435   * @param  bool   $checked  If TRUE the box is checked
 436   * @param  int    $tabindex The HTML tabindex
 437   * @param  string $id       The HTML id
 438   * @return string HTML input
 439   * @example
 440   * echo checkbox('name', 'value', true);
 441   */
 442  
 443  function checkbox($name, $value, $checked = true, $tabindex = 0, $id = '')
 444  {
 445      $class = 'checkbox';
 446  
 447      if ($checked) {
 448          $class .= ' active';
 449      }
 450  
 451      $atts = join_atts(array(
 452          'class'    => $class,
 453          'id'       => $id,
 454          'name'     => $name,
 455          'type'     => 'checkbox',
 456          'checked'  => (bool) $checked,
 457          'tabindex' => (int) $tabindex,
 458      ), TEXTPATTERN_STRIP_EMPTY);
 459  
 460      $atts .= join_atts(array('value' => (string) $value), TEXTPATTERN_STRIP_NONE);
 461  
 462      return n.tag_void('input', $atts);
 463  }
 464  
 465  /**
 466   * A checkbox without an option to set the value.
 467   *
 468   * @param  string $name     The field
 469   * @param  bool   $value    If TRUE the box is checked
 470   * @param  int    $tabindex The HTML tabindex
 471   * @param  string $id       The HTML id
 472   * @return string HTML input
 473   * @access private
 474   * @see    checkbox()
 475   */
 476  
 477  function checkbox2($name, $value, $tabindex = 0, $id = '')
 478  {
 479      return checkbox($name, 1, $value, $tabindex, $id);
 480  }
 481  
 482  /**
 483   * A single radio button.
 484   *
 485   * @param  string $name     The field
 486   * @param  string $value    The value
 487   * @param  bool   $checked  If TRUE, the button is selected
 488   * @param  string $id       The HTML id
 489   * @param  int    $tabindex The HTML tabindex
 490   * @return string HTML input
 491   */
 492  
 493  function radio($name, $value, $checked = true, $id = '', $tabindex = 0)
 494  {
 495      $class = 'radio';
 496  
 497      if ($checked) {
 498          $class .= ' active';
 499      }
 500  
 501      $atts = join_atts(array(
 502          'class'    => $class,
 503          'id'       => $id,
 504          'name'     => $name,
 505          'type'     => 'radio',
 506          'checked'  => (bool) $checked,
 507          'tabindex' => (int) $tabindex,
 508      ), TEXTPATTERN_STRIP_EMPTY);
 509  
 510      $atts .= join_atts(array('value' => (string) $value), TEXTPATTERN_STRIP_NONE);
 511  
 512      return n.tag_void('input', $atts);
 513  }
 514  
 515  /**
 516   * Generates a form element.
 517   *
 518   * This form will contain a CSRF token if called on an authenticated page.
 519   *
 520   * @param  string $contents           The form contents
 521   * @param  string $style              Inline styles added to the form
 522   * @param  string $onsubmit           JavaScript run when the form is sent
 523   * @param  string $method             The form method, e.g. "post", "get"
 524   * @param  string $class              The HTML class
 525   * @param  string $fragment           A URL fragment added to the form target
 526   * @param  string $id                 The HTML id
 527   * @param  string $role               ARIA role name
 528   * @param  bool   $allow_autocomplete If FALSE, the form is set to autocomplete="off"
 529   * @return string HTML form element
 530   */
 531  
 532  function form($contents, $style = '', $onsubmit = '', $method = 'post', $class = '', $fragment = '', $id = '', $role = '', $allow_autocomplete = true)
 533  {
 534      $action = 'index.php';
 535      $autocomplete = '';
 536  
 537      if ($onsubmit) {
 538          $onsubmit = 'return '.$onsubmit;
 539      }
 540  
 541      if ($fragment) {
 542          $action .= '#'.$fragment;
 543      }
 544  
 545      if ($allow_autocomplete === false) {
 546          $autocomplete = 'off';
 547      }
 548  
 549      return n.tag($contents.tInput().n, 'form', array(
 550          'class'        => $class,
 551          'id'           => $id,
 552          'method'       => $method,
 553          'action'       => $action,
 554          'onsubmit'     => $onsubmit,
 555          'role'         => $role,
 556          'autocomplete' => $autocomplete,
 557          'style'        => $style,
 558      ));
 559  }
 560  
 561  /**
 562   * Gets and sanitises a field from a prefixed core database table.
 563   *
 564   * @param  string $name       The field
 565   * @param  string $event      The table
 566   * @param  string $identifier The field used for selecting
 567   * @param  string $id         The value used for selecting
 568   * @return string HTML
 569   * @access private
 570   * @see    fetch()
 571   * @see    txpspecialchars()
 572   */
 573  
 574  function fetch_editable($name, $event, $identifier, $id)
 575  {
 576      $q = fetch($name, 'txp_'.$event, $identifier, $id);
 577  
 578      return txpspecialchars($q);
 579  }
 580  
 581  /**
 582   * A textarea.
 583   *
 584   * @param  string $name        The field
 585   * @param  int    $h           The field height in pixels
 586   * @param  int    $w           The field width in pixels
 587   * @param  string $thing       The value
 588   * @param  string $id          The HTML id
 589   * @param  int    $rows        Rows
 590   * @param  int    $cols        Columns
 591   * @param  string $placeholder The placeholder value displayed when the field is empty
 592   * @param  bool   $required    If TRUE the field is marked as required
 593   * @return string HTML
 594   */
 595  
 596  function text_area($name, $h = 0, $w = 0, $thing = '', $id = '', $rows = 5, $cols = 40, $placeholder = null, $required = false)
 597  {
 598      $style = '';
 599  
 600      if ($w) {
 601          $style .= 'width:'.intval($w).'px;';
 602      }
 603  
 604      if ($h) {
 605          $style .= 'height:'.intval($h).'px;';
 606      }
 607  
 608      if ((string) $thing === '') {
 609          $thing = null;
 610      } else {
 611          $thing = txpspecialchars($thing);
 612      }
 613  
 614      if (!intval($rows)) {
 615          $rows = 5;
 616      }
 617  
 618      if (!intval($cols)) {
 619          $cols = 40;
 620      }
 621  
 622      $atts = (is_array($name) ? $name : array('name' => $name)) + array(
 623          'id'          => $id,
 624          'rows'        => (int) $rows,
 625          'cols'        => (int) $cols,
 626          'style'       => $style,
 627          'required'    => (bool) $required,
 628          'placeholder' => $placeholder,
 629      );
 630  
 631      if (!isset($atts['placeholder'])) {
 632          $atts['placeholder'] = $atts['required'] ? gTxt('required') : false;
 633      }
 634  
 635      return n.tag($thing, 'textarea', $atts);
 636  }
 637  
 638  /**
 639   * Generates a select field with a name "type".
 640   *
 641   * @param  array $options
 642   * @return string
 643   * @access private
 644   * @see    selectInput()
 645   */
 646  
 647  function type_select($options)
 648  {
 649      return n.'<select name="type">'.type_options($options).'</select>';
 650  }
 651  
 652  /**
 653   * Generates a list of options for use in a select field.
 654   *
 655   * @param  array $array
 656   * @return string
 657   * @access private
 658   * @see    selectInput()
 659   */
 660  
 661  function type_options($array)
 662  {
 663      foreach ($array as $a => $b) {
 664          $out[] = n.'<option value="'.$a.'">'.gTxt($b).'</option>';
 665      }
 666  
 667      return join('', $out);
 668  }
 669  
 670  /**
 671   * Generates a list of radio buttons wrapped in an unordered list.
 672   *
 673   * @param  string       $name        The field
 674   * @param  array        $values      The values as an array array( $value => $label )
 675   * @param  string       $current_val The selected option. Takes a value from $value
 676   * @param  string       $hilight_val The highlighted list item
 677   * @param  string|array $atts        HTML attributes
 678   * @return string       HTML
 679   */
 680  
 681  function radio_list($name, $values, $current_val = '', $hilight_val = '', $atts = array('class' => 'plain-list'))
 682  {
 683      foreach ($values as $value => $label) {
 684          $id = $name.'-'.$value;
 685          $class = 'status-'.$value;
 686  
 687          if ((string) $value === (string) $hilight_val) {
 688              $label = strong($label);
 689              $class .= ' active';
 690          }
 691  
 692          $out[] = tag(
 693              radio($name, $value, ((string) $current_val === (string) $value), $id).
 694              n.tag($label, 'label', array('for' => $id)),
 695              'li',
 696              array('class' => $class)
 697          );
 698      }
 699  
 700      return tag(n.join(n, $out).n, 'ul', $atts);
 701  }
 702  
 703  /**
 704   * Generates a field used to store and set a date.
 705   *
 706   * @param  string $name        The field
 707   * @param  string $datevar     The strftime format the date is displayed
 708   * @param  int    $time        The displayed date as a UNIX timestamp
 709   * @param  int    $tab         The HTML tabindex
 710   * @param  string $id          The HTML id
 711   * @return string HTML
 712   * @access private
 713   * @example
 714   * echo tsi('year', '%Y', 1200000000);
 715   */
 716  
 717  function tsi($name, $datevar, $time, $tab = 0, $id = '')
 718  {
 719      static $placeholders = array(
 720          '%Y' => 'yyyy',
 721          '%m' => 'mm',
 722          '%d' => 'dd',
 723          '%H' => 'hh',
 724          '%M' => 'mn',
 725          '%S' => 'ss',
 726      );
 727  
 728      $value = $placeholder = '';
 729      $size = INPUT_TINY;
 730      $pattern = '([0-5][0-9])';
 731  
 732      if ((int) $time) {
 733          $value = safe_strftime($datevar, (int) $time);
 734      }
 735  
 736      if (isset($placeholders[$datevar])) {
 737          $placeholder = gTxt($placeholders[$datevar]);
 738      }
 739  
 740      if ($datevar == '%Y' || $name == 'year' || $name == 'exp_year') {
 741          $class = 'input-year';
 742          $pattern = '[0-9]{4}';
 743          $size = INPUT_XSMALL;
 744          $title = 'input_year';
 745      }
 746  
 747      if ($datevar == '%m' || $name == 'month' || $name == 'exp_month') {
 748          $class = 'input-month';
 749          $pattern = '(0[1-9]|1[012])';
 750          $title = 'input_month';
 751      }
 752  
 753      if ($datevar == '%d' || $name == 'day' || $name == 'exp_day') {
 754          $class = 'input-day';
 755          $pattern = '(0[1-9]|[12][0-9]|3[01])';
 756          $title = 'input_day';
 757      }
 758  
 759      if ($datevar == '%H' || $name == 'hour' || $name == 'exp_hour') {
 760          $class = 'input-hour';
 761          $pattern = '([0-1][0-9]|2[0-3])';
 762          $title = 'input_hour';
 763      }
 764  
 765      if ($datevar == '%M' || $name == 'minute' || $name == 'exp_minute') {
 766          $class = 'input-minute';
 767          $pattern = '([0-5][0-9])';
 768          $title = 'input_minute';
 769      }
 770  
 771      if ($datevar == '%S' || $name == 'second' || $name == 'exp_second') {
 772          $class = 'input-second';
 773          $pattern = '([0-5][0-9])';
 774          $title = 'input_second';
 775      }
 776  
 777      return n.tag_void('input', array(
 778          'class'       => $class,
 779          'id'          => $id,
 780          'name'        => $name,
 781          'type'        => 'text',
 782          'inputmode'   => 'numeric',
 783          'pattern'     => $pattern,
 784          'size'        => (int) $size,
 785          'maxlength'   => $size,
 786          'title'       => gTxt($title),
 787          'aria-label'  => gTxt($title),
 788          'placeholder' => $placeholder,
 789          'tabindex'    => (int) $tab,
 790          'value'       => $value,
 791      ));
 792  }

title

Description

title

Description

title

Description

title

title

Body