Textpattern | PHP Cross Reference | Content Management Systems |
Description: Collection of HTML form widgets.
1 <?php 2 3 /* 4 * Textpattern Content Management System 5 * http://textpattern.com 6 * 7 * Copyright (C) 2016 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 <http://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) ? ' multiple="multiple"' : ''; 138 139 if ($multiple) { 140 $name .= '[]'; 141 } else { 142 $value = (string) $value; 143 } 144 145 foreach ($array as $avalue => $alabel) { 146 if (!$multiple && $value === (string) $avalue || $multiple && in_array($avalue, $value)) { 147 $sel = ' selected="selected"'; 148 $selected = true; 149 } else { 150 $sel = ''; 151 } 152 153 $out[] = '<option value="'.txpspecialchars($avalue).'"'.$sel.'>'.txpspecialchars($alabel).'</option>'; 154 } 155 156 if ($blank_first) { 157 array_unshift($out, '<option value=""'.($selected === false ? ' selected="selected"' : '').'> </option>'); 158 } 159 160 $atts = join_atts(array( 161 'id' => $select_id, 162 'name' => $name, 163 'disabled' => (bool) $disabled, 164 ), TEXTPATTERN_STRIP_EMPTY); 165 166 if ((string) $onchange === '1') { 167 $atts .= ' data-submit-on="change"'; 168 } elseif ($onchange) { 169 $atts .= ' '.trim($onchange); 170 } 171 172 return n.'<select'.$atts.$multiple.'>'.n.join(n, $out).n.'</select>'.n 173 .($multiple ? hInput($name, '').n : ''); // TODO: use jQuery UI selectmenu? 174 } 175 176 /** 177 * Generates a tree structured select field. 178 * 179 * This field takes a NSTREE structure as an associative array. This is mainly 180 * used for categories. 181 * 182 * @param string $select_name The field 183 * @param array $array The values as an array 184 * @param string $value The selected option. Takes a value from $value 185 * @param string $select_id The HTML id 186 * @param int $truncate Truncate labels to certain length. Disabled if set <4. 187 * @return string HTML 188 * @see getTree() 189 */ 190 191 function treeSelectInput($select_name = '', $array = array(), $value = '', $select_id = '', $truncate = 0) 192 { 193 $out = array(); 194 195 $doctype = get_pref('doctype'); 196 $selected = false; 197 198 foreach ($array as $a) { 199 if ($a['name'] == 'root') { 200 continue; 201 } 202 203 if ((string) $a['name'] === (string) $value) { 204 $sel = ' selected="selected"'; 205 $selected = true; 206 } else { 207 $sel = ''; 208 } 209 210 $sp = str_repeat(sp.sp, $a['level']); 211 212 if (($truncate > 3) && (strlen(utf8_decode($a['title'])) > $truncate)) { 213 $htmltitle = ' title="'.txpspecialchars($a['title']).'"'; 214 $a['title'] = preg_replace('/^(.{0,'.($truncate - 3).'}).*$/su', '$1', $a['title']); 215 $hellip = '…'; 216 } else { 217 $htmltitle = $hellip = ''; 218 } 219 220 $data_level = ''; 221 if ($doctype !== 'xhtml') { 222 $data_level = ' data-level="'.$a['level'].'"'; 223 } 224 225 $out[] = '<option value="'.txpspecialchars($a['name']).'"'.$htmltitle.$sel.$data_level.'>'.$sp.txpspecialchars($a['title']).$hellip.'</option>'; 226 } 227 228 array_unshift($out, '<option value=""'.($selected === false ? ' selected="selected"' : '').'> </option>'); 229 230 return n.tag(n.join(n, $out).n, 'select', array( 231 'id' => $select_id, 232 'name' => $select_name, 233 )); 234 } 235 236 /** 237 * Generic form input. 238 * 239 * @param string $type The input type 240 * @param string $name The input name 241 * @param string $value The value 242 * @param string $class The HTML class 243 * @param string $title The tooltip 244 * @param string $onClick Inline JavaScript attached to the click event 245 * @param int $size The input size 246 * @param int $tab The HTML tabindex 247 * @param string $id The HTML id 248 * @param bool $disabled If TRUE renders the input disabled 249 * @param bool $required If TRUE the field is marked as required 250 * @param string $placeholder The placeholder value displayed when the field is empty 251 * @return string HTML input 252 * @example 253 * echo fInput('text', 'myInput', 'My example value'); 254 */ 255 256 function fInput($type, $name, $value, $class = '', $title = '', $onClick = '', $size = 0, $tab = 0, $id = '', $disabled = false, $required = false, $placeholder = '') 257 { 258 $atts = join_atts(array( 259 'class' => $class, 260 'id' => $id, 261 'name' => $name, 262 'type' => $type, 263 'size' => (int) $size, 264 'title' => $title, 265 'onclick' => $onClick, 266 'tabindex' => (int) $tab, 267 'disabled' => (bool) $disabled, 268 'required' => (bool) $required, 269 'placeholder' => $placeholder, 270 ), TEXTPATTERN_STRIP_EMPTY); 271 272 if ($type != 'file' && $type != 'image') { 273 $atts .= join_atts(array('value' => (string) $value), TEXTPATTERN_STRIP_NONE); 274 } 275 276 return n.tag_void('input', $atts); 277 } 278 279 /** 280 * Sanitises a page title. 281 * 282 * @param string $text The input string 283 * @return string 284 * @deprecated in 4.2.0 285 * @see escape_title() 286 */ 287 288 function cleanfInput($text) 289 { 290 trigger_error(gTxt('deprecated_function_with', array('{name}' => __FUNCTION__, '{with}' => 'escape_title')), E_USER_NOTICE); 291 292 return escape_title($text); 293 } 294 295 /** 296 * Hidden form input. 297 * 298 * @param string $name The name 299 * @param string $value The value 300 * @return string HTML input 301 * @example 302 * echo hInput('myInput', 'hidden value'); 303 */ 304 305 function hInput($name, $value) 306 { 307 return fInput('hidden', $name, $value); 308 } 309 310 /** 311 * Hidden step input. 312 * 313 * @param string $step The step 314 * @return string HTML input 315 * @see form() 316 * @see eInput() 317 * @example 318 * echo form( 319 * eInput('event'). 320 * sInput('step') 321 * ); 322 */ 323 324 function sInput($step) 325 { 326 return hInput('step', $step); 327 } 328 329 /** 330 * Hidden event input. 331 * 332 * @param string $event The event 333 * @return string HTML input 334 * @see form() 335 * @see sInput() 336 * @example 337 * echo form( 338 * eInput('event'). 339 * sInput('step') 340 * ); 341 */ 342 343 function eInput($event) 344 { 345 return hInput('event', $event); 346 } 347 348 /** 349 * Hidden form token input. 350 * 351 * @return string A hidden HTML input containing a CSRF token 352 * @see bouncer() 353 * @see form_token() 354 */ 355 356 function tInput() 357 { 358 return hInput('_txp_token', form_token()); 359 } 360 361 /** 362 * A checkbox. 363 * 364 * @param string $name The field 365 * @param string $value The value 366 * @param bool $checked If TRUE the box is checked 367 * @param int $tabindex The HTML tabindex 368 * @param string $id The HTML id 369 * @return string HTML input 370 * @example 371 * echo checkbox('name', 'value', true); 372 */ 373 374 function checkbox($name, $value, $checked = true, $tabindex = 0, $id = '') 375 { 376 $class = 'checkbox'; 377 378 if ($checked) { 379 $class .= ' active'; 380 } 381 382 $atts = join_atts(array( 383 'class' => $class, 384 'id' => $id, 385 'name' => $name, 386 'type' => 'checkbox', 387 'checked' => (bool) $checked, 388 'tabindex' => (int) $tabindex, 389 ), TEXTPATTERN_STRIP_EMPTY); 390 391 $atts .= join_atts(array('value' => (string) $value), TEXTPATTERN_STRIP_NONE); 392 393 return n.tag_void('input', $atts); 394 } 395 396 /** 397 * A checkbox without an option to set the value. 398 * 399 * @param string $name The field 400 * @param bool $value If TRUE the box is checked 401 * @param int $tabindex The HTML tabindex 402 * @param string $id The HTML id 403 * @return string HTML input 404 * @access private 405 * @see checkbox() 406 */ 407 408 function checkbox2($name, $value, $tabindex = 0, $id = '') 409 { 410 return checkbox($name, 1, $value, $tabindex, $id); 411 } 412 413 /** 414 * A single radio button. 415 * 416 * @param string $name The field 417 * @param string $value The value 418 * @param bool $checked If TRUE, the button is selected 419 * @param string $id The HTML id 420 * @param int $tabindex The HTML tabindex 421 * @return string HTML input 422 */ 423 424 function radio($name, $value, $checked = true, $id = '', $tabindex = 0) 425 { 426 $class = 'radio'; 427 428 if ($checked) { 429 $class .= ' active'; 430 } 431 432 $atts = join_atts(array( 433 'class' => $class, 434 'id' => $id, 435 'name' => $name, 436 'type' => 'radio', 437 'checked' => (bool) $checked, 438 'tabindex' => (int) $tabindex, 439 ), TEXTPATTERN_STRIP_EMPTY); 440 441 $atts .= join_atts(array('value' => (string) $value), TEXTPATTERN_STRIP_NONE); 442 443 return n.tag_void('input', $atts); 444 } 445 446 /** 447 * Generates a form element. 448 * 449 * This form will contain a CSRF token if called on an authenticated page. 450 * 451 * @param string $contents The form contents 452 * @param string $style Inline styles added to the form 453 * @param string $onsubmit JavaScript run when the form is sent 454 * @param string $method The form method, e.g. "post", "get" 455 * @param string $class The HTML class 456 * @param string $fragment A URL fragment added to the form target 457 * @param string $id The HTML id 458 * @param string $role ARIA role name 459 * @return string HTML form element 460 */ 461 462 function form($contents, $style = '', $onsubmit = '', $method = 'post', $class = '', $fragment = '', $id = '', $role = '') 463 { 464 $action = 'index.php'; 465 466 if ($onsubmit) { 467 $onsubmit = 'return '.$onsubmit; 468 } 469 470 if ($fragment) { 471 $action .= '#'.$fragment; 472 } 473 474 return n.tag($contents.tInput().n, 'form', array( 475 'class' => $class, 476 'id' => $id, 477 'method' => $method, 478 'action' => $action, 479 'onsubmit' => $onsubmit, 480 'role' => $role, 481 'style' => $style, 482 )); 483 } 484 485 /** 486 * Gets and sanitises a field from a prefixed core database table. 487 * 488 * @param string $name The field 489 * @param string $event The table 490 * @param string $identifier The field used for selecting 491 * @param string $id The value used for selecting 492 * @return string HTML 493 * @access private 494 * @see fetch() 495 * @see txpspecialchars() 496 */ 497 498 function fetch_editable($name, $event, $identifier, $id) 499 { 500 $q = fetch($name, 'txp_'.$event, $identifier, $id); 501 502 return txpspecialchars($q); 503 } 504 505 /** 506 * A textarea. 507 * 508 * @param string $name The field 509 * @param int $h The field height in pixels 510 * @param int $w The field width in pixels 511 * @param string $thing The value 512 * @param string $id The HTML id 513 * @param int $rows Rows 514 * @param int $cols Columns 515 * @param string $placeholder The placeholder value displayed when the field is empty 516 * @return string HTML 517 */ 518 519 function text_area($name, $h = 0, $w = 0, $thing = '', $id = '', $rows = 5, $cols = 40, $placeholder = '') 520 { 521 $style = ''; 522 523 if ($w) { 524 $style .= 'width:'.intval($w).'px;'; 525 } 526 527 if ($h) { 528 $style .= 'height:'.intval($h).'px;'; 529 } 530 531 if ((string) $thing === '') { 532 $thing = null; 533 } else { 534 $thing = txpspecialchars($thing); 535 } 536 537 if (!intval($rows)) { 538 $rows = 5; 539 } 540 541 if (!intval($cols)) { 542 $cols = 40; 543 } 544 545 return n.tag($thing, 'textarea', array( 546 'id' => $id, 547 'name' => $name, 548 'rows' => (int) $rows, 549 'cols' => (int) $cols, 550 'style' => $style, 551 'placeholder' => $placeholder, 552 )); 553 } 554 555 /** 556 * Generates a select field with a name "type". 557 * 558 * @param array $options 559 * @return string 560 * @access private 561 * @see selectInput() 562 */ 563 564 function type_select($options) 565 { 566 return n.'<select name="type">'.type_options($options).'</select>'; 567 } 568 569 /** 570 * Generates a list of options for use in a select field. 571 * 572 * @param array $array 573 * @return string 574 * @access private 575 * @see selectInput() 576 */ 577 578 function type_options($array) 579 { 580 foreach ($array as $a => $b) { 581 $out[] = n.'<option value="'.$a.'">'.gTxt($b).'</option>'; 582 } 583 584 return join('', $out); 585 } 586 587 /** 588 * Generates a list of radio buttons wrapped in a unordered list. 589 * 590 * @param string $name The field 591 * @param array $values The values as an array array( $value => $label ) 592 * @param string $current_val The selected option. Takes a value from $value 593 * @param string $hilight_val The highlighted list item 594 * @param string|array $atts HTML attributes 595 * @return string HTML 596 */ 597 598 function radio_list($name, $values, $current_val = '', $hilight_val = '', $atts = array('class' => 'plain-list')) 599 { 600 foreach ($values as $value => $label) { 601 $id = $name.'-'.$value; 602 $class = 'status-'.$value; 603 604 if ((string) $value === (string) $hilight_val) { 605 $label = strong($label); 606 $class .= ' active'; 607 } 608 609 $out[] = tag( 610 radio($name, $value, ((string) $current_val === (string) $value), $id). 611 n.tag($label, 'label', array('for' => $id)), 612 'li', array('class' => $class) 613 ); 614 } 615 616 return tag(n.join(n, $out).n, 'ul', $atts); 617 } 618 619 /** 620 * Generates a field used to store and set a date. 621 * 622 * @param string $name The field 623 * @param string $datevar The strftime format the date is displayed 624 * @param int $time The displayed date as a UNIX timestamp 625 * @param int $tab The HTML tabindex 626 * @param string $id The HTML id 627 * @return string HTML 628 * @access private 629 * @example 630 * echo tsi('year', '%Y', 1200000000); 631 */ 632 633 function tsi($name, $datevar, $time, $tab = 0, $id = '') 634 { 635 static $placeholders = array( 636 '%Y' => 'yyyy', 637 '%m' => 'mm', 638 '%d' => 'dd', 639 '%H' => 'hh', 640 '%M' => 'mn', 641 '%S' => 'ss', 642 ); 643 644 $value = $placeholder = ''; 645 $size = INPUT_TINY; 646 $pattern = '([0-5][0-9])'; 647 648 if ((int) $time) { 649 $value = safe_strftime($datevar, (int) $time); 650 } 651 652 if (isset($placeholders[$datevar])) { 653 $placeholder = gTxt($placeholders[$datevar]); 654 } 655 656 if ($datevar == '%Y' || $name == 'year' || $name == 'exp_year') { 657 $class = 'input-year'; 658 $size = INPUT_XSMALL; 659 $pattern = '[0-9]{4}'; 660 } 661 662 if ($datevar == '%m' || $name == 'month' || $name == 'exp_month') { 663 $class = 'input-month'; 664 $pattern = '(0[1-9]|1[012])'; 665 } 666 667 if ($datevar == '%d' || $name == 'day' || $name == 'exp_day') { 668 $class = 'input-day'; 669 $pattern = '(0[1-9]|1[0-9]|2[0-9]|3[01])'; 670 } 671 672 if ($datevar == '%H' || $name == 'hour' || $name == 'exp_hour') { 673 $class = 'input-hour'; 674 $pattern = '(0[0-9]|1[0-9]|2[0-3])'; 675 } 676 677 if ($datevar == '%M' || $name == 'minute' || $name == 'exp_minute') { 678 $class = 'input-minute'; 679 } 680 681 if ($datevar == '%S' || $name == 'second' || $name == 'exp_second') { 682 $class = 'input-second'; 683 } 684 685 return n.tag_void('input', array( 686 'class' => $class, 687 'id' => $id, 688 'name' => $name, 689 'type' => 'text', 690 'inputmode' => 'numeric', 691 'pattern' => $pattern, 692 'size' => (int) $size, 693 'maxlength' => $size, 694 'title' => gTxt('article_'.$name), 695 'aria-label' => gTxt('article_'.$name), 696 'placeholder' => $placeholder, 697 'tabindex' => (int) $tab, 698 'value' => $value, 699 )); 700 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
title