%PDF- %PDF-
| Direktori : /www/varak.net/wiki.varak.net/vendor/oojs/oojs-ui/php/mixins/ |
| Current File : //www/varak.net/wiki.varak.net/vendor/oojs/oojs-ui/php/mixins/TabIndexedElement.php |
<?php
namespace OOUI;
/**
* Element supporting "sequential focus navigation" using the 'tabindex' attribute.
*
* @abstract
*/
trait TabIndexedElement {
/**
* Tab index value.
*
* @var number|null
*/
protected $tabIndex = null;
/**
* @var Element
*/
protected $tabIndexed;
/**
* @param array $config Configuration options
* @param string|number|null $config['tabIndex'] Tab index value. Use 0 to use default ordering,
* use -1 to prevent tab focusing, use null to suppress the `tabindex` attribute. (default: 0)
*/
public function initializeTabIndexedElement( array $config = [] ) {
// Properties
$this->tabIndexed = $config['tabIndexed'] ?? $this;
// Initialization
$this->setTabIndex( $config['tabIndex'] ?? 0 );
$this->registerConfigCallback( function ( &$config ) {
if ( $this->tabIndex !== 0 ) {
$config['tabIndex'] = $this->tabIndex;
}
} );
}
/**
* Set tab index value.
*
* @param string|number|null $tabIndex Tab index value or null for no tab index
* @return $this
*/
public function setTabIndex( $tabIndex ) {
$tabIndex = preg_match( '/^-?\d+$/', $tabIndex ) ? (int)$tabIndex : null;
if ( $this->tabIndex !== $tabIndex ) {
$this->tabIndex = $tabIndex;
$this->updateTabIndex();
}
return $this;
}
/**
* Update the tabIndex attribute, in case of changes to tabIndex or disabled
* state.
*
* @return $this
*/
public function updateTabIndex() {
$disabled = $this->isDisabled();
if ( $this->tabIndex !== null ) {
$this->tabIndexed->setAttributes( [
// Do not index over disabled elements
'tabindex' => $disabled ? -1 : $this->tabIndex,
// ChromeVox and NVDA do not seem to inherit this from parent elements
'aria-disabled' => ( $disabled ? 'true' : 'false' )
] );
} else {
$this->tabIndexed->removeAttributes( [ 'tabindex', 'aria-disabled' ] );
}
return $this;
}
/**
* Get tab index value.
*
* @return number|null Tab index value
*/
public function getTabIndex() {
return $this->tabIndex;
}
/**
* Get an ID of a focusable element of this widget, if any, to be used for `<label for>` value.
*
* If the element already has an ID then that is returned, otherwise unique ID is
* generated, set on the element, and returned.
*
* @return string|null The ID of the focusable element
*/
public function getInputId() {
$id = $this->tabIndexed->getAttribute( 'id' );
if ( !$this->isLabelableNode( $this->tabIndexed ) ) {
return null;
}
if ( $id === null ) {
$id = Tag::generateElementId();
$this->tabIndexed->setAttributes( [ 'id' => $id ] );
}
return $id;
}
/**
* Whether the node is 'labelable' according to the HTML spec
* (i.e., whether it can be interacted with through a `<label for="…">`).
* See: <https://html.spec.whatwg.org/multipage/forms.html#category-label>.
*
* @param Tag $tag
* @return boolean
*/
private function isLabelableNode( Tag $tag ) {
$labelableTags = [ 'button', 'meter', 'output', 'progress', 'select', 'textarea' ];
$tagName = strtolower( $tag->getTag() );
if ( $tagName === 'input' && $tag->getAttribute( 'type' ) !== 'hidden' ) {
return true;
}
if ( in_array( $tagName, $labelableTags, true ) ) {
return true;
}
return false;
}
}