yf_html5fw_bs5 classTwitter bootstrap v5 html5 abstraction driver.
| File | plugins/html/classes/html5fw/yf_html5fw_bs5.class.php |
|---|---|
| Use | _class('html5fw_bs5', 'classes/html5fw/') |
| Extends | yf_html5fw_bs3 → yf_html5fw_empty |
A site sets them in its config with $PROJECT_CONF['html5fw_bs5']['NAME'] = ...;
| Property | Default | Description |
|---|---|---|
$CLASS_ADDON |
'input-group-text' |
|
$CLASS_CONTROLS |
'col-md-9' |
|
$CLASS_CONTROLS_BUTTONS |
'col-md-9' |
|
$CLASS_CONTROL_INVALIDstring |
'is-invalid' |
validation state classes Bootstrap 5 styles on the control itself |
$CLASS_CONTROL_VALID |
'is-valid' |
|
$CLASS_DESC |
'' |
|
$CLASS_EDIT_ICON |
'bi bi-pencil' |
|
$CLASS_EDIT_LINK |
'btn btn-outline-secondary btn-sm' |
|
$CLASS_ERROR |
'has-error is-invalid' |
|
$CLASS_FEEDBACK |
'invalid-feedback' |
|
$CLASS_FLOATINGstring |
'form-floating' |
wrapper of a field with the `floating` option: the control, then its label |
$CLASS_FORM_GROUP |
'mb-3 row' |
|
$CLASS_HELP |
'form-text' |
|
$CLASS_HELP_INVALIDstring |
'invalid-feedback d-block' |
help text of a field with an error (d-block: an input group sits between the control and the message) |
$CLASS_INFO |
'has-info' |
|
$CLASS_INPUT_APPEND |
'' |
|
$CLASS_INPUT_GROUP |
'input-group' |
|
$CLASS_INPUT_GROUP_BTNstring |
'' |
Bootstrap 5 puts input group buttons in the group as they are |
$CLASS_INPUT_PREPEND |
'' |
|
$CLASS_LABEL |
'col-form-label col-md-3' |
|
$CLASS_LINK_URL |
'btn btn-outline-secondary' |
|
$CLASS_NO_LABEL |
' offset-md-3' |
|
$CLASS_NO_LABEL_BUTTONS |
' offset-md-3' |
|
$CLASS_STACKED_CONTROLSstring |
'd-flex flex-wrap align-items-start gap-2' |
controls of a form2 row_start() row: its stacked items sit side by side, as the bs3 CSS floats them |
$CLASS_STACKED_ITEM |
'stacked-item' |
|
$CLASS_SUCCESS |
'has-success is-valid' |
|
$CLASS_WARNING |
'has-warning' |
from yf_html5fw_bs3: $CLASS_INPUT_GROUP_SIZE
public function form_dd_row($content, $extra = [], $replace = [], $form = [])
Form row using dl row, dt col-sm-3, dd col-sm-9.
public function form_dd_row($content, $extra = [], $replace = [], $form = [])
{
$class_wrapper = ($extra['class_wrapper'] ?? null) ?: 'row';
if ($extra['class_add_wrapper'] ?? null) {
$class_wrapper .= ' ' . $extra['class_add_wrapper'];
}
$class_dd = ($extra['class_dd'] ?? null) ?: 'col-sm-9';
if ($extra['class_add_dd'] ?? null) {
$class_dd .= ' ' . $extra['class_add_dd'];
}
$row_start = ! ($extra['wide'] ?? null) ? '<dl class="' . $class_wrapper . '">' . PHP_EOL . '<dt class="col-sm-3">' . t($extra['desc'] ?? '') . '</dt>' . PHP_EOL : '';
$before_content_html = '<dd class="' . $class_dd . '">';
$after_content_html = '</dd>';
$row_end = '</dl>' . PHP_EOL;
if ($extra['edit_link'] ?? null) {
if (MAIN_TYPE_ADMIN && main()->ADMIN_GROUP != 1 && ! _class('admin_methods')->_admin_link_is_allowed($extra['edit_link'])) {
$extra['edit_link'] = '';
}
}
$edit_link_html = ($extra['edit_link'] ?? null) ? ' <a href="' . _escape_tpl_braces(_htmlchars($extra['edit_link'])) . '" class="' . $this->CLASS_EDIT_LINK . '"><i class="' . $this->CLASS_EDIT_ICON . '"></i> ' . t('Edit') . '</a>' . PHP_EOL : '';
$link_name_html = (($extra['link_url'] ?? null) && ($extra['link_name'] ?? null)) ? ' <a href="' . $extra['link_url'] . '" class="' . $this->CLASS_LINK_URL . '">' . t($extra['link_name']) . '</a>' . PHP_EOL : '';
$inline_tip_html = ($extra['tip'] ?? null) ? ' ' . tip($extra['tip'], $replace) : '';
if ($extra['only_row_start'] ?? null) {
return $row_start . $before_content_html;
} elseif ($extra['only_row_end'] ?? null) {
return $after_content_html . $row_end;
} elseif ($extra['stacked'] ?? null) {
return $content . PHP_EOL . $edit_link_html . $link_name_html . $inline_tip_html;
}
return $row_start
. $before_content_html . $content . PHP_EOL
. $edit_link_html . $link_name_html . $inline_tip_html . $after_content_html
. $this->_add_rich_editor($extra, $replace, $form)
. $row_end;
}
public function form_row($content, $extra = [], $replace = [], $form = [])
Bootstrap 5 row: the bs3 row markup with the validation state on the control (`is-invalid` / `is-valid` on the element named like the field) and the error text as `invalid-feedback`; the row wrapper keeps its state classes.
public function form_row($content, $extra = [], $replace = [], $form = [])
{
$stacked_row = is_object($form) && isset($form->CLASS_STACKED_ROW) ? (string) $form->CLASS_STACKED_ROW : 'stacked-row';
if (($extra['only_row_start'] ?? null) && $stacked_row !== '' && in_array($stacked_row, explode(' ', (string) ($extra['class_add_form_group'] ?? '')), true)) {
$extra['class_add_controls'] = trim(($extra['class_add_controls'] ?? '') . ' ' . $this->CLASS_STACKED_CONTROLS);
}
if ($extra['floating'] ?? null) {
[$content, $extra] = $this->_floating($content, $extra, $replace, $form);
}
$name = (string) ($extra['name'] ?? '');
$state = $name !== '' ? $this->_field_state($extra, $name) : '';
if ($state === '') {
return parent::form_row($content, $extra, $replace, $form);
}
$content = $this->_add_control_class($content, $name, $state === 'errors' ? $this->CLASS_CONTROL_INVALID : $this->CLASS_CONTROL_VALID);
if ($state !== 'errors') {
return parent::form_row($content, $extra, $replace, $form);
}
$help = $this->CLASS_HELP;
$this->CLASS_HELP = $this->CLASS_HELP_INVALID;
try {
return parent::form_row($content, $extra, $replace, $form);
} finally {
$this->CLASS_HELP = $help;
}
}
_ hooks and helpers; not routable as page actionspublic function _add_control_class($html, $name, $class)
Add a class to the input / select / textarea elements named $name inside $html.
$html string$name string$class string public function _add_control_class($html, $name, $class)
{
// a tag with quoted attribute values that may contain '>'
$tag_re = '~<(input|select|textarea)\b((?:[^>"\']|"[^"]*"|\'[^\']*\')*)>~i';
$attr_re = '~\s([a-z_:][-a-z0-9_:.]*)(?:\s*=\s*(?:"([^"]*)"|\'([^\']*)\'|([^\s>"\']+)))?~i';
return preg_replace_callback($tag_re, function ($m) use ($name, $class, $attr_re) {
preg_match_all($attr_re, $m[2], $attrs, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
$found = [];
foreach ($attrs as $a) {
$key = strtolower($a[1][0]);
if ( ! isset($found[$key])) {
$value = ($a[2][0] ?? '') !== '' ? $a[2][0] : (($a[3][0] ?? '') !== '' ? $a[3][0] : ($a[4][0] ?? ''));
$found[$key] = ['text' => $a[0][0], 'value' => html_entity_decode($value, ENT_QUOTES)];
}
}
if (($found['name']['value'] ?? null) !== $name || in_array(strtolower($found['type']['value'] ?? ''), ['hidden', 'submit', 'button', 'reset'], true)) {
return $m[0];
}
if (isset($found['class'])) {
$classes = trim($found['class']['value'] . ' ' . $class);
$attrs_out = str_replace($found['class']['text'], ' class="' . htmlspecialchars($classes, ENT_QUOTES) . '"', $m[2]);
} else {
$attrs_out = ' class="' . $class . '"' . $m[2];
}
return '<' . $m[1] . $attrs_out . '>';
}, (string) $html) ?? $html;
}
public function _field_state($extra, $name)
'errors', 'success' or '' for a field, the same lookup the bs3 row does for its wrapper class.
$name string public function _field_state($extra, $name)
{
$dotted = false !== strpos($name, '[') ? str_replace(['[', ']'], ['.', ''], trim($name, '][')) : null;
foreach (['errors', 'success'] as $key) {
if (isset($extra[$key][$name]) || ($dotted !== null && isset($extra[$key][$dotted]))) {
return $key;
}
}
return '';
}
public function _floating($content, $extra, $replace = [], $form = null)
Floating label (`floating` option): the control and then its label inside div.form-floating, and no label column (the controls take the no-label offset, so they line up with the other rows). Without a label to float the row stays as it is.
$content string$extra array public function _floating($content, $extra, $replace = [], $form = null)
{
$no_label = $extra['no_label'] ?? (is_object($form) ? ($form->_params['no_label'] ?? false) : false);
if ($no_label || ! strlen((string) ($extra['desc'] ?? '')) || ($extra['only_row_start'] ?? null) || ($extra['only_row_end'] ?? null)) {
return [$content, $extra];
}
$label_tip_html = ($extra['label_tip'] ?? null) ? trim(' ' . tip($extra['label_tip'], $replace)) : '';
// the rendered control's id: a select_box() id is select_box_N, not the field name in $extra['id']
$for_html = preg_match('~<(?:input|select|textarea)\b[^>]*?\sid="([^"]+)"~', $content, $m) ? ' for="' . $m[1] . '"' : _attrs(['for' => $extra['id'] ?? null], ['for']);
$content = '<div class="' . $this->CLASS_FLOATING . '">' . $content . PHP_EOL
. '<label' . $for_html . '>' . t($extra['desc']) . $label_tip_html . '</label>' . PHP_EOL
. '</div>';
$extra['no_label'] = 1;
return [$content, $extra];
}
from yf_html5fw_empty: _add_rich_editor(), form_render_out()