Seditio Source
Root |
./othercms/dotclear-2.22/inc/libs/clearbricks/common/lib.forms.php
<?php

declare(strict_types=1);

/**
 * @class forms
 * @brief HTML Forms creation helpers
 *
 * @package Clearbricks
 * @subpackage Common
 *
 * @since 1.2 First time this was introduced.
 *
 * @copyright Olivier Meunier & Association Dotclear
 * @copyright GPL-2.0-only
 */
class forms
{
   
/**
     * Add common attributes
     *
     * @param      array   $params          The parameters
     *      $params[
     *          'name'          => string name (required if id is not provided).
     *          'id'            => string id (required if name is not provided).
     *          'value'         => string value.
     *          'default'       => string default value (will be used if value is not provided).
     *          'autocomplete'  => string autocomplete type.
     *          'autofocus'     => boolean autofocus.
     *          'class'         => string class(es).
     *          'disabled'      => boolean disabled.
     *          'form'          => string form id.
     *          'lang'          => string lang
     *          'list'          => string list id.
     *          'readonly'      => boolean readonly.
     *          'required'      => boolean required.
     *          'spellcheck'    => boolean spellcheck
     *          'tabindex'      => int tabindex.
     *          'data'          => array data.
     *              [
     *                  key => string data id (rendered as data-<id>).
     *                  value => string data value.
     *              ]
     *          'extra'         => string extra HTML attributes.
     *      ]
     * @param      bool    $includeValue    Includes $params['value'] if exist
     *
     * @return     string
     */
   
protected static function commonAttributes(array $params, bool $includeValue = true): string
   
{
       
$render = '' .

           
// Identifier
            // - use $params['name'] for name attribute else $params['id'] if exists
            // - use $params['id'] for id attribute else $params['name'] if exists
           
(isset($params['name']) ?
               
' name="' . $params['name'] . '"' :
                (isset(
$params['id']) ? ' name="' . $params['id'] . '"' : '')) .
            (isset(
$params['id']) ?
               
' id="' . $params['id'] . '"' :
                (isset(
$params['name']) ? ' id="' . $params['name'] . '"' : '')) .

           
// Value
            // - $params['default'] will be used as value if exists and $params['value'] does not
           
($includeValue && array_key_exists('value', $params) ?
               
' value="' . $params['value'] . '"' : '') .
            (
$includeValue && !array_key_exists('value', $params) && array_key_exists('default', $params) ?
               
' value="' . $params['default'] . '"' : '') .
            (isset(
$params['checked']) && $params['checked'] ?
               
' checked' : '') .

           
// Common attributes
           
(isset($params['autocomplete']) ?
               
' autocomplete="' . $params['autocomplete'] . '"' : '') .
            (isset(
$params['autofocus']) && $params['autofocus'] ?
               
' autofocus' : '') .
            (isset(
$params['class']) ?
               
' class="' . (is_array($params['class']) ? implode(' ', $params['class']) : $params['class']) . '"' : '') .
            (isset(
$params['disabled']) && $params['disabled'] ?
               
' disabled' : '') .
            (isset(
$params['form']) ?
               
' form="' . $params['form'] . '"' : '') .
            (isset(
$params['list']) ?
               
' list="' . $params['list'] . '"' : '') .
            (isset(
$params['readonly']) && $params['readonly'] ?
               
' readonly' : '') .
            (isset(
$params['required']) && $params['required'] ?
               
' required' : '') .
            (isset(
$params['lang']) ?
               
' lang="' . $params['lang'] . '"' : '') .
            (isset(
$params['spellcheck']) ?
               
' spellcheck="' . $params['spellcheck'] . '"' : '') .
            (
array_key_exists('tabindex', $params) ?
               
' tabindex="' . strval((int) $params['tabindex']) . '"' : '') .

       
'';

        if (isset(
$params['data']) && is_array($params['data'])) {
           
// Data attributes
           
foreach ($params['data'] as $key => $value) {
               
$render .= ' data-' . $key . '="' . $value . '"';
            }
        }

        if (isset(
$params['extra'])) {
           
// Extra HTML
           
$render .= ' ' . (is_array($params['extra']) ? implode(' ', $params['extra']) : $params['extra']);
        }

        return
$render;
    }

   
/**
     * Check mandatory attributes in parameters, at least name or id must be present
     *
     * @param      array  $params  The parameters
     *
     * @return     bool
     */
   
protected static function checkAttributes(array $params): bool
   
{
       
// Check for mandatory info
       
return (isset($params['name']) || isset($params['id']));
    }

   
/**
     * Select Box
     *
     * Returns HTML code for a select box.
     * **$params['items']** is an array with option titles keys and values in values
     * or an array of object of type {@link formSelectOption}.
     * or an array of object of type {@link formsSelectOption}.
     * If **$params['items']** is an array of arrays, optgroups will be created.
     *
     * @uses form::formSelectOption
     *
     * @param array         $params     Select parameters
     *      $param[
     *          'name' and/or 'id'  => string name and or id (required).
     *          'items'             => mixed combo items (see above).
     *          …                   => see {@link commonAttributes}.
     *      ]
     *
     * @return string
     *
     * @static
     */
   
public static function combo(array $params): string
   
{
       
// Check for mandatory info
       
if (!self::checkAttributes($params)) {
            return
'';
        }

        return
'<select' . self::commonAttributes($params) . '>' . "\n" .
            (isset(
$params['items']) ? self::comboOptions($params['items'], $params['default'] ?? null) : '') .
           
'</select>' . "\n";
    }

    private static function
comboOptions(array $items, $default = null): string
   
{
       
$render   = '';
       
$option   = '<option value="%1$s"%3$s>%2$s</option>' . "\n";
       
$optgroup = '<optgroup label="%1$s">' . "\n" . '%2$s' . "</optgroup>\n";

        foreach (
$items as $key => $value) {
            if (
is_array($value)) {
               
$render .= sprintf($optgroup, $key, self::comboOptions($value, $default));
            } elseif (
$value instanceof formsSelectOption) {
               
$render .= $value->render($default);
            } elseif (
$value instanceof formSelectOption) { // Old class, for compatibility purpose
               
$render .= $value->render($default);
            } else {
               
$selected = ((string) $value == (string) $default) ? ' selected' : '';
               
$render .= sprintf($option, $value, $key, $selected);
            }
        }

        return
$render;
    }

   
/**
     * Radio button
     *
     * Returns HTML code for a radio button.
     *
     * @param array         $params     Radio parameters
     *      $param[
     *          'name' and/or 'id'  => string name and or id (required).
     *          …                   => see {@link commonAttributes}.
     *      ]
     *
     * @return string
     *
     * @static
     */
   
public static function radio(array $params): string
   
{
       
// Check for mandatory info
       
if (!self::checkAttributes($params)) {
            return
'';
        }

        return
'<input type="radio"' . self::commonAttributes($params) . '/>' . "\n";
    }

   
/**
     * Checkbox
     *
     * Returns HTML code for a checkbox.
     *
     * @param array         $params     Checkbox parameters
     *      $param[
     *          'name' and/or 'id'  => string name and or id (required).
     *          …                   => see {@link commonAttributes}.
     *      ]
     *
     * @return string
     *
     * @static
     */
   
public static function checkbox(array $params): string
   
{
       
// Check for mandatory info
       
if (!self::checkAttributes($params)) {
            return
'';
        }

        return
'<input type="checkbox"' . self::commonAttributes($params) . '/>' . "\n";
    }

   
/**
     * Input field
     *
     * Returns HTML code for an input field.
     *
     * @param array         $params     Field parameters
     *      $param[
     *          'name' and/or 'id'  => string name and or id (required).
     *          'type'              => string type of input (default = text).
     *          'size'              => int number of visible characters.
     *          'maxlength'         => int number of max characters.
     *          …                   => see {@link commonAttributes}.
     *      ]
     *
     * @return string
     *
     * @static
     */
   
public static function field(array $params): string
   
{
       
// Check for mandatory info
       
if (!self::checkAttributes($params)) {
            return
'';
        }

        return
'<input type="' . ($params['type'] ?? 'text') . '"' . self::commonAttributes($params) .
            (isset(
$params['size']) ? ' size="' . strval((int) $params['size']) . '"' : '') .
            (isset(
$params['maxlength']) ? ' maxlength="' . strval((int) $params['maxlength']) . '"' : '') .
           
'/>' . "\n";
    }

   
/**
     * Password field
     *
     * Returns HTML code for a password field.
     *
     * @uses forms::field
     *
     * @param array         $params     Password field parameters
     *      $param[
     *          'name' and/or 'id'  => string name and or id (required).
     *          …                   => see {@link commonAttributes}.
     *      ]
     *
     * @return string
     *
     * @static
     */
   
public static function password(array $params): string
   
{
        return
self::field(array_merge(
            [
               
'type' => 'password',
            ],
           
$params
       
));
    }

   
/**
     * HTML5 Color field
     *
     * Returns HTML code for an input color field.
     *
     * @uses forms::field
     *
     * @param array         $params     Color field parameters
     *      $param[
     *          'name' and/or 'id'  => string name and or id (required).
     *          'size'              => int number of visible characters (default = 7).
     *          'maxlength'         => int number of max characters (default = 7).
     *          …                   => see {@link commonAttributes}.
     *      ]
     *
     * @return string
     *
     * @static
     */
   
public static function color(array $params): string
   
{
        return
self::field(array_merge(
            [
               
'type'      => 'color',
               
'size'      => 7,
               
'maxlength' => 7,
            ],
           
$params
       
));
    }

   
/**
     * HTML5 Email field
     *
     * Returns HTML code for an input email field.
     *
     * @uses forms::field
     *
     * @param array         $params     Email field parameters
     *      $param[
     *          'name' and/or 'id'  => string name and or id (required).
     *          'size'              => int number of visible characters (default = 20).
     *          'maxlength'         => int number of max characters (default = 255).
     *          …                   => see {@link commonAttributes}.
     *      ]
     *
     * @return string
     *
     * @static
     */
   
public static function email(array $params): string
   
{
        return
self::field(array_merge(
            [
               
'type'      => 'email',
               
'size'      => 20,
               
'maxlength' => 255,
            ],
           
$params
       
));
    }

   
/**
     * HTML5 URL field
     *
     * Returns HTML code for an input (absolute) URL field.
     *
     * @uses forms::field
     *
     * @param array         $params     Email field parameters
     *      $param[
     *          'name' and/or 'id'  => string name and or id (required).
     *          'size'              => int number of visible characters (default = 20).
     *          'maxlength'         => int number of max characters (default = 255).
     *          …                   => see {@link commonAttributes}.
     *      ]
     *
     * @return string
     *
     * @static
     */
   
public static function url(array $params): string
   
{
        return
self::field(array_merge(
            [
               
'type'      => 'url',
               
'size'      => 20,
               
'maxlength' => 255,
            ],
           
$params
       
));
    }

   
/**
     * HTML5 Datetime (local) field
     *
     * Returns HTML code for an input datetime field.
     *
     * @uses forms::field
     *
     * @param array         $params     Email field parameters
     *      $param[
     *          'name' and/or 'id'  => string name and or id (required).
     *          'size'              => int number of visible characters (default = 16).
     *          'maxlength'         => int number of max characters (default = 16).
     *          …                   => see {@link commonAttributes}.
     *      ]
     *
     * @return string
     *
     * @static
     */
   
public static function datetime(array $params): string
   
{
       
// Cope with unimplemented input type for some browser (type="text" + pattern + placeholder)
       
$extra = [];
        if (
strpos(strtolower(($params['extra']) ?? ''), 'pattern=') === false) {
           
$extra[] = 'pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}"';
        }
        if (
strpos(strtolower(($params['extra']) ?? ''), 'placeholder') === false) {
           
$extra[] = 'placeholder="1962-05-13T14:45"';
        }
        if (
count($extra)) {
           
$params['extra'] ??= '' . implode(' ', $extra);
        }

        return
self::field(array_merge(
            [
               
'type'      => 'datetime-local',
               
'size'      => 16,
               
'maxlength' => 16,
            ],
           
$params
       
));
    }

   
/**
     * HTML5 Date field
     *
     * Returns HTML code for an input date field.
     *
     * @uses forms::field
     *
     * @param array         $params     Email field parameters
     *      $param[
     *          'name' and/or 'id'  => string name and or id (required).
     *          'size'              => int number of visible characters (default = 10).
     *          'maxlength'         => int number of max characters (default = 10).
     *          …                   => see {@link commonAttributes}.
     *      ]
     *
     * @return string
     *
     * @static
     */
   
public static function date(array $params): string
   
{
       
// Cope with unimplemented input type for some browser (type="text" + pattern + placeholder)
       
$extra = [];
        if (
strpos(strtolower(($params['extra']) ?? ''), 'pattern=') === false) {
           
$extra[] = 'pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}"';
        }
        if (
strpos(strtolower(($params['extra']) ?? ''), 'placeholder') === false) {
           
$extra[] = 'placeholder="1962-05-13"';
        }
        if (
count($extra)) {
           
$params['extra'] ??= '' . implode(' ', $extra);
        }

        return
self::field(array_merge(
            [
               
'type'      => 'date',
               
'size'      => 10,
               
'maxlength' => 10,
            ],
           
$params
       
));
    }

   
/**
     * HTML5 Time (local) field
     *
     * Returns HTML code for an input time field.
     *
     * @uses forms::field
     *
     * @param array         $params     Email field parameters
     *      $param[
     *          'name' and/or 'id'  => string name and or id (required).
     *          'size'              => int number of visible characters (default = 5).
     *          'maxlength'         => int number of max characters (default = 5).
     *          …                   => see {@link commonAttributes}.
     *      ]
     *
     * @return string
     *
     * @static
     */
   
public static function time(array $params): string
   
{
       
// Cope with unimplemented input type for some browser (type="text" + pattern + placeholder)
       
$extra = [];
        if (
strpos(strtolower(($params['extra']) ?? ''), 'pattern=') === false) {
           
$extra[] = 'pattern="[0-9]{2}:[0-9]{2}"';
        }
        if (
strpos(strtolower(($params['extra']) ?? ''), 'placeholder') === false) {
           
$extra[] = 'placeholder="14:45"';
        }
        if (
count($extra)) {
           
$params['extra'] ??= '' . implode(' ', $extra);
        }

        return
self::field(array_merge(
            [
               
'type'      => 'time',
               
'size'      => 5,
               
'maxlength' => 5,
            ],
           
$params
       
));
    }

   
/**
     * HTML5 file field
     *
     * Returns HTML code for an input file field.
     *
     * @param array         $params     Email field parameters
     *      $param[
     *          'name' and/or 'id'  => string name and or id (required).
     *          …                   => see {@link commonAttributes}.
     *      ]
     *
     * @return string
     *
     * @static
     */
   
public static function file(array $params): string
   
{
       
// Check for mandatory info
       
if (!self::checkAttributes($params)) {
            return
'';
        }

        return
'<input type="file"' . self::commonAttributes($params) . '/>' . "\n";
    }

   
/**
     * HTML5 number input field
     *
     * Returns HTML code for an number input field.
     *
     * @param array         $params     Number field parameters
     *      $param[
     *          'name' and/or 'id'  => string name and or id (required).
     *          'min'               => int number of text columns.
     *          'max'               => int number of text raws.
     *          …                   => see {@link commonAttributes}.
     *      ]
     *
     * @return string
     *
     * @static
     */
   
public static function number(array $params): string
   
{
       
// Check for mandatory info
       
if (!self::checkAttributes($params)) {
            return
'';
        }

        return
'<input type="number"' . self::commonAttributes($params) .
            (isset(
$params['min']) ? ' min="' . strval((int) $params['min']) . '"' : '') .
            (isset(
$params['max']) ? ' max="' . strval((int) $params['max']) . '"' : '') .
           
'/>' . "\n";
    }

   
/**
     * Textarea
     *
     * Returns HTML code for a textarea.
     *
     * @param array         $params     Textarea parameters
     *      $param[
     *          'name' and/or 'id'  => string name and or id (required).
     *          'cols'              => int number of text columns.
     *          'rows'              => int number of text raws.
     *          …                   => see {@link commonAttributes}.
     *      ]
     *
     * @return string
     *
     * @static
     */
   
public static function textarea(array $params): string
   
{
       
// Check for mandatory info
       
if (!self::checkAttributes($params)) {
            return
'';
        }

        return
'<textarea' . self::commonAttributes($params, false) .
            (isset(
$params['cols']) ? ' cols="' . strval((int) $params['cols']) . '"' : '') .
            (isset(
$params['rows']) ? ' rows="' . strval((int) $params['rows']) . '"' : '') .
           
'>' .
            (
$params['value'] ?? '') .
           
'</textarea>' . "\n";
    }

   
/**
     * Hidden field
     *
     * Returns HTML code for an hidden field.
     *
     * @param array         $params     Hidden field parameters
     *      $param[
     *          'name' and/or 'id'  => string name and or id (required).
     *          …                   => see {@link commonAttributes}.
     *      ]
     *
     * @return string
     *
     * @static
     */
   
public static function hidden(array $params): string
   
{
       
// Check for mandatory info
       
if (!self::checkAttributes($params)) {
            return
'';
        }

        return
'<input type="hidden"' . self::commonAttributes($params) . '/>' . "\n";
    }
}

/**
 * @class formsSelectOption
 * @brief HTML Forms creation helpers
 *
 * @package Clearbricks
 * @subpackage Common
 */
class formsSelectOption
{
    public
$name;       ///< string Option name
   
public $value;      ///< mixed  Option value
   
public $class_name; ///< string Element class name
   
public $extra;      ///< string 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 array   $params       Parameters
     *      $params = [
     *          'name'          => string option name (required).
     *          'value'         => string option value (required).
     *          'class_name'    => string class name.
     *          'extra'         => string extra HTML attributes.
     *      ]
     */
   
public function __construct(array $params)
    {
       
$this->name       = $params['name'];
       
$this->value      = $params['value'];
       
$this->class_name = $params['class'] ?? null;
       
$this->extra      = $params['extra'] ?? null;
    }

   
/**
     * Option renderer
     *
     * Returns option HTML code
     *
     * @param string  $default  Value of selected option
     * @return string
     */
   
public function render(?string $default): string
   
{
       
$attr = $this->class_name ? ' class="' . $this->class_name . '"' : '';
       
$attr .= $this->extra ? ' ' . $this->extra : '';

        if (
$this->value == $default) {
           
$attr .= ' selected';
        }

        return
sprintf($this->option, $this->value, $this->name, $attr);
    }
}