resetManager($options, $schema); } const MANAGER_OPTIONS_SCHEMA = [ "type" => [null, null, "type de formulaire par défaut"], ]; /** @var array */ protected $stack; /** @var array */ protected $options; /** @var array */ protected $schema; function resetManager($options=null, ?array $schema=null): void { $this->stack = []; md::ensure_schema($options, self::MANAGER_OPTIONS_SCHEMA, null, false); $this->options = $options; $this->schema = $schema; $this->inForm = false; $this->inSection = false; $this->inGroup = false; } function push($options=null, ?array $schema=null): void { A::push($this->stack, [$this->options, $this->schema]); md::ensure_schema($options, self::MANAGER_OPTIONS_SCHEMA, null, false); if ($options !== null) $this->options = $options; if ($schema !== null) $this->schema = $schema; } function pop(): void { $last = A::pop($this->stack); if ($last !== null) { [$this->options, $this->schema] = $last; } } protected static function build_attrs(?array $attrs, array $options, ?array $set_keys=null, ?array $merge_keys=null): array { A::update_nx($attrs, $options["attrs"]); if ($set_keys !== null) { foreach ($set_keys as $key) { A::set_nz($attrs, $key, $options[$key]); } } if ($merge_keys !== null) { foreach ($merge_keys as $key) { if ($options[$key]) A::merge($attrs[$key], $options[$key]); A::set_nz($attrs, $key, $options[$key]); } } return $attrs; } /** @var bool */ protected $inForm; /** @var array */ protected $formSuffix; function started(): bool { return $this->inForm; } const FORM_OPTIONS_SCHEMA = [ "type" => [null, null, "type de formulaire"], "action" => [null, null, "action du formulaire"], "method" => [null, null, "méthode du formulaire (post, get)"], "upload" => [null, null, "ce formulaire est-il utilisé pour uploader des fichiers?"], "id" => [null, null, "identifiant du formulaire"], "enctype" => [null, null, "type d'encodage"], "class" => [null, null, "classes CSS du formulaire"], "style" => [null, null, "style CSS du formulaire"], "attrs" => [null, null, "attributs HTML génériques"], "prefix" => [null, null, "contenu à afficher avant"], "suffix" => [null, null, "contenu à afficher après"], ]; function start($options=null, ?array $schema=null): array { $vs = []; if ($this->inForm) $vs[] = $this->end(); $this->push(null, $schema); $this->inForm = true; md::ensure_schema($options, self::FORM_OPTIONS_SCHEMA, null, false); A::replace_z($options, "type", $this->options["type"]); $vs[] = q($options["prefix"]); $this->formSuffix = q($options["suffix"]); $attrs = self::build_attrs(null, $options, [ "action", "method", "id", "enctype", "style", ], ["class"]); if ($options["upload"]) { $attrs["method"] = "post"; $attrs["enctype"] = "multipart/form-data"; } $vs[] = v::start("form", $attrs); return $vs; } function end(): array { if (!$this->inForm) return []; $vs = []; if ($this->inGroup) $vs[] = $this->endGroup(); if ($this->inSection) $vs[] = $this->endSection(); $vs[] = v::end("form"); $vs[] = $this->formSuffix; $this->pop(); $this->inForm = false; $this->formSuffix = null; return $vs; } /** @var bool */ protected $inSection; /** @var array */ protected $sectionSuffix; const SECTION_OPTIONS_SCHEMA = [ "section" => [null, null, "libellé de la section"], "id" => [null, null, "identifiant du champ"], "class" => [null, null, "classes CSS du champ"], "style" => [null, null, "style CSS du champ"], "attrs" => [null, null, "attributs HTML génériques"], "prefix" => [null, null, "contenu à afficher avant"], "suffix" => [null, null, "contenu à afficher après"], ]; function section($options=null): array { if (!$this->inForm) return []; md::ensure_schema($options, self::SECTION_OPTIONS_SCHEMA, null, false); $vs = []; if ($this->inGroup) $vs[] = $this->endGroup(); if ($this->inSection) $vs[] = $this->endSection(); $this->inSection = true; $vs[] = q($options["prefix"]); $this->sectionSuffix = q($options["suffix"]); $attrs = self::build_attrs(null, $options, [ "id", "style", ], ["class"]); $vs[] = v::tag("h2", [$attrs, q($options["section"])]); return $vs; } function endSection(): array { if (!$this->inSection) return []; $vs = [$this->sectionSuffix]; $this->inSection = false; $this->sectionSuffix = null; return $vs; } /** @var bool */ protected $inGroup; /** @var array */ protected $groupSuffix; const GROUP_OPTIONS_SCHEMA = [ "label" => [null, null, "libellé du groupe"], "prefix" => [null, null, "contenu à afficher avant"], "suffix" => [null, null, "contenu à afficher après"], ]; function group($options=null): array { if (!$this->inForm) return []; md::ensure_schema($options, self::GROUP_OPTIONS_SCHEMA, null, false); $vs = []; if ($this->inGroup) $vs[] = $this->endGroup(); $this->inGroup = true; $vs[] = q($options["prefix"]); $this->groupSuffix = q($options["suffix"]); $vs[] = v::start("p", q($options["label"])); return $vs; } function endGroup(): array { if (!$this->inGroup) return []; $vs = ["
", $this->groupSuffix]; $this->inGroup = false; $this->groupSuffix = null; return $vs; } const PREFIX = "\n"; /** @var array contenu à afficher avant chaque élément de formulaire */ protected $prefix = [self::PREFIX]; function setPrefix(?string $prefix=null) { if ($prefix === null) $prefix = static::PREFIX; $this->prefix = q($prefix); } const SUFFIX = null; /** @var array contenu à afficher après chaque élément de formulaire */ protected $suffix = [self::SUFFIX]; function setSuffix(?string $suffix=null) { if ($suffix === null) $suffix = static::SUFFIX; $this->suffix = q($suffix); } const FIXED_OPTIONS_SCHEMA = [ "label" => [null, null, "libellé"], "id" => [null, null, "identifiant"], "value" => [null, null, "valeur"], "class" => [null, null, "classes CSS du champ"], "style" => [null, null, "style CSS du champ"], "attrs" => [null, null, "attributs HTML génériques"], "prefix" => [null, null, "contenu à afficher avant"], "suffix" => [null, null, "contenu à afficher après"], ]; function fixed($label, string $name, $value, ?array $options=null): array { md::ensure_schema($options, self::FIXED_OPTIONS_SCHEMA, null, false); A::set_nz($options, "label", $label); A::set_nz($options, "name", $name); A::set_nz($options, "value", $value); A::replace_n_indirect($options, "id", "name"); $label = $options["label"]; $vs = [$this->prefix, q($options["prefix"])]; if ($label) $vs[] = v::start("label", q($label)); $attrs = self::build_attrs(null, $options, [ "id", "style", ], ["class"]); $vs[] = v::tag("span", [$attrs, q($options["value"])]); if ($label) $vs[] = v::end("label"); $vs[] = q($options["suffix"]); $vs[] = $this->suffix; return $vs; } const HIDDEN_OPTIONS_SCHEMA = [ "id" => [null, null, "identifiant du champ"], "name" => [null, null, "nom du champ"], "value" => [null, null, "valeur du champ"], "attrs" => [null, null, "attributs HTML génériques"], ]; function hidden(string $name, $value, ?array $options=null): array { md::ensure_schema($options, self::HIDDEN_OPTIONS_SCHEMA, null, false); A::set_nz($options, "name", $name); A::set_nz($options, "value", $value); $attrs = self::build_attrs(["type" => "hidden"], $options, [ "id", "name", "value", ]); return v::tag1("input", $attrs); } function hiddens(array $values, string ...$names): array { if (!$names) $names = array_keys($values); $vs = []; foreach ($names as $name) { $value = A::get($values, $name); $vs[] = $this->hidden($name, $value); } return $vs; } const INPUT_OPTIONS_SCHEMA = [ "label" => [null, null, "libellé du champ"], "id" => [null, null, "identifiant du champ"], "name" => [null, null, "nom du champ"], "value" => [null, null, "valeur par défaut du champ"], "placeholder" => [null, null, "valeur suggérée"], "required" => [null, null, "ce champ est-il requis?"], "accesskey" => [null, null, "touche d'accès rapide"], "tabindex" => [null, null, "index de tabulation"], "class" => [null, null, "classes CSS du champ"], "style" => [null, null, "style CSS du champ"], "attrs" => [null, null, "attributs HTML génériques"], "prefix" => [null, null, "contenu à afficher avant"], "suffix" => [null, null, "contenu à afficher après"], ]; protected function _input(string $type, $label, string $name, $value, ?array $options=null): array { md::ensure_schema($options, self::INPUT_OPTIONS_SCHEMA, null, false); A::set_nz($options, "label", $label); A::set_nz($options, "name", $name); A::set_nz($options, "value", $value); A::replace_n_indirect($options, "id", "name"); $label = $options["label"]; $vs = [$this->prefix, q($options["prefix"])]; if ($label) $vs[] = v::start("label", q($label)); $attrs = self::build_attrs(["type" => $type], $options, [ "id", "name", "value", "placeholder", "accesskey", "tabindex", "style", ], ["class"]); if ($options["required"]) $attrs["required"] = "required"; $vs[] = v::tag1("input", $attrs); if ($label) $vs[] = v::end("label"); $vs[] = q($options["suffix"]); $vs[] = $this->suffix; return $vs; } function text($label, string $name, $value, ?array $options=null): array { return $this->_input("text", $label, $name, $value, $options); } function texts($label, array $values, string ...$names): array { if (!$names) $names = array_keys($values); $vs = []; if ($label) $vs[] = q($label); foreach ($names as $name) { $value = A::get($values, $name); $vs[] = $this->text(null, $name, $value); } return $vs; } function password($label, string $name, $value, ?array $options=null): array { return $this->_input("password", $label, $name, $value, $options); } const SELECT_OPTIONS_SCHEMA = [ "label" => [null, null, "libellé du champ"], "id" => [null, null, "identifiant du champ"], "name" => [null, null, "nom du champ"], "value" => [null, null, "valeur par défaut du champ"], "required" => [null, null, "ce champ est-il requis?"], "accesskey" => [null, null, "touche d'accès rapide"], "tabindex" => [null, null, "index de tabulation"], "items" => [null, null, "liste d'éléments à afficher"], "items_func" => [null, null, "fonction fournissant une liste d'éléments à afficher"], "item_value_key" => [null, null, "clé de la valeur d'un élément"], "item_value_func" => [null, null, "fonction fournissant la clé de la valeur d'un élément"], "item_text_key" => [null, null, "clé du libellé d'un élément"], "item_text_func" => [null, null, "fonction fournissant la clé du libellé d'un élément"], "no_item_value" => [null, null, "valeur si aucun élément n'est sélectionné"], "no_item_text" => [null, null, "libellé si aucun élément n'est sélectionné"], "class" => [null, null, "classes CSS du champ"], "style" => [null, null, "style CSS du champ"], "attrs" => [null, null, "attributs HTML génériques"], "prefix" => [null, null, "contenu à afficher avant"], "suffix" => [null, null, "contenu à afficher après"], "option_prefix" => [null, null, "contenu à afficher avant chaque option"], "option_suffix" => [null, null, "contenu à afficher après chaque option"], ]; private function vof( array $options, ?string $value_key=null, $value_func=null, $item=null, ?string $item_key=null, ?int $item_index = null, ...$item_func_args) { if ($value_key !== null) { $value = A::get($options, $value_key); if ($value !== null) return $value; } if ($value_func !== null) { $func = A::get($options, $value_func); if ($func !== null) { func::ensure_func($func, $this, $item_func_args); $value = func::call($func, ...$item_func_args); if ($value !== null) return $value; } } if (A::is_array($item)) { $array_item = A::with($item); if ($item_key !== null) { $value_key = A::get($options, $item_key); if ($value_key !== null) { $value = A::get($array_item, $value_key); if ($value !== null) return $value; } } if ($item_index !== null) { $index = 0; foreach ($array_item as $value) { if ($index === $item_index) { return $value; } $index++; } } } return $item; } function select($label, string $name, $value, ?array $options=null): array { md::ensure_schema($options, self::SELECT_OPTIONS_SCHEMA, null, false); A::set_nz($options, "label", $label); A::set_nz($options, "name", $name); A::set_nz($options, "value", $value); A::replace_n_indirect($options, "id", "name"); $value = $options["value"]; $items = $this->vof($options, "items", "items_func"); $no_item_value = $options["no_item_value"]; $no_item_text = $options["no_item_text"]; $oos = array(); if ($no_item_value !== null) { $oos[] = array( "value" => $no_item_value, "text" => $no_item_text, "selected" => $value == $no_item_value, ); } foreach ($items as $key => $item) { $item_value = $this->vof($options, null, "item_value_func", $item, "item_value_key", 0, $item, $key); $item_text = $this->vof($options, null, "item_text_func", $item, "item_text_key", 1, $item, $key); if (!$item_text) $item_text = $item_value; $oos[] = array( "value" => $item_value, "text" => $item_text, "selected" => $value == $item_value, ); } $label = $options["label"]; $vs = [$this->prefix, q($options["prefix"])]; if ($label) $vs[] = v::start("label", q($label)); $attrs = self::build_attrs(null, $options, [ "id", "name", "value", "accesskey", "tabindex", "style", ], ["class"]); if ($options["required"]) $attrs["required"] = "required"; $vs[] = v::start("select", $attrs); foreach ($oos as $oo) { $vs[] = q($options["option_prefix"]); $vs[] = v::tag("option", [ "value" => $oo["value"], "selected" => $oo["selected"]? "selected": false, q($oo["text"]), ]); $vs[] = q($options["option_suffix"]); } $vs[] = v::end("select"); if ($label) $vs[] = v::end("label"); $vs[] = q($options["suffix"]); $vs[] = $this->suffix; return $vs; } const CHECKBOX_OPTIONS_SCHEMA = [ "text" => [null, null, "libellé de la case à cocher"], "id" => [null, null, "identifiant de la case à cocher"], "name" => [null, null, "nom du champ"], "value" => [null, null, "valeur du champ"], "checked" => [null, null, "la case est-elle cochée?"], "accesskey" => [null, null, "touche d'accès rapide"], "tabindex" => [null, null, "index de tabulation"], "class" => [null, null, "classes CSS du champ"], "style" => [null, null, "style CSS du champ"], "attrs" => [null, null, "attributs HTML génériques"], "prefix" => [null, null, "contenu à afficher avant"], "suffix" => [null, null, "contenu à afficher après"], ]; function checkbox($text, string $name, $value, ?bool $checked=null, ?array $options=null): array { md::ensure_schema($options, self::CHECKBOX_OPTIONS_SCHEMA, null, false); A::set_nz($options, "text", $text); A::set_nz($options, "name", $name); A::set_nz($options, "value", $value); A::set_nz($options, "checked", $checked); A::replace_n_indirect($options, "id", "name"); $text = $options["text"]; if (is_string($text)) $text = " $text"; $vs = [q($options["prefix"])]; if ($text) $vs[] = v::start("label"); $attrs = self::build_attrs(["type" => "checkbox"], $options, [ "id", "name", "value", "accesskey", "tabindex", "style", ], ["class"]); if ($options["checked"]) $attrs["checked"] = "checked"; $vs[] = v::tag1("input", $attrs); if ($text) { $vs[] = q($text); $vs[] = v::end("label"); } $vs[] = q($options["suffix"]); return $vs; } const CHECKBOXES_OPTIONS_SCHEMA = [ "label" => [null, null, "libellé du champ"], "id" => [null, null, "identifiant du champ"], "name" => [null, null, "nom du champ"], "values" => [null, null, "valeurs cochées par défaut"], "accesskey" => [null, null, "touche d'accès rapide"], "tabindex" => [null, null, "index de tabulation"], "items" => [null, null, "liste d'éléments à afficher"], "items_func" => [null, null, "fonction fournissant une liste d'éléments à afficher"], "item_value_key" => [null, null, "clé de la valeur d'un élément"], "item_value_func" => [null, null, "fonction fournissant la clé de la valeur d'un élément"], "item_text_key" => [null, null, "clé du libellé d'un élément"], "item_text_func" => [null, null, "fonction fournissant la clé du libellé d'un élément"], "class" => [null, null, "classes CSS du champ"], "style" => [null, null, "style CSS du champ"], "attrs" => [null, null, "attributs HTML génériques"], "prefix" => [null, null, "contenu à afficher avant"], "suffix" => [null, null, "contenu à afficher après"], "checkbox_prefix" => [null, null, "contenu à afficher avant chaque case à cocher"], "checkbox_suffix" => [null, null, "contenu à afficher après chaque case à cocher"], ]; function checkboxes($label, string $name, $values, ?array $options=null): array { md::ensure_schema($options, self::CHECKBOXES_OPTIONS_SCHEMA, null, false); A::set_nz($options, "label", $label); A::set_nz($options, "name", $name); A::set_nz($options, "values", $values); $name = $options["name"]; $values = A::with($options["values"]); $items = $this->vof($options, "items", "items_func"); $oos = array(); foreach ($items as $key => $item) { $item_value = $this->vof($options, null, "item_value_func", $item, "item_value_key", 0, $item, $key); $item_text = $this->vof($options, null, "item_text_func", $item, "item_text_key", 1, $item, $key); if (!$item_text) $item_text = $item_value; $oos[] = array( "name" => "${name}[$key]", "value" => $item_value, "text" => $item_text, "checked" => in_array($item_value, $values), ); } $label = $options["label"]; $vs = [$this->prefix, q($options["prefix"])]; if ($label) $vs[] = v::start("label", q($label)); $attrs = self::build_attrs(null, $options, [ "id", "accesskey", "tabindex", "style", ], ["class"]); $first = true; foreach ($oos as $oo) { $vs[] = q($options["checkbox_prefix"]); $vs[] = $this->checkbox($oo["text"], $oo["name"], $oo["value"], $oo["checked"], ["attrs" => $attrs]); $vs[] = q($options["checkbox_suffix"]); if ($first && $label) $vs[] = v::end("label"); $attrs["id"] = false; # id uniquement sur le premier unset($attrs["accesskey"]); # accesskey uniquement sur le premier unset($attrs["tabindex"]); # accesskey uniquement sur le premier $first = false; } if ($first && $label) $vs[] = v::end("label"); $vs[] = q($options["suffix"]); $vs[] = $this->suffix; return $vs; } const RADIOBUTTON_OPTIONS_SCHEMA = [ "text" => [null, null, "libellé du bouton radio"], "id" => [null, null, "identifiant du bouton radio"], "name" => [null, null, "nom du champ"], "value" => [null, null, "valeur du champ"], "checked" => [null, null, "le bouton est-il sélectionné?"], "accesskey" => [null, null, "touche d'accès rapide"], "tabindex" => [null, null, "index de tabulation"], "class" => [null, null, "classes CSS du champ"], "style" => [null, null, "style CSS du champ"], "attrs" => [null, null, "attributs HTML génériques"], "prefix" => [null, null, "contenu à afficher avant"], "suffix" => [null, null, "contenu à afficher après"], ]; function radiobutton($text, string $name, $value, ?bool $checked=null, ?array $options=null): array { md::ensure_schema($options, self::RADIOBUTTON_OPTIONS_SCHEMA, null, false); A::set_nz($options, "text", $text); A::set_nz($options, "name", $name); A::set_nz($options, "value", $value); A::set_nz($options, "checked", $checked); A::replace_n_indirect($options, "id", "name"); $text = $options["text"]; if (is_string($text)) $text = " $text"; $vs = [q($options["prefix"])]; if ($text) $vs[] = v::start("label"); $attrs = self::build_attrs(["type" => "radio"], $options, [ "id", "name", "value", "accesskey", "tabindex", "style", ], ["class"]); if ($options["checked"]) $attrs["checked"] = "checked"; $vs[] = v::tag1("input", $attrs); if ($text) { $vs[] = q($text); $vs[] = v::end("label"); } $vs[] = q($options["suffix"]); return $vs; } const RADIOBUTTONS_OPTIONS_SCHEMA = [ "label" => [null, null, "libellé du champ"], "id" => [null, null, "identifiant du champ"], "name" => [null, null, "nom du champ"], "value" => [null, null, "valeur cochée par défaut"], "accesskey" => [null, null, "touche d'accès rapide"], "tabindex" => [null, null, "index de tabulation"], "items" => [null, null, "liste d'éléments à afficher"], "items_func" => [null, null, "fonction fournissant une liste d'éléments à afficher"], "item_value_key" => [null, null, "clé de la valeur d'un élément"], "item_value_func" => [null, null, "fonction fournissant la clé de la valeur d'un élément"], "item_text_key" => [null, null, "clé du libellé d'un élément"], "item_text_func" => [null, null, "fonction fournissant la clé du libellé d'un élément"], "class" => [null, null, "classes CSS du champ"], "style" => [null, null, "style CSS du champ"], "attrs" => [null, null, "attributs HTML génériques"], "prefix" => [null, null, "contenu à afficher avant"], "suffix" => [null, null, "contenu à afficher après"], "radiobutton_prefix" => [null, null, "contenu à afficher avant chaque bouton radio"], "radiobutton_suffix" => [null, null, "contenu à afficher après chaque bouton radio"], ]; function radiobuttons($label, string $name, $value, ?array $options): array { md::ensure_schema($options, self::RADIOBUTTONS_OPTIONS_SCHEMA, null, false); A::set_nz($options, "label", $label); A::set_nz($options, "name", $name); A::set_nz($options, "value", $value); A::replace_n_indirect($options, "id", "name"); $id = $options["id"]; $name = $options["name"]; $value = $options["value"]; $items = $this->vof($options, "items", "items_func"); $oos = array(); $i = 0; foreach ($items as $key => $item) { $item_value = $this->vof($options, null, "item_value_func", $item, "item_value_key", 0, $item, $key); $item_text = $this->vof($options, null, "item_text_func", $item, "item_text_key", 1, $item, $key); if (!$item_text) $item_text = $item_value; $oos[] = array( "id" => "$id$i", "name" => "$name", "value" => $item_value, "text" => $item_text, "checked" => $value === $item_value, ); $i++; } $label = $options["label"]; $vs = [$this->prefix, q($options["prefix"])]; if ($label) $vs[] = v::start("label", q($label)); $attrs = self::build_attrs(null, $options, [ "accesskey", "tabindex", "style", ], ["class"]); $first = true; foreach ($oos as $oo) { $vs[] = q($options["radiobutton_prefix"]); $vs[] = $this->radiobutton($oo["text"], $oo["name"], $oo["value"], $oo["checked"], ["id" => $oo["id"], "attrs" => $attrs]); $vs[] = q($options["radiobutton_suffix"]); if ($first && $label) $vs[] = v::end("label"); unset($attrs["accesskey"]); # accesskey uniquement sur le premier unset($attrs["tabindex"]); # accesskey uniquement sur le premier $first = false; } if ($first && $label) $vs[] = v::end("label"); $vs[] = q($options["suffix"]); $vs[] = $this->suffix; return $vs; } const TEXTAREA_OPTIONS_SCHEMA = [ "label" => [null, null, "libellé du champ"], "id" => [null, null, "identifiant du champ"], "name" => [null, null, "nom du champ"], "value" => [null, null, "valeur par défaut du champ"], "placeholder" => [null, null, "valeur suggérée"], "required" => [null, null, "ce champ est-il requis?"], "accesskey" => [null, null, "touche d'accès rapide"], "tabindex" => [null, null, "index de tabulation"], "class" => [null, null, "classes CSS du champ"], "style" => [null, null, "style CSS du champ"], "attrs" => [null, null, "attributs HTML génériques"], "prefix" => [null, null, "contenu à afficher avant"], "suffix" => [null, null, "contenu à afficher après"], ]; function textarea($label, string $name, $value, ?array $options=null): array { md::ensure_schema($options, self::TEXTAREA_OPTIONS_SCHEMA, null, false); A::set_nz($options, "label", $label); A::set_nz($options, "name", $name); A::set_nz($options, "value", $value); A::replace_n_indirect($options, "id", "name"); $label = $options["label"]; $vs = [$this->prefix, q($options["prefix"])]; if ($label) $vs[] = v::start("label", q($label)); $attrs = self::build_attrs(null, $options, [ "id", "name", "placeholder", "accesskey", "tabindex", "style", ], ["class"]); if ($options["required"]) $attrs["required"] = "required"; $vs[] = v::tag("textarea", [$attrs, q($options["value"])]); if ($label) $vs[] = v::end("label"); $vs[] = q($options["suffix"]); $vs[] = $this->suffix; return $vs; } const FILE_OPTIONS_SCHEMA = [ "label" => [null, null, "libellé du champ"], "id" => [null, null, "identifiant du champ"], "name" => [null, null, "nom du champ"], "accept" => [null, ".pdf,image/*", "types MIME acceptés"], "required" => [null, null, "ce champ est-il requis?"], "accesskey" => [null, null, "touche d'accès rapide"], "tabindex" => [null, null, "index de tabulation"], "class" => [null, null, "classes CSS du champ"], "style" => [null, null, "style CSS du champ"], "attrs" => [null, null, "attributs HTML génériques"], "prefix" => [null, null, "contenu à afficher avant"], "suffix" => [null, null, "contenu à afficher après"], ]; function file($label, string $name, ?array $options=null): array { md::ensure_schema($options, self::FILE_OPTIONS_SCHEMA, null, false); A::set_nz($options, "label", $label); A::set_nz($options, "name", $name); A::replace_n_indirect($options, "id", "name"); $label = $options["label"]; $vs = [$this->prefix, q($options["prefix"])]; if ($label) $vs[] = v::start("label", q($label)); $attrs = self::build_attrs(["type" => "file"], $options, [ "id", "name", "accept", "accesskey", "tabindex", "style", ], ["class"]); if ($options["required"]) $attrs["required"] = "required"; $vs[] = v::tag1("input", $attrs); if ($label) $vs[] = v::end("label"); $vs[] = q($options["suffix"]); $vs[] = $this->suffix; return $vs; } const SUBMIT_OPTIONS_SCHEMA = [ "submit" => [null, null, "libellé du bouton de soumission"], "id" => [null, null, "identifiant du bouton"], "name" => [null, null, "nom du champ"], "value" => [null, null, "valeur du champ"], "formmethod" => [null, null, "méthode de soumission (post, get)"], "formaction" => [null, null, "action pour la soumission"], "formenctype" => [null, null, "type d'encodage pour la soumission"], "accesskey" => [null, null, "touche d'accès rapide"], "tabindex" => [null, null, "index de tabulation"], "type" => [null, null, "type de bouton (submit, reset)"], "class" => [null, null, "classes CSS du bouton"], "style" => [null, null, "style CSS du bouton"], "attrs" => [null, null, "attributs HTML génériques"], "prefix" => [null, null, "contenu à afficher avant"], "suffix" => [null, null, "contenu à afficher après"], ]; function submit($options=null): array { md::ensure_schema($options, self::SUBMIT_OPTIONS_SCHEMA, null, false); A::replace_z($options, "type", "submit"); $vs = [$this->prefix, q($options["prefix"])]; $attrs = self::build_attrs(null, $options, [ "type", "id", "name", "value", "formaction", "formmethod", "formenctype", "accesskey", "tabindex", "style", ], ["class"]); $vs[] = v::tag("button", [$attrs, q($options["submit"])]); $vs[] = q($options["suffix"]); $vs[] = $this->suffix; return $vs; } const RESET_OPTIONS_SCHEMA = [ "reset" => [null, null, "libellé du bouton de soumission"], "id" => [null, null, "identifiant du bouton"], "name" => [null, null, "nom du champ"], "value" => [null, null, "valeur du champ"], "accesskey" => [null, null, "touche d'accès rapide"], "tabindex" => [null, null, "index de tabulation"], "type" => [null, null, "type de bouton (submit, reset)"], "class" => [null, null, "classes CSS du bouton"], "style" => [null, null, "style CSS du bouton"], "attrs" => [null, null, "attributs HTML génériques"], "prefix" => [null, null, "contenu à afficher avant"], "suffix" => [null, null, "contenu à afficher après"], ]; function reset($options=null): array { md::ensure_schema($options, self::RESET_OPTIONS_SCHEMA, null, false); A::replace_z($options, "type", "reset"); $vs = [$this->prefix, q($options["prefix"])]; $attrs = self::build_attrs(null, $options, [ "type", "id", "name", "value", "accesskey", "tabindex", "style", ], ["class"]); $vs[] = v::tag("button", [$attrs, q($options["reset"])]); $vs[] = q($options["suffix"]); $vs[] = $this->suffix; return $vs; } }