%PDF- %PDF-
Direktori : /www/varak.net/wiki.varak.net/vendor/oojs/oojs-ui/php/layouts/ |
Current File : //www/varak.net/wiki.varak.net/vendor/oojs/oojs-ui/php/layouts/FieldLayout.php |
<?php namespace OOUI; /** * Layout made of a field and optional label. * * Available label alignment modes include: * - left: Label is before the field and aligned away from it, best for when the user will be * scanning for a specific label in a form with many fields * - right: Label is before the field and aligned toward it, best for forms the user is very * familiar with and will tab through field checking quickly to verify which field they are in * - top: Label is before the field and above it, best for when the user will need to fill out all * fields from top to bottom in a form with few fields * - inline: Label is after the field and aligned toward it, best for small boolean fields like * checkboxes or radio buttons */ class FieldLayout extends Layout { use LabelElement; use TitledElement; /** * Alignment. * * @var string */ protected $align; /** * Field widget to be laid out. * * @var Widget */ protected $fieldWidget; /** * Error messages. * * @var array */ protected $errors; /** * Notice messages. * * @var array */ protected $notices; /** * @var ButtonWidget|string */ protected $help; protected $field, $header, $body, $messages; /** * @param Widget $fieldWidget Field widget * @param array $config Configuration options * @param string $config['align'] Alignment mode, either 'left', 'right', 'top' or 'inline' * (default: 'left') * @param array $config['errors'] Error messages about the widget, as strings or HtmlSnippet * instances. * @param array $config['notices'] Notices about the widget, as strings or HtmlSnippet instances. * @param string|HtmlSnippet $config['help'] Explanatory text shown as a '?' icon. * @param bool $config['helpInline'] Whether or not the help should be inline, * or shown when the "help" icon is clicked. (default: false) * @param-taint $config escapes_htmlnoent * @throws Exception An exception is thrown if no widget is specified */ public function __construct( $fieldWidget, array $config = [] ) { // Allow passing positional parameters inside the config array if ( is_array( $fieldWidget ) && isset( $fieldWidget['fieldWidget'] ) ) { $config = $fieldWidget; $fieldWidget = $config['fieldWidget']; } // Make sure we have required constructor arguments if ( $fieldWidget === null ) { throw new Exception( 'Widget not found' ); } // Config initialization $config = array_merge( [ 'align' => 'left', 'helpInline' => false ], $config ); // Parent constructor parent::__construct( $config ); // Properties $this->fieldWidget = $fieldWidget; $this->errors = $config['errors'] ?? []; $this->notices = $config['notices'] ?? []; $this->field = $this->isFieldInline() ? new Tag( 'span' ) : new Tag( 'div' ); $this->messages = new Tag( 'ul' ); $this->header = new Tag( 'span' ); $this->body = new Tag( 'div' ); $this->helpText = $config['help'] ?? ''; $this->helpInline = $config['helpInline']; // Traits $this->initializeLabelElement( array_merge( $config, [ 'labelElement' => new Tag( 'label' ) ] ) ); $this->initializeTitledElement( array_merge( $config, [ 'titled' => $this->label ] ) ); // Initialization $this->help = empty( $this->helpText ) ? '' : $this->createHelpElement(); if ( $this->fieldWidget->getInputId() ) { $this->label->setAttributes( [ 'for' => $this->fieldWidget->getInputId() ] ); if ( !empty( $this->helpText ) && $this->helpInline ) { $this->help->setAttributes( [ 'for' => $this->fieldWidget->getInputId() ] ); } } $this ->addClasses( [ 'oo-ui-fieldLayout' ] ) ->toggleClasses( [ 'oo-ui-fieldLayout-disabled' ], $this->fieldWidget->isDisabled() ) ->appendContent( $this->body ); if ( count( $this->errors ) || count( $this->notices ) ) { $this->appendContent( $this->messages ); } $this->body->addClasses( [ 'oo-ui-fieldLayout-body' ] ); $this->header->addClasses( [ 'oo-ui-fieldLayout-header' ] ); $this->messages->addClasses( [ 'oo-ui-fieldLayout-messages' ] ); $this->field ->addClasses( [ 'oo-ui-fieldLayout-field' ] ) ->appendContent( $this->fieldWidget ); foreach ( $this->notices as $text ) { $this->messages->appendContent( $this->makeMessage( 'notice', $text ) ); } foreach ( $this->errors as $text ) { $this->messages->appendContent( $this->makeMessage( 'error', $text ) ); } $this->setAlignment( $config['align'] ); // Call this again to take into account the widget's accessKey $this->updateTitle(); } /** * @param string $kind 'error' or 'notice' * @param string|HtmlSnippet $text * @return Tag */ private function makeMessage( $kind, $text ) { $listItem = new Tag( 'li' ); if ( $kind === 'error' ) { $icon = new IconWidget( [ 'icon' => 'alert', 'flags' => [ 'warning' ] ] ); $listItem->setAttributes( [ 'role' => 'alert' ] ); } elseif ( $kind === 'notice' ) { $icon = new IconWidget( [ 'icon' => 'notice' ] ); } else { $icon = null; } $message = new LabelWidget( [ 'label' => $text ] ); $listItem ->appendContent( $icon, $message ) ->addClasses( [ "oo-ui-fieldLayout-messages-$kind" ] ); return $listItem; } /** * Get the field. * * @return Widget Field widget */ public function getField() { return $this->fieldWidget; } /** * Return `true` if the given field widget can be used with `'inline'` alignment (see * setAlignment()). Return `false` if it can't or if this can't be determined. * * @return bool */ public function isFieldInline() { // This is very simplistic, but should be good enough. It's important to avoid false positives, // as that will cause the generated HTML to be invalid and go all out of whack when parsed. return strtolower( $this->getField()->getTag() ) === 'span'; } /** * Set the field alignment mode. * * @param string $value Alignment mode, either 'left', 'right', 'top' or 'inline' * @return $this */ protected function setAlignment( $value ) { if ( $value !== $this->align ) { // Default to 'left' if ( !in_array( $value, [ 'left', 'right', 'top', 'inline' ] ) ) { $value = 'left'; } // Validate if ( $value === 'inline' && !$this->isFieldInline() ) { $value = 'top'; } // Reorder elements $this->body->clearContent(); if ( $this->helpInline ) { if ( $value === 'top' ) { $this->header->appendContent( $this->label ); $this->body->appendContent( $this->header, $this->field, $this->help ); } elseif ( $value === 'inline' ) { $this->header->appendContent( $this->label, $this->help ); $this->body->appendContent( $this->field, $this->header ); } else { $this->header->appendContent( $this->label, $this->help ); $this->body->appendContent( $this->header, $this->field ); } } else { if ( $value === 'top' ) { $this->header->appendContent( $this->help, $this->label ); $this->body->appendContent( $this->header, $this->field ); } elseif ( $value === 'inline' ) { $this->header->appendContent( $this->help, $this->label ); $this->body->appendContent( $this->field, $this->header ); } else { $this->header->appendContent( $this->label ); $this->body->appendContent( $this->header, $this->help, $this->field ); } } // Set classes. The following classes can be used here: // * oo-ui-fieldLayout-align-left // * oo-ui-fieldLayout-align-right // * oo-ui-fieldLayout-align-top // * oo-ui-fieldLayout-align-inline if ( $this->align ) { $this->removeClasses( [ 'oo-ui-fieldLayout-align-' . $this->align ] ); } $this->addClasses( [ 'oo-ui-fieldLayout-align-' . $value ] ); $this->align = $value; } return $this; } /** * Include information about the widget's accessKey in our title. TitledElement calls this method. * (This is a bit of a hack.) * * @param string $title Tooltip label for 'title' attribute * @return string */ protected function formatTitleWithAccessKey( $title ) { if ( $this->fieldWidget && method_exists( $this->fieldWidget, 'formatTitleWithAccessKey' ) ) { return $this->fieldWidget->formatTitleWithAccessKey( $title ); } return $title; } public function getConfig( &$config ) { $config['fieldWidget'] = $this->fieldWidget; $config['align'] = $this->align; $config['errors'] = $this->errors; $config['notices'] = $this->notices; $config['help'] = $this->helpText; $config['helpInline'] = $this->helpInline; $config['$overlay'] = true; return parent::getConfig( $config ); } /** * Creates and returns the help element. * * @return Widget The element that should become `$this->help`. */ private function createHelpElement() { if ( $this->helpInline ) { return new LabelWidget( [ 'classes' => [ 'oo-ui-inline-help' ], 'label' => $this->helpText, ] ); } else { return new ButtonWidget( [ 'classes' => [ 'oo-ui-fieldLayout-help' ], 'framed' => false, 'icon' => 'info', 'title' => $this->helpText, ] ); } } }