Files
oav/dotclear._no/inc/libs/clearbricks/common/lib.form.php
2023-03-20 12:18:38 +01:00

747 lines
30 KiB
PHP

<?php
/**
* @class form
* @brief HTML Forms creation helpers
*
* @package Clearbricks
* @subpackage Common
*
* @copyright Olivier Meunier & Association Dotclear
* @copyright GPL-2.0-only
*/
class form
{
/**
* return id and name from given argument
*
* @param string|array $nid input argument
* @param string &$name returned name
* @param string &$id returned id
*
* @static
* @access private
*/
private static function getNameAndId($nid, &$name, &$id)
{
if (is_array($nid)) {
$name = $nid[0];
$id = !empty($nid[1]) ? $nid[1] : null;
} else {
$name = $id = $nid;
}
}
/**
* return an associative array of optional parameters of a class method
*
* @param string $class class name
* @param string $method method name
* @return array
*
* @static
* @access private
*/
private static function getDefaults($class, $method)
{
$options = [];
$reflect = new ReflectionMethod($class, $method);
foreach ($reflect->getParameters() as $param) {
if ($param->isOptional()) {
$options[$param->getName()] = $param->getDefaultValue();
}
}
return $options;
}
/**
* Select Box
*
* Returns HTML code for a select box.
* **$nid** could be a string or an array of name and ID.
* **$data** is an array with option titles keys and values in values
* or an array of object of type {@link formSelectOption}. If **$data** is an array of
* arrays, optgroups will be created.
*
* **$default** could be a string or an associative array of any of optional parameters:
*
* ```php
* form::combo(['name', 'id'], $data, ['class' => 'maximal', 'extra_html' => 'data-language="php"']);
* ```
*
* @uses formSelectOption
*
* @param string|array $nid Element ID and name
* @param mixed $data Select box data
* @param string|array $default Default value in select box | associative array of optional parameters
* @param string $class Element class name
* @param string $tabindex Element tabindex
* @param boolean $disabled True if disabled
* @param string $extra_html Extra HTML attributes
*
* @return string
*
* @static
*/
public static function combo($nid, $data, $default = '', $class = '', $tabindex = '',
$disabled = false, $extra_html = '') {
self::getNameAndId($nid, $name, $id);
if (func_num_args() > 2 && is_array($default)) {
// Cope with associative array of optional parameters
$options = self::getDefaults(__CLASS__, __FUNCTION__);
extract(array_merge($options, array_intersect_key($default, $options)));
}
return '<select name="' . $name . '" ' .
($id ? 'id="' . $id . '" ' : '') .
($class ? 'class="' . $class . '" ' : '') .
($tabindex ? 'tabindex="' . $tabindex . '" ' : '') .
($disabled ? 'disabled="disabled" ' : '') .
$extra_html .
'>' . "\n" .
self::comboOptions($data, $default) .
'</select>' . "\n";
}
private static function comboOptions($data, $default)
{
$res = '';
$option = '<option value="%1$s"%3$s>%2$s</option>' . "\n";
$optgroup = '<optgroup label="%1$s">' . "\n" . '%2$s' . "</optgroup>\n";
foreach ($data as $k => $v) {
if (is_array($v)) {
$res .= sprintf($optgroup, $k, self::comboOptions($v, $default));
} elseif ($v instanceof formSelectOption) {
$res .= $v->render($default);
} else {
$s = ((string) $v == (string) $default) ? ' selected="selected"' : '';
$res .= sprintf($option, $v, $k, $s);
}
}
return $res;
}
/**
* Radio button
*
* Returns HTML code for a radio button.
* $nid could be a string or an array of name and ID.
* $checked could be a boolean or an associative array of any of optional parameters
*
* @param string|array $nid Element ID and name
* @param string $value Element value
* @param boolean|array $checked True if checked | associative array of optional parameters
* @param string $class Element class name
* @param string $tabindex Element tabindex
* @param boolean $disabled True if disabled
* @param string $extra_html Extra HTML attributes
*
* @return string
*
* @static
*/
public static function radio($nid, $value, $checked = '', $class = '', $tabindex = '',
$disabled = false, $extra_html = '') {
self::getNameAndId($nid, $name, $id);
if (func_num_args() > 2 && is_array($checked)) {
// Cope with associative array of optional parameters
$options = self::getDefaults(__CLASS__, __FUNCTION__);
extract(array_merge($options, array_intersect_key($checked, $options)));
}
return '<input type="radio" name="' . $name . '" value="' . $value . '" ' .
($id ? 'id="' . $id . '" ' : '') .
($checked ? 'checked="checked" ' : '') .
($class ? 'class="' . $class . '" ' : '') .
($tabindex ? 'tabindex="' . $tabindex . '" ' : '') .
($disabled ? 'disabled="disabled" ' : '') .
$extra_html .
'/>' . "\n";
}
/**
* Checkbox
*
* Returns HTML code for a checkbox.
* $nid could be a string or an array of name and ID.
* $checked could be a boolean or an associative array of any of optional parameters
*
* @param string|array $nid Element ID and name
* @param string $value Element value
* @param boolean|array $checked True if checked | associative array of optional parameters
* @param string $class Element class name
* @param string $tabindex Element tabindex
* @param boolean $disabled True if disabled
* @param string $extra_html Extra HTML attributes
*
* @return string
*
* @static
*/
public static function checkbox($nid, $value, $checked = '', $class = '', $tabindex = '',
$disabled = false, $extra_html = '') {
self::getNameAndId($nid, $name, $id);
if (func_num_args() > 2 && is_array($checked)) {
// Cope with associative array of optional parameters
$options = self::getDefaults(__CLASS__, __FUNCTION__);
extract(array_merge($options, array_intersect_key($checked, $options)));
}
return '<input type="checkbox" name="' . $name . '" value="' . $value . '" ' .
($id ? 'id="' . $id . '" ' : '') .
($checked ? 'checked="checked" ' : '') .
($class ? 'class="' . $class . '" ' : '') .
($tabindex ? 'tabindex="' . $tabindex . '" ' : '') .
($disabled ? 'disabled="disabled" ' : '') .
$extra_html .
' />' . "\n";
}
/**
* Input field
*
* Returns HTML code for an input field.
* $nid could be a string or an array of name and ID.
* $default could be a string or an associative array of any of optional parameters
*
* @param string|array $nid Element ID and name
* @param integer $size Element size
* @param integer $max Element maxlength
* @param string|array $default Element value | associative array of optional parameters
* @param string $class Element class name
* @param string $tabindex Element tabindex
* @param boolean $disabled True if disabled
* @param string $extra_html Extra HTML attributes
* @param boolean $required Element is required
* @param string $type Input type
* @param string $autocomplete Autocomplete attributes if relevant
*
* @return string
*
* @static
*/
public static function field($nid, $size, $max, $default = '', $class = '', $tabindex = '',
$disabled = false, $extra_html = '', $required = false, $type = 'text', $autocomplete = '') {
self::getNameAndId($nid, $name, $id);
if (func_num_args() > 3 && is_array($default)) {
// Cope with associative array of optional parameters
$options = self::getDefaults(__CLASS__, __FUNCTION__);
extract(array_merge($options, array_intersect_key($default, $options)));
}
return '<input type="' . $type . '" size="' . $size . '" name="' . $name . '" ' .
($id ? 'id="' . $id . '" ' : '') .
($max ? 'maxlength="' . $max . '" ' : '') .
($default || $default === '0' ? 'value="' . $default . '" ' : '') .
($class ? 'class="' . $class . '" ' : '') .
($tabindex ? 'tabindex="' . $tabindex . '" ' : '') .
($disabled ? 'disabled="disabled" ' : '') .
($required ? 'required ' : '') .
($autocomplete ? 'autocomplete="' . $autocomplete . '" ' : '') .
$extra_html .
' />' . "\n";
}
/**
* Password field
*
* Returns HTML code for a password field.
* $nid could be a string or an array of name and ID.
* $default could be a string or an associative array of any of optional parameters
*
* @uses form::field
*
* @param string|array $nid Element ID and name
* @param integer $size Element size
* @param integer $max Element maxlength
* @param string|array $default Element value | associative array of optional parameters
* @param string $class Element class name
* @param string $tabindex Element tabindex
* @param boolean $disabled True if disabled
* @param string $extra_html Extra HTML attributes
* @param boolean $required Element is required
* @param string $autocomplete Autocomplete attributes if relevant (new-password/current-password)
*
* @return string
*
* @static
*/
public static function password($nid, $size, $max, $default = '', $class = '', $tabindex = '',
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
if (func_num_args() > 3 && is_array($default)) {
// Cope with associative array of optional parameters
$options = self::getDefaults(__CLASS__, __FUNCTION__);
extract(array_merge($options, array_intersect_key($default, $options)));
}
return self::field($nid, $size, $max, $default, $class, $tabindex, $disabled, $extra_html,
$required, 'password', $autocomplete);
}
/**
* HTML5 Color field
*
* Returns HTML code for an input color field.
* $nid could be a string or an array of name and ID.
* $size could be a integer or an associative array of any of optional parameters
*
* @uses form::field
*
* @param string|array $nid Element ID and name
* @param integer|array $size Element size | associative array of optional parameters
* @param integer $max Element maxlength
* @param string $default Element value
* @param string $class Element class name
* @param string $tabindex Element tabindex
* @param boolean $disabled True if disabled
* @param string $extra_html Extra HTML attributes
* @param boolean $required Element is required
* @param string $autocomplete Autocomplete attributes if relevant
*
* @return string
*
* @static
*/
public static function color($nid, $size = 7, $max = 7, $default = '', $class = '', $tabindex = '',
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
if (func_num_args() > 1 && is_array($size)) {
// Cope with associative array of optional parameters
$options = self::getDefaults(__CLASS__, __FUNCTION__);
extract(array_merge($options, array_intersect_key($size, $options)));
}
return self::field($nid, $size, $max, $default, $class, $tabindex, $disabled, $extra_html,
$required, 'color', $autocomplete);
}
/**
* HTML5 Email field
*
* Returns HTML code for an input email field.
* $nid could be a string or an array of name and ID.
* $size could be a integer or an associative array of any of optional parameters
*
* @uses form::field
*
* @param string|array $nid Element ID and name
* @param integer|array $size Element size | associative array of optional parameters
* @param integer $max Element maxlength
* @param string $default Element value
* @param string $class Element class name
* @param string $tabindex Element tabindex
* @param boolean $disabled True if disabled
* @param string $extra_html Extra HTML attributes
* @param boolean $required Element is required
* @param string $autocomplete Autocomplete attributes if relevant
*
* @return string
*
* @static
*/
public static function email($nid, $size = 20, $max = 255, $default = '', $class = '', $tabindex = '',
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
if (func_num_args() > 1 && is_array($size)) {
// Cope with associative array of optional parameters
$options = self::getDefaults(__CLASS__, __FUNCTION__);
extract(array_merge($options, array_intersect_key($size, $options)));
}
return self::field($nid, $size, $max, $default, $class, $tabindex, $disabled, $extra_html,
$required, 'email', $autocomplete);
}
/**
* HTML5 URL field
*
* Returns HTML code for an input (absolute) URL field.
* $nid could be a string or an array of name and ID.
* $size could be a integer or an associative array of any of optional parameters
*
* @uses form::field
*
* @param string|array $nid Element ID and name
* @param integer|array $size Element size | associative array of optional parameters
* @param integer $max Element maxlength
* @param string $default Element value
* @param string $class Element class name
* @param string $tabindex Element tabindex
* @param boolean $disabled True if disabled
* @param string $extra_html Extra HTML attributes
* @param boolean $required Element is required
* @param string $autocomplete Autocomplete attributes if relevant
*
* @return string
*
* @static
*/
public static function url($nid, $size = 20, $max = 255, $default = '', $class = '', $tabindex = '',
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
if (func_num_args() > 1 && is_array($size)) {
// Cope with associative array of optional parameters
$options = self::getDefaults(__CLASS__, __FUNCTION__);
extract(array_merge($options, array_intersect_key($size, $options)));
}
return self::field($nid, $size, $max, $default, $class, $tabindex, $disabled, $extra_html,
$required, 'url', $autocomplete);
}
/**
* HTML5 Datetime (local) field
*
* Returns HTML code for an input datetime field.
* $nid could be a string or an array of name and ID.
* $size could be a integer or an associative array of any of optional parameters
*
* @uses form::field
*
* @param string|array $nid Element ID and name
* @param integer|array $size Element size | associative array of optional parameters
* @param integer $max Element maxlength
* @param string $default Element value (in YYYY-MM-DDThh:mm format)
* @param string $class Element class name
* @param string $tabindex Element tabindex
* @param boolean $disabled True if disabled
* @param string $extra_html Extra HTML attributes
* @param boolean $required Element is required
* @param string $autocomplete Autocomplete attributes if relevant
*
* @return string
*
* @static
*/
public static function datetime($nid, $size = 16, $max = 16, $default = '', $class = '', $tabindex = '',
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
if (func_num_args() > 1 && is_array($size)) {
// Cope with associative array of optional parameters
$options = self::getDefaults(__CLASS__, __FUNCTION__);
extract(array_merge($options, array_intersect_key($size, $options)));
}
// Cope with unimplemented input type for some browser (type="text" + pattern + placeholder)
if (strpos(strtolower($extra_html), 'pattern=') === false) {
$extra_html .= ' pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}"';
}
if (strpos(strtolower($extra_html), 'placeholder') === false) {
$extra_html .= ' placeholder="1962-05-13T14:45"';
}
return self::field($nid, $size, $max, $default, $class, $tabindex, $disabled, $extra_html,
$required, 'datetime-local', $autocomplete);
}
/**
* HTML5 Date field
*
* Returns HTML code for an input date field.
* $nid could be a string or an array of name and ID.
* $size could be a integer or an associative array of any of optional parameters
*
* @uses form::field
*
* @param string|array $nid Element ID and name
* @param integer|array $size Element size | associative array of optional parameters
* @param integer $max Element maxlength
* @param string $default Element value (in YYYY-MM-DD format)
* @param string $class Element class name
* @param string $tabindex Element tabindex
* @param boolean $disabled True if disabled
* @param string $extra_html Extra HTML attributes
* @param boolean $required Element is required
* @param string $autocomplete Autocomplete attributes if relevant
*
* @return string
*
* @static
*/
public static function date($nid, $size = 10, $max = 10, $default = '', $class = '', $tabindex = '',
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
if (func_num_args() > 1 && is_array($size)) {
// Cope with associative array of optional parameters
$options = self::getDefaults(__CLASS__, __FUNCTION__);
extract(array_merge($options, array_intersect_key($size, $options)));
}
// Cope with unimplemented input type for some browser (type="text" + pattern + placeholder)
if (strpos(strtolower($extra_html), 'pattern=') === false) {
$extra_html .= ' pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}"';
}
if (strpos(strtolower($extra_html), 'placeholder') === false) {
$extra_html .= ' placeholder="1962-05-13"';
}
return self::field($nid, $size, $max, $default, $class, $tabindex, $disabled, $extra_html,
$required, 'date', $autocomplete);
}
/**
* HTML5 Time (local) field
*
* Returns HTML code for an input time field.
* $nid could be a string or an array of name and ID.
* $size could be a integer or an associative array of any of optional parameters
*
* @uses form::field
*
* @param string|array $nid Element ID and name
* @param integer|array $size Element size | associative array of optional parameters
* @param integer $max Element maxlength
* @param string $default Element value (in hh:mm format)
* @param string $class Element class name
* @param string $tabindex Element tabindex
* @param boolean $disabled True if disabled
* @param string $extra_html Extra HTML attributes
* @param boolean $required Element is required
* @param string $autocomplete Autocomplete attributes if relevant
*
* @return string
*
* @static
*/
public static function time($nid, $size = 5, $max = 5, $default = '', $class = '', $tabindex = '',
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
if (func_num_args() > 1 && is_array($size)) {
// Cope with associative array of optional parameters
$options = self::getDefaults(__CLASS__, __FUNCTION__);
extract(array_merge($options, array_intersect_key($size, $options)));
}
// Cope with unimplemented input type for some browser (type="text" + pattern + placeholder)
if (strpos(strtolower($extra_html), 'pattern=') === false) {
$extra_html .= ' pattern="[0-9]{2}:[0-9]{2}"';
}
if (strpos(strtolower($extra_html), 'placeholder') === false) {
$extra_html .= ' placeholder="14:45"';
}
return self::field($nid, $size, $max, $default, $class, $tabindex, $disabled, $extra_html,
$required, 'time', $autocomplete);
}
/**
* HTML5 file field
*
* Returns HTML code for an input file field.
* $nid could be a string or an array of name and ID.
* $default could be a integer or an associative array of any of optional parameters
*
* @param string|array $nid Element ID and name
* @param string|array $default Element value | associative array of optional parameters
* @param string $class Element class name
* @param string $tabindex Element tabindex
* @param boolean $disabled True if disabled
* @param string $extra_html Extra HTML attributes
* @param boolean $required Element is required
*
* @return string
*
* @static
*/
public static function file($nid, $default = '', $class = '', $tabindex = '', $disabled = false, $extra_html = '',
$required = false) {
self::getNameAndId($nid, $name, $id);
if (func_num_args() > 1 && is_array($default)) {
// Cope with associative array of optional parameters
$options = self::getDefaults(__CLASS__, __FUNCTION__);
extract(array_merge($options, array_intersect_key($default, $options)));
}
return '<input type="file" ' . '" name="' . $name . '" ' .
($id ? 'id="' . $id . '" ' : '') .
($default || $default === '0' ? 'value="' . $default . '" ' : '') .
($class ? 'class="' . $class . '" ' : '') .
($tabindex ? 'tabindex="' . $tabindex . '" ' : '') .
($disabled ? 'disabled="disabled" ' : '') .
($required ? 'required ' : '') .
$extra_html .
' />' . "\n";
}
/**
* HTML5 number input field
*
* Returns HTML code for an number input field.
* $nid could be a string or an array of name and ID.
* $min could be a string or an associative array of any of optional parameters
*
* @param string|array $nid Element ID and name
* @param integer|array $min Element min value (may be negative) | associative array of optional parameters
* @param integer $max Element max value (may be negative)
* @param string $default Element value
* @param string $class Element class name
* @param string $tabindex Element tabindex
* @param boolean $disabled True if disabled
* @param string $extra_html Extra HTML attributes
* @param boolean $required Element is required
* @param string $autocomplete Autocomplete attributes if relevant
*
* @return string
*
* @static
*/
public static function number($nid, $min = null, $max = null, $default = '', $class = '', $tabindex = '',
$disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
self::getNameAndId($nid, $name, $id);
if (func_num_args() > 1 && is_array($min)) {
// Cope with associative array of optional parameters
$options = self::getDefaults(__CLASS__, __FUNCTION__);
extract(array_merge($options, array_intersect_key($min, $options)));
}
return '<input type="number" name="' . $name . '" ' .
($id ? 'id="' . $id . '" ' : '') .
($min !== null ? 'min="' . $min . '" ' : '') .
($max !== null ? 'max="' . $max . '" ' : '') .
($default || $default === '0' ? 'value="' . $default . '" ' : '') .
($class ? 'class="' . $class . '" ' : '') .
($tabindex ? 'tabindex="' . $tabindex . '" ' : '') .
($disabled ? 'disabled="disabled" ' : '') .
($required ? 'required ' : '') .
($autocomplete ? 'autocomplete="' . $autocomplete . '" ' : '') .
$extra_html .
' />' . "\n";
}
/**
* Textarea
*
* Returns HTML code for a textarea.
* $nid could be a string or an array of name and ID.
* $default could be a string or an associative array of any of optional parameters
*
* @param string|array $nid Element ID and name
* @param integer $cols Number of columns
* @param integer $rows Number of rows
* @param string|array $default Element value | associative array of optional parameters
* @param string $class Element class name
* @param string $tabindex Element tabindex
* @param boolean $disabled True if disabled
* @param string $extra_html Extra HTML attributes
* @param boolean $required Element is required
* @param string $autocomplete Autocomplete attributes if relevant
*
* @return string
*
* @static
*/
public static function textArea($nid, $cols, $rows, $default = '', $class = '',
$tabindex = '', $disabled = false, $extra_html = '', $required = false, $autocomplete = '') {
self::getNameAndId($nid, $name, $id);
if (func_num_args() > 3 && is_array($default)) {
// Cope with associative array of optional parameters
$options = self::getDefaults(__CLASS__, __FUNCTION__);
extract(array_merge($options, array_intersect_key($default, $options)));
}
return '<textarea cols="' . $cols . '" rows="' . $rows . '" name="' . $name . '" ' .
($id ? 'id="' . $id . '" ' : '') .
($tabindex != '' ? 'tabindex="' . $tabindex . '" ' : '') .
($class ? 'class="' . $class . '" ' : '') .
($disabled ? 'disabled="disabled" ' : '') .
($required ? 'required ' : '') .
($autocomplete ? 'autocomplete="' . $autocomplete . '" ' : '') .
$extra_html . '>' . $default . '</textarea>' . "\n";
}
/**
* Hidden field
*
* Returns HTML code for an hidden field. $nid could be a string or an array of
* name and ID.
*
* @param string|array $nid Element ID and name
* @param string $value Element value
*
* @return string
*
* @static
*/
public static function hidden($nid, $value)
{
self::getNameAndId($nid, $name, $id);
return '<input type="hidden" name="' . $name . '" value="' . $value . '" ' .
($id ? 'id="' . $id . '" ' : '') .
' />' . "\n";
}
}
/**
* @class formSelectOption
* @brief HTML Forms creation helpers
*
* @package Clearbricks
* @subpackage Common
*/
class formSelectOption
{
public $name; ///< Option name
public $value; ///< Option value
public $class_name; ///< Element class name
public $html; ///< Extra HTML attributes
/**
* sprintf template for option
* @var string $option
* @access private
*/
private $option = '<option value="%1$s"%3$s>%2$s</option>' . "\n";
/**
* Option constructor
*
* @param string $name Option name
* @param string $value Option value
* @param string $class_name Element class name
* @param string $html Extra HTML attributes
*/
public function __construct($name, $value, $class_name = '', $html = '')
{
$this->name = $name;
$this->value = $value;
$this->class_name = $class_name;
$this->html = $html;
}
/**
* Option renderer
*
* Returns option HTML code
*
* @param boolean $default Option is selected
* @return string
*/
public function render($default)
{
$attr = $this->html ? ' ' . $this->html : '';
$attr .= $this->class_name ? ' class="' . $this->class_name . '"' : '';
if ($this->value == $default) {
$attr .= ' selected="selected"';
}
return sprintf($this->option, $this->value, $this->name, $attr) . "\n";
}
}