Файловый менеджер - Редактировать - /var/www/html/php.zip
Ðазад
PK ! �O��= = changelog.gznu �[��� � �\�r�F��裡�:Bj�h��>�IK�u0D_���08H��ڱ�1����&�E�I6��.g��Ƒ��Ǘ_fu�͌��i�yl��O�U���mOMwj= �jZT�~��'ք����R����v,���'��9y���&FV4��Ҽ$e*n���A�$���'�U��!_�I����+"���&�muB,�|�V�6�1=߳|oI���i~�IvO� ��������i��H�eD�Fh���PB�[�Q���Wϯ�b� �U��ۅ�ߢ��\�s}{���~DŽ}(sJv��"����d��\H�l��\EqX<H���w���.�}Ҟ�!���c�JQ�������(+�-�3��{^���KB|��P�[��|P�Oo]��QQ0.�����k|��_���$,�e�|w�{�f��!�ߥ9#4.Y��2�e�W4|[*vB�e#�eÞ���k>D,���!e;��mu�Vp�bF�(�݄<>�S��'�aY��y�d�J��#P��6��hV2�[ɏYHKƝ�<M�q�}wQ�%i���P�F���������wW��%���[�P��J��Ҹ�.�7�Són�㯿"���4� ����M$r�E"�n�b.��|�խ��!s&�B��|�αE�J��xW��Y�n!�։Rž(�.�#xjU� �pK���k�b�d�6)s�-<w2�g�����&-}{�hR�nav��>�h��PT%����WgW<7d�D�� i�v}s�g�ZC���\~��x�*�I������6�7M��4ks���/�O��I� ��L�ΓdWY}Ҿ�@�S��rReqJ��C}���k.��7ηyT�����2�w~�7��GR�c�Wt/��=�w�Mq��`�n-Gُ��ά���(I����ް�\]����V1�)?B[�}���l�MY��)���Rk���^s�.)B��H � ڔ���c��oa��$f��9$Ҝe��'9�Y�:O�4)�4n4����Fp �2ƙC��A��o-|K�z�/�D�����j��q�d#������,�zAo��\��۴!�2�� 6Jh^�ۂl �S��6[�y�8����_J~�E���������X�Y?�A�ua34��腠o�������nv�t4v�%�cC ��.��P �M��q����F�[�F�^Dy���C X���tw/��ǯ�6� B�iΣ�(� 2z��vY��U�{�����wWg�ߟ=�����f%���P�}G��n�%�ZPR�@���B�w�H�#��4�eћ&���]�ۂz�T%B�H$}H��@(�"�ܑ� 3tޤTe����/H�E~����c������+��w�x�hޛ�z�>���˷W�d��AZG� WX�B�J����e�c�*���A�U�kH��(ǔ�/T�&C����A=��EP�� �D��u�ce-Xǟ�s`18^�cg-1ND�?�xL�V���$�ad�O����_cz9T8�R�P��z�c,��8y4��۞���4�m+�D�YC�i���7�ǮZ?A��!��'"g1��e�U��\��!��&S�?�r4qY�� O��/:�.@���6q���2@A�tU�1+�B�-�H>}J���<�( �6ɧ\�$���Q�w6I�m��dI�֨d �sf��P�e�k��$�r!4j��|�a��'\px��^Լ J! *�5Yd�X����U6�ZsC��Y��� ����B��0>�H����F"#���6��Cʱ�B��4���;�`tξf���65 @� �,��RL�j�� ���Q�G���l��y�8|4��+%J�+�8���Ҳ�}?x�v�.�a9w�I�2�4���[�rO�(�F0Z�xp5bT�Pls�_�<C��֜i��?����d>u���H����L{>�-�+�dbIi�Ѥ�;p%h�#@�q�Z�{ۃ|1Ғ�Fpp-l�iJ�3$�QR�8_�E�U�����iٸ���+ � ��q }4m�(ц��� �!���/�2�!��T���L��볫�4�<��]/�E ��V���$3�_��\�`� ! �|l+\P�8 r��̷5Pgn��b�4=��vu-�KΪ��\����٠ܫ(j�m�,gt�*q��#X��w12�͕ ��|���GD�M��. OA@�S͉Ps�yR�vb0�x2:�>Hk��K�x4����,K�+�3w��`#��ɤ�J�!!����X�|e �R�yv�WAԅ���[������3�i�Sy��=` �obt5K�߲���y$���V +�ުF�G�, niD�B/Ԁ�<w�����)����%.|g&F&�-qP�S �~��qQ�s!p2�fw�х.��i���`~�q%%��'��ƀ�~CjΧ�D#;�K�&B�����m �P��MnL��F��2��] �-�r����9�ri-`*��,4��ûDhƱTh�՞�0�Ў��T1�<�Y%�oQi�.|�r?J'�'ъ��Ϗ��[({`�P�`� �'yb�§��|���i�FZ�w [i������B'a��p"���DM��t�wtt�jV1C����|>� �s�h\�i8MG�j���]St���՛��Ve����=�V��6��Z��`�Z��91��ѩsh�y�G� �kVޥ��We�g�Zh��,a��$�x�v��lj �����@�MX<2Cx���e�깳#��sZ���u�b1��-ˬ�OO7Q��tڞ*�� �y.V q�V��H�٬�9f�P<�vg@����gw�XL����C�Έ!��Dkp�[f �A�m��ݥ,��c�)JD�l����h[��ߝ�*�غz��� {��ۗ|G�N�;8�L\��8�}A���F:k� *�ɉ�C��R���5"ـ�p���sH�M�t���nqY�Lbж�ۭ��y���.��^��x� �A�yFFs>S�eG�!J��`����T�x�H+�[;X6������2�]�t+D�h��m�H��p�]Z�՟b# �yh� D�����bf�-S��,�6};���� q��@\#���XNzrj⫌v8){!���Gmų����b�;���?�|�s�IR��y�@)<�iU֢(��Q�1���?\7C��I5���v�(gA����(s�<6]# ix5_�-Y39����qQ7�,��9��,�k"]dd�r[���|G�f��>�9��?@(�E�����:Ϣ�q?l���r�6��wL�`�Z�G1��C�#���B:3U�\��c+���*��B@� $�*۞���N�SF��,ǨC�����f~��dЄ�Ĵ���v�t���ś����y`O���`KXЬ��e ���<�Y'�v�&☢�$���s +�=�,�y(��תEGpJ�̐�GU4��/�h��9{'5�`�V��X(�#�M�o*le�����&�h�ۋ`���� �Z�x�!���IN6��;�8����ʸV?]�<�w��Z��W�X���:�^%���,�h� �Zq\�̽@� J��J��OW��M-�m���Y�d4��k��'��#�:�`�i�����7U �6T$<+ i.�g��.x��R��M�ux����լc1$��Q�G��ucj�����a�;pmFq��ѳ8M3�}i��Z�j1�,����E����p�Xb8K%��$����� ���9�T�E������KxH�r�D{\n1�3�~�:����zʦ�A ! �EZti�P[)�B��+3C��� �brXc�N��m�,�9{�B�e�P��n�R�a^Ph!^J� �h�lbֵwflmi�ٙ9z���Y+�-�i+x�W����s{ċ�B��Ӫ�O!G�r�;��o���M��M�k��%-�bZl��� EK�-����QN��ļFe�~z���*��^�q��C�����U������4i�}q�4��W�Bxh��Mey�PLS ��x ����Ll(O1A���p(��f�� �5V{����w�q��?$�?��8Z��J��H�#_��WWo�py�N�AѨm���h��˧��Z�0�(Xk�Q�!1ǟ$i��>�9(��Y!/�Cpz1�whqT�1���g9V���es�^s���E��P���]Ҍ��-zK#au���QH[�3%�`SSG~��L;LJֽA�b�B�wv�g^�ro��1Z��՛��_�"Mb��+S�� � <��%��y����c꞊�9�ƪS,�J5� �,+ϗ@����&l�Z|�����z{�3��9�n�^ 䎪>���{#�Y�n:�#Kc.�jS�v�y��2�G�c�����1-��� �++�#��ˁ4���Uv���E�[C�~�Q�F\<������:�ב#��XM��/Zrb��nj����5cfDi�h�`^��i:�/�/��k ea��� ��i�PmB<4q �A��Cj�qBΥK8$�blð���<:[�G ���y���虋�U�Z�r��h�O6�Dv�q����Kb�eP���0 ��N/2D�h�1�p3ő�t�Ӑ�fq9��G�Tk"6�k X[Ps@�zĉ>Y.#9Q6���h-�D��#:�a#��<#�:h�˹=��p["�E�.n[�δ*S��Q���$�S�9��%���o���=iJ�L �@��1P �o�t��\�}9��e- D�=1�����!�$GAw��Dh�h�>�56�"Q�� �`�cf��b���m�w�X�&O���2b��#&g4 V�mZ�\?�Rh��<{%����&�9/� �8���� ҋ����}�~&;��:i\��~~!�Lj��0R4Ӂ��h�ag�ɜ[3w2��G� ]�6�Z�����[=� 0�e!~6����M5�����!e�;H�`��z�WeF��֣��Q\�Bw�o��'�-B�fC�\�A�.��Ve1���!��Պ�컳��E ����L���CZ� ~���Ygb���������^��x�SVܴ?�����Gd��A��;ja= O)���OU�r)�Q�d;<�Ϛ�}HUM�4j����;�'�� | I��l�C�[��oub��c]p��vΏ+N(� ��<r�,�L�W=�0�,�5>��c%�iŖk��x�K�-Ƈ6 P��B�E!���/!y֙���5�m���?66�0QM-g1��͋�H���~�,���Qd�(�Dz,u�K��I�c�}c�t�A����٧��8��v��t5}��h�!?���[±��<�ˋ���J�Pab�Z�A�eP����<��qt狆6�ԑ6��m�HŋO��u�;`k{������(S�|y�����AoDX�+^[�*��~�w0��ߤ�;�w9����mE��Fn�� ��Dv>�vtG )���c��<\Ϲ!1>���Dkk�5Ĺ������1����Mk��2��'�HS)fd�[������V���5ျV PK ! ��= = copyrightnu �[��� Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Author: Ondřej Surý <ondrej@debian.org> Files: * Copyright: 2015 Ondřej Surý License: Expat Files: php-maintscript-helper Copyright: 2012 Arno Töll 2013-2015 Ondřej Surý License: Expat License: Expat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: . The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. . THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK ! �?`�j j themes/WikimediaUITheme.phpnu �Iw�� <?php namespace OOUI; class WikimediaUITheme extends Theme { /* Methods */ /** @inheritDoc */ public function getElementClasses( Element $element ) { $variants = [ 'invert' => false, 'progressive' => false, 'destructive' => false, 'error' => false, 'warning' => false, 'success' => false ]; // Parent method $classes = parent::getElementClasses( $element ); if ( $element instanceof IconWidget && $element->hasClass( 'oo-ui-checkboxInputWidget-checkIcon' ) ) { // Icon on CheckboxInputWidget $variants['invert'] = true; } elseif ( $element->supports( [ 'hasFlag' ] ) ) { // @phan-suppress-next-line PhanUndeclaredMethod $isFramed = $element->supports( [ 'isFramed' ] ) && $element->isFramed(); // @phan-suppress-next-line PhanUndeclaredMethod $isActive = $element->supports( [ 'isActive' ] ) && $element->isActive(); if ( $isFramed && ( $isActive || $element->isDisabled() || $element->hasFlag( 'primary' ) ) ) { // Button with a dark background, use white icon $variants['invert'] = true; } elseif ( !$isFramed && $element->isDisabled() && !$element->hasFlag( 'invert' ) ) { // Frameless disabled button, always use black icon regardless of flags $variants['invert'] = false; } elseif ( !$element->isDisabled() ) { // Any other kind of button, use the right colored icon if available $variants['progressive'] = $element->hasFlag( 'progressive' ); $variants['destructive'] = $element->hasFlag( 'destructive' ); $variants['invert'] = $element->hasFlag( 'invert' ); $variants['error'] = $element->hasFlag( 'error' ); $variants['warning'] = $element->hasFlag( 'warning' ); $variants['success'] = $element->hasFlag( 'success' ); } } foreach ( $variants as $variant => $toggle ) { $classes[$toggle ? 'on' : 'off'][] = 'oo-ui-image-' . $variant; } return $classes; } } PK ! D��. . themes/BlankTheme.phpnu �Iw�� <?php namespace OOUI; class BlankTheme extends Theme { /* Methods */ /** @inheritDoc */ public function getElementClasses( Element $element ) { // Parent method $classes = parent::getElementClasses( $element ); // Add classes to $classes['on'] or $classes['off'] return $classes; } } PK ! �1H|: : themes/ApexTheme.phpnu �Iw�� <?php namespace OOUI; class ApexTheme extends Theme { } PK ! Ʊl�? ? Exception.phpnu �Iw�� <?php namespace OOUI; class Exception extends \Exception { } PK ! �.�x� � HtmlSnippet.phpnu �Iw�� <?php namespace OOUI; /** * Wraps a HTML snippet for use with Tag::appendContent() and Tag::prependContent(). */ class HtmlSnippet { /* Properties */ /** * HTML snippet this instance represents. * * @var string */ protected $content; /* Methods */ /** * @param string $content HTML snippet * @param-taint $content exec_html */ public function __construct( $content ) { if ( !is_string( $content ) ) { throw new Exception( 'Content passed to HtmlSnippet must be a string' ); } $this->content = $content; } /** * Render into HTML. * * @return string Unchanged HTML snippet */ public function __toString() { return $this->content; } } PK ! �v�W W Layout.phpnu �Iw�� <?php namespace OOUI; /** * Container for elements. * * @abstract */ class Layout extends Element { /** * @param array $config Configuration options */ public function __construct( array $config = [] ) { // Parent constructor parent::__construct( $config ); // Initialization $this->addClasses( [ 'oo-ui-layout' ] ); } } PK ! ��j� Theme.phpnu �Iw�� <?php namespace OOUI; /** * Theme logic. * * @abstract */ abstract class Theme { /* Properties */ /** @var self|null */ private static $singleton; /* Static Methods */ /** * @param Theme|null $theme Theme to use throughout the application */ public static function setSingleton( ?Theme $theme = null ) { self::$singleton = $theme; } /** * @return Theme */ public static function singleton() { if ( !self::$singleton ) { throw new Exception( __METHOD__ . ' was called with no singleton theme set.' ); } return self::$singleton; } /** * Get a list of classes to be applied to a widget. * * The 'on' and 'off' lists combined MUST contain keys for all classes the theme adds or removes, * otherwise state transitions will not work properly. * * @param Element $element Element for which to get classes * @return string[][] Categorized class names with `on` and `off` lists */ public function getElementClasses( Element $element ) { return [ 'on' => [], 'off' => [] ]; } /** * Update CSS classes provided by the theme. * * For elements with theme logic hooks, this should be called any time there's a state change. * * @param Element $element Element for which to update classes */ public function updateElementClasses( Element $element ) { $classes = $this->getElementClasses( $element ); if ( method_exists( $element, 'getIconElement' ) ) { // @phan-suppress-next-line PhanUndeclaredMethod $element->getIconElement() ->removeClasses( $classes['off'] ) ->addClasses( $classes['on'] ); } if ( method_exists( $element, 'getIndicatorElement' ) ) { // @phan-suppress-next-line PhanUndeclaredMethod $element->getIndicatorElement() ->removeClasses( $classes['off'] ) ->addClasses( $classes['on'] ); } } } PK ! ���� � Element.phpnu �Iw�� <?php namespace OOUI; /** * DOM element abstraction. * * @abstract */ class Element extends Tag { /* Static Properties */ /** * HTML tag name. * * This may be ignored if getTagName() is overridden. * * @var string */ public static $tagName = 'div'; /** * Default text direction, used for some layout calculations. Use setDefaultDir() to change. * * Currently only per-document directionality is supported. * * @var string */ public static $defaultDir = 'ltr'; /* Properties */ /** * Element data. * * @var mixed */ protected $data = null; /** * @var bool */ protected $visible = true; /** * Strings of the CSS classes explicitly configured for this element (as opposed to #$classes, * which contains all classes for this element). * * @var array */ protected $ownClasses = []; /** * @var callable[] */ protected $configCallbacks = []; /* Static methods */ /** * Emits a deprecation warning with provided message. * * @param string $message Message about the deprecation */ public static function warnDeprecation( $message = '' ) { trigger_error( $message, E_USER_DEPRECATED ); } /* Methods */ /** * @param array $config Configuration options * - string[] $config['classes'] CSS class names to add * - string $config['id'] HTML id attribute * - string $config['text'] Text to insert * - string[]|HtmlSnippet[]|Element[] $config['content'] Content to append (after text). * Strings will be HTML-escaped for output, use an HtmlSnippet instance to prevent that. * - mixed $config['data'] Element data */ public function __construct( array $config = [] ) { // Parent constructor parent::__construct( $this->getTagName() ); // Initialization if ( isset( $config['infusable'] ) && is_bool( $config['infusable'] ) ) { $this->setInfusable( $config['infusable'] ); } if ( isset( $config['data'] ) ) { $this->setData( $config['data'] ); } if ( isset( $config['classes'] ) && is_array( $config['classes'] ) ) { $this->ownClasses = $config['classes']; $this->addClasses( $this->ownClasses ); } if ( isset( $config['id'] ) ) { $this->setAttributes( [ 'id' => $config['id'] ] ); } if ( isset( $config['text'] ) ) { // JS compatibility $this->appendContent( $config['text'] ); } if ( isset( $config['content'] ) ) { $this->appendContent( $config['content'] ); } } /** * Get the HTML tag name. * * Override this method to base the result on instance information. * * @return string HTML tag name */ public function getTagName() { return $this::$tagName; } /** * Toggle visibility of an element. * * @param bool|null $show Make element visible, omit to toggle visibility * @return $this */ public function toggle( $show = null ) { $show = $show === null ? !$this->visible : $show; $this->visible = $show; $this->toggleClasses( [ 'oo-ui-element-hidden' ], !$this->visible ); return $this; } /** * Get element data. * * @return mixed Element data */ public function getData() { return $this->data; } /** * Set element data. * * @param mixed $data Element data * @return $this */ public function setData( $data ) { $this->data = $data; return $this; } /** * Check if element supports one or more methods. * * @param string|string[] $methods Method or list of methods to check * @return bool All methods are supported */ public function supports( $methods ) { foreach ( (array)$methods as $method ) { if ( !method_exists( $this, $method ) ) { return false; } } return true; } /** * Register an additional function to call when building the config. See ::getConfig(). * * @param callable $func The function. Parameters and return value are the same as ::getConfig(). */ public function registerConfigCallback( callable $func ) { $this->configCallbacks[] = $func; } /** * Add the necessary properties to the given `$config` array to allow * reconstruction of this widget via its constructor. * @param array &$config An array which will be mutated to add the necessary configuration * properties. Unless you are implementing a subclass, you should * always pass a new empty array `[]`. * @return array A configuration array which can be passed to this object's * constructor to recreate it. This is a return value to allow * the safe use of copy-by-value functions like `array_merge` in * the implementation. */ public function getConfig( &$config ) { // If there are traits, add their config foreach ( $this->configCallbacks as $func ) { $func( $config ); } if ( $this->data !== null ) { $config['data'] = $this->data; } if ( $this->ownClasses !== [] ) { $config['classes'] = $this->ownClasses; } return $config; } /** * Create a modified version of the configuration array suitable for * JSON serialization by replacing `Tag` references and * `HtmlSnippet`s. * * @return array A serialized configuration array. */ private function getSerializedConfig() { // Ensure that '_' comes first in the output. $config = [ '_' => true ]; $config = $this->getConfig( $config ); // Post-process config array to turn Tag references into ID references // and HtmlSnippet references into a { html: 'string' } JSON form. $replaceElements = static function ( &$item ) { if ( $item instanceof Tag ) { $item->ensureInfusableId(); $item = [ 'tag' => $item->getAttribute( 'id' ) ]; } elseif ( $item instanceof HtmlSnippet ) { $item = [ 'html' => (string)$item ]; } }; array_walk_recursive( $config, $replaceElements ); // Set '_' last to ensure that subclasses can't accidentally step on it. $config['_'] = $this->getJavaScriptClassName(); return $config; } /** * The class name of the JavaScript version of this widget * @return string */ protected function getJavaScriptClassName() { return str_replace( 'OOUI\\', 'OO.ui.', get_class( $this ) ); } /** * @return string[] */ protected function getGeneratedAttributes() { $attributesArray = parent::getGeneratedAttributes(); // Add `data-ooui` attribute from serialized config array. if ( $this->infusable ) { $serialized = $this->getSerializedConfig(); $attributesArray['data-ooui'] = json_encode( $serialized ); } return $attributesArray; } /** * Render element into HTML. * * @return string HTML serialization */ public function toString() { Theme::singleton()->updateElementClasses( $this ); if ( $this->isInfusable() ) { $this->ensureInfusableId(); } return parent::toString(); } /** * Get the direction of the user interface for a given element. * * Currently only per-document directionality is supported. * * @param Tag $element Element to check * @return string Text direction, either 'ltr' or 'rtl' */ public static function getDir( Tag $element ) { return self::$defaultDir; } /** * Set the default direction of the user interface. * * @param string $dir Text direction, either 'ltr' or 'rtl' */ public static function setDefaultDir( $dir ) { self::$defaultDir = $dir === 'rtl' ? 'rtl' : 'ltr'; } /** * A helper method to massage an array of HTML attributes into a format that is more likely to * work with an OOUI PHP element, camel-casing attribute names and setting values of boolean * ones to true. Intended as a convenience to be used when refactoring legacy systems using HTML * to use OOUI. * * @param array $attrs HTML attributes, e.g. `[ 'disabled' => '', 'accesskey' => 'k' ]` * @return array OOUI PHP element config, e.g. `[ 'disabled' => true, 'accessKey' => 'k' ]` */ public static function configFromHtmlAttributes( array $attrs ) { $booleanAttrs = [ 'disabled' => true, 'required' => true, 'autofocus' => true, 'multiple' => true, 'readonly' => true, ]; $attributeToConfig = [ 'maxlength' => 'maxLength', 'minlength' => 'minLength', 'readonly' => 'readOnly', 'tabindex' => 'tabIndex', 'accesskey' => 'accessKey', ]; $config = []; foreach ( $attrs as $key => $value ) { if ( isset( $booleanAttrs[$key] ) && $value !== false && $value !== null ) { $value = true; } if ( isset( $attributeToConfig[$key] ) ) { $key = $attributeToConfig[$key]; } $config[$key] = $value; } return $config; } } PK ! �*B�� � mixins/AccessKeyedElement.phpnu �Iw�� <?php namespace OOUI; /** * Element with an access key. * * Access keys allow an user to go to a specific element by using * a shortcut combination of a browser specific keys + the key * set to the field. * * @abstract */ trait AccessKeyedElement { /** * Access key * * @var ?string */ protected $accessKey = null; /** * @var Tag */ protected $accessKeyed; /** * @param array $config Configuration options * - string $config['accessKey'] Access key. If not provided, no access key will be added */ public function initializeAccessKeyedElement( array $config = [] ) { // Properties $this->accessKeyed = $config['accessKeyed'] ?? $this; // Initialization $this->setAccessKey( $config['accessKey'] ?? null ); $this->registerConfigCallback( function ( &$config ) { if ( $this->accessKey !== null ) { $config['accessKey'] = $this->accessKey; } } ); } /** * Set access key. * * @param string $accessKey Tag's access key, use empty string to remove * @return $this */ public function setAccessKey( $accessKey ) { $accessKey = is_string( $accessKey ) && strlen( $accessKey ) ? $accessKey : null; if ( $this->accessKey !== $accessKey ) { if ( $accessKey !== null ) { $this->accessKeyed->setAttributes( [ 'accesskey' => $accessKey ] ); } else { $this->accessKeyed->removeAttributes( [ 'accesskey' ] ); } $this->accessKey = $accessKey; // Only if this is a TitledElement if ( method_exists( $this, 'updateTitle' ) ) { // @phan-suppress-next-line PhanUndeclaredMethod $this->updateTitle(); } } return $this; } /** * Get access key. * * @return string Access key string */ public function getAccessKey() { return $this->accessKey; } /** * Add information about the access key to the element's tooltip label. * (This is only public for hacky usage in FieldLayout.) * * @param string $title Tooltip label for `title` attribute * @return string */ public function formatTitleWithAccessKey( $title ) { $accessKey = $this->getAccessKey(); if ( $accessKey ) { $title .= " [$accessKey]"; } return $title; } /** * @param callable $func */ abstract public function registerConfigCallback( callable $func ); } PK ! .��ĺ � mixins/LabelElement.phpnu �Iw�� <?php namespace OOUI; /** * Element containing a label. * * @abstract */ trait LabelElement { /** * Label value. * * @var string|HtmlSnippet|null */ protected $labelValue = null; /** * Label value. * * @var bool */ protected $invisibleLabel = false; /** * @var Tag */ protected $label; /** * @param array $config Configuration options * - string|HtmlSnippet $config['label'] Label text * - bool $config['invisibleLabel'] Whether the label should be visually hidden (but still * accessible to screen-readers). (default: false) */ public function initializeLabelElement( array $config = [] ) { // Properties // FIXME 'labelElement' is a very stupid way to call '$label' $this->label = $config['labelElement'] ?? new Tag( 'span' ); // Initialization $this->label->addClasses( [ 'oo-ui-labelElement-label' ] ); $this->setLabel( $config['label'] ?? null ); $this->setInvisibleLabel( $config['invisibleLabel'] ?? false ); $this->registerConfigCallback( function ( &$config ) { if ( $this->labelValue !== null ) { $config['label'] = $this->labelValue; } if ( $this->invisibleLabel !== false ) { $config['invisibleLabel'] = $this->invisibleLabel; } } ); } /** * Set the label. * * An empty string will result in the label being hidden. A string containing only whitespace will * be converted to a single ` `. * * @param string|HtmlSnippet|null $label Label text * @return $this */ public function setLabel( $label ) { $this->labelValue = (string)$label !== '' ? $label : null; $this->label->clearContent(); if ( $this->labelValue !== null ) { if ( is_string( $this->labelValue ) && trim( $this->labelValue ) === '' ) { $this->label->appendContent( new HtmlSnippet( ' ' ) ); } else { $this->label->appendContent( $label ); } } $visibleLabel = $this->labelValue !== null && !$this->invisibleLabel; $this->toggleClasses( [ 'oo-ui-labelElement' ], $visibleLabel ); return $this; } /** * Set whether the label should be visually hidden (but still accessible to screen-readers). * * An empty string will result in the label being hidden. A string containing only whitespace will * be converted to a single ` `. * * @param bool $invisibleLabel * @return $this */ public function setInvisibleLabel( $invisibleLabel ) { $this->invisibleLabel = (bool)$invisibleLabel; $this->label->toggleClasses( [ 'oo-ui-labelElement-invisible' ], $this->invisibleLabel ); // Pretend that there is no label, a lot of CSS has been written with this assumption $visibleLabel = $this->labelValue !== null && !$this->invisibleLabel; $this->toggleClasses( [ 'oo-ui-labelElement' ], $visibleLabel ); return $this; } /** * Get the label. * * @return string|HtmlSnippet|null Label text */ public function getLabel() { return $this->labelValue; } /** * Toggle CSS classes. * * @param array $classes List of classes to add * @param bool|null $toggle Add classes * @return $this */ abstract public function toggleClasses( array $classes, $toggle = null ); /** * @param callable $func */ abstract public function registerConfigCallback( callable $func ); } PK ! Ǵ�D! ! mixins/IndicatorElement.phpnu �Iw�� <?php namespace OOUI; /** * Element containing an indicator. * * Indicators are graphics, smaller than normal text. They can be used to describe unique status or * behavior. Indicators should only be used in exceptional cases; such as a button that opens a menu * instead of performing an action directly, or an item in a list which has errors that need to be * resolved. * * @abstract */ trait IndicatorElement { /** * Symbolic indicator name * * @var string|null */ protected $indicatorName = null; /** * @var Tag */ protected $indicator; /** * @param array $config Configuration options * - string $config['indicator'] Symbolic indicator name */ public function initializeIndicatorElement( array $config = [] ) { // Properties // FIXME 'indicatorElement' is a very stupid way to call '$indicator' $this->indicator = $config['indicatorElement'] ?? new Tag( 'span' ); // Initialization $this->indicator->addClasses( [ 'oo-ui-indicatorElement-indicator' ] ); $this->setIndicator( $config['indicator'] ?? null ); $this->registerConfigCallback( function ( &$config ) { if ( $this->indicatorName !== null ) { $config['indicator'] = $this->indicatorName; } } ); } /** * Set indicator name. * * @param string|null $indicator Symbolic name of indicator to use or null for no indicator * @return $this */ public function setIndicator( $indicator = null ) { if ( $this->indicatorName !== null ) { $this->indicator->removeClasses( [ 'oo-ui-indicator-' . $this->indicatorName ] ); } if ( $indicator !== null ) { $this->indicator->addClasses( [ 'oo-ui-indicator-' . $indicator ] ); } $this->indicatorName = $indicator; $this->toggleClasses( [ 'oo-ui-indicatorElement' ], (bool)$this->indicatorName ); $this->indicator->toggleClasses( [ 'oo-ui-indicatorElement-noIndicator' ], !$this->indicatorName ); return $this; } /** * Get indicator name. * * @return string|null Symbolic name of indicator, null if not set */ public function getIndicator() { return $this->indicatorName; } /** * Do not use outside of Theme::updateElementClasses * * @protected * @return Tag */ public function getIndicatorElement() { return $this->indicator; } /** * Toggle CSS classes. * * @param array $classes List of classes to add * @param bool|null $toggle Add classes * @return $this */ abstract public function toggleClasses( array $classes, $toggle = null ); /** * @param callable $func */ abstract public function registerConfigCallback( callable $func ); } PK ! �!�O9 9 mixins/RequiredElement.phpnu �Iw�� <?php namespace OOUI; /** * Element with a required attribute. * * @abstract */ trait RequiredElement { /** * Mark as required. * * @var bool */ protected $required = false; /** * @var Element */ protected $requiredElement; /** * @var IndicatorElement|null */ protected $indicatorElement; /** * @var Element|null */ protected $input; /** * @param array $config Configuration options * - bool $config['required'] Mark the field as required. * Implies `indicator: 'required'`. Note that `false` & setting `indicator: 'required' * will result in no indicator shown. (default: false) * - Element $config['requiredElement'] * - IndicatorElement $config['indicatorElement'] */ public function initializeRequiredElement( array $config = [] ) { // Properties $this->requiredElement = $config['requiredElement'] ?? ( $this->input ?? $this ); $this->indicatorElement = array_key_exists( 'indicatorElement', $config ) ? $config['indicatorElement'] : $this; if ( $this->indicatorElement && !method_exists( $this->indicatorElement, 'getIndicator' ) ) { throw new Exception( 'config[\'indicatorElement\'] must use the IndicatorElement trait.' ); } // Initialization $this->setRequired( $config['required'] ?? false ); $this->registerConfigCallback( function ( &$config ) { $config['required'] = $this->required; } ); } /** * Check if the widget is required. * * @return bool */ public function isRequired(): bool { return $this->required; } /** * Set the required state of the widget. * * @param bool $state Make input required * @return $this */ public function setRequired( bool $state ) { $this->required = $state; if ( $this->required ) { $this->requiredElement->setAttributes( [ 'required' => null ] ); if ( $this->indicatorElement && $this->indicatorElement->getIndicator() === null ) { $this->indicatorElement->setIndicator( 'required' ); } } else { $this->requiredElement->removeAttributes( [ 'required' ] ); if ( $this->indicatorElement && $this->indicatorElement->getIndicator() === 'required' ) { $this->indicatorElement->setIndicator( null ); } } return $this; } /** * @param callable $func */ abstract public function registerConfigCallback( callable $func ); } PK ! ��2� � mixins/GroupElement.phpnu �Iw�� <?php namespace OOUI; /** * Element containing a sequence of child elements. * * @abstract */ trait GroupElement { /** * List of items in the group as Elements. * * @var Element[] */ protected $items = []; /** * @var Tag */ protected $group; /** * @param array $config Configuration options */ public function initializeGroupElement( array $config = [] ) { // Properties $this->group = $config['group'] ?? new Tag( 'div' ); $this->registerConfigCallback( function ( &$config ) { $config['items'] = $this->items; } ); } /** * Check if there are no items. * * @return bool Group is empty */ public function isEmpty() { return $this->items === []; } /** * Get items. * * @return Element[] Items */ public function getItems() { return $this->items; } /** * @param mixed $data * @return Element|null */ public function findItemFromData( $data ) { $items = $this->getItems(); // TODO: Support non-string $data using a hash (e.g. json_encode) foreach ( $items as $item ) { if ( $item->getData() === $data ) { return $item; } } return null; } /** * Add items. * * Adding an existing item will move it. * * @param Element[] $items Items * @param int|null $index Index to insert items at * @return $this */ public function addItems( array $items, $index = null ) { foreach ( $items as $item ) { // Check if item exists then remove it first, effectively "moving" it $currentIndex = array_search( $item, $this->items, true ); if ( $currentIndex !== false ) { $this->removeItems( [ $item ] ); // Adjust index to compensate for removal if ( $currentIndex < $index ) { $index--; } } // Add the item $item->setElementGroup( $this ); } if ( $index === null || $index < 0 || $index >= count( $this->items ) ) { $this->items = array_merge( $this->items, $items ); } else { array_splice( $this->items, $index, 0, $items ); } // Update actual target element contents to reflect our list $this->group->clearContent(); $this->group->appendContent( $this->items ); return $this; } /** * Remove items. * * @param Element[] $items Items to remove * @return $this */ public function removeItems( $items ) { foreach ( $items as $item ) { $index = array_search( $item, $this->items, true ); if ( $index !== false ) { $item->setElementGroup( null ); array_splice( $this->items, $index, 1 ); } } // Update actual target element contents to reflect our list $this->group->clearContent(); $this->group->appendContent( $this->items ); return $this; } /** * Clear all items. * * Items will be detached, not removed, so they can be used later. * * @return $this */ public function clearItems() { foreach ( $this->items as $item ) { $item->setElementGroup( null ); } $this->items = []; $this->group->clearContent(); return $this; } /** * @param callable $func */ abstract public function registerConfigCallback( callable $func ); } PK ! 0e�c c mixins/TitledElement.phpnu �Iw�� <?php namespace OOUI; /** * Element with a title. * * Titles are rendered by the browser and are made visible when hovering the element. Titles are * not visible on touch devices. * * @abstract */ trait TitledElement { /** * Title text. * * @var string */ protected $title = null; /** * @var Element */ protected $titled; /** * @param array $config Configuration options * - string $config['title'] Title. If not provided, the static property 'title' is used. * If config for an invisible label (LabelElement) is present, and a title is * omitted, the label will be used as a fallback for the title. */ public function initializeTitledElement( array $config = [] ) { // Properties $this->titled = $config['titled'] ?? $this; // Initialization $title = $config['title'] ?? null; if ( $title === null && isset( $config['invisibleLabel'] ) && $config['invisibleLabel'] && isset( $config['label'] ) && is_string( $config['label'] ) ) { // If config for an invisible label is present, use this as a fallback title $title = $config['label']; } $this->setTitle( $title ); $this->registerConfigCallback( function ( &$config ) { if ( $this->title !== null ) { $config['title'] = $this->title; } } ); } /** * Set title. * * @param string|null $title Title text or null for browser default title, which is no title for * most elements. * @return $this */ public function setTitle( $title ) { if ( $this->title !== $title ) { $this->title = $title; $this->updateTitle(); } return $this; } /** * Update the title attribute, in case of changes to title or accessKey. * * @return $this */ protected function updateTitle() { $title = $this->getTitle(); if ( $title !== null ) { // Only if this is an AccessKeyedElement if ( method_exists( $this, 'formatTitleWithAccessKey' ) ) { // @phan-suppress-next-line PhanUndeclaredMethod $title = $this->formatTitleWithAccessKey( $title ); } $this->titled->setAttributes( [ 'title' => $title ] ); } else { $this->titled->removeAttributes( [ 'title' ] ); } return $this; } /** * Get title. * * @return string Title string */ public function getTitle() { return $this->title; } /** * @param callable $func */ abstract public function registerConfigCallback( callable $func ); } PK ! �^��U U mixins/GroupWidget.phpnu �Iw�� <?php namespace OOUI; /** * Use together with ItemWidget to make disabled state inheritable. * * @abstract * * @method Widget[] getItems() */ trait GroupWidget { use GroupElement; /** * @param bool $disabled */ public function setDisabled( $disabled ) { // @phan-suppress-next-line PhanTraitParentReference parent::setDisabled( $disabled ); $modifiedItems = []; $items = $this->getItems(); /** @var Widget $item */ foreach ( $items as $item ) { $modifiedItems[] = $item->setDisabled( $disabled ); } $this->clearItems(); $this->addItems( $modifiedItems ); } } PK ! jK#.� � mixins/TabIndexedElement.phpnu �Iw�� <?php namespace OOUI; /** * Element supporting "sequential focus navigation" using the 'tabindex' attribute. * * @abstract */ trait TabIndexedElement { /** * Tab index value. * * @var int|null */ protected $tabIndex = null; /** * @var Element */ protected $tabIndexed; /** * @param array $config Configuration options * - string|int|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|int|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 ) { // Do not index over disabled elements $this->tabIndexed->setAttributes( [ 'tabindex' => $disabled ? -1 : $this->tabIndex ] ); if ( $disabled ) { // ChromeVox and NVDA do not seem to inherit this from parent elements $this->tabIndexed->setAttributes( [ 'aria-disabled' => 'true' ] ); } else { $this->tabIndexed->removeAttributes( [ 'aria-disabled' ] ); } } else { $this->tabIndexed->removeAttributes( [ 'tabindex', 'aria-disabled' ] ); } return $this; } /** * Get tab index value. * * @return int|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 bool */ 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; } /** * @return bool */ abstract public function isDisabled(); /** * @param callable $func */ abstract public function registerConfigCallback( callable $func ); } PK ! �mN:� � mixins/ButtonElement.phpnu �Iw�� <?php namespace OOUI; /** * Element with a button. * * Buttons are used for controls which can be clicked. They can be configured to use tab indexing * and access keys for accessibility purposes. * * @abstract */ trait ButtonElement { /** * Button is framed. * * @var bool */ protected $framed = false; /** * @var Tag */ protected $button; /** * @param array $config Configuration options * - bool $config['framed'] Render button with a frame (default: true) */ public function initializeButtonElement( array $config = [] ) { // Properties if ( !$this instanceof Element ) { throw new Exception( "ButtonElement trait can only be used on Element instances" ); } $target = $config['button'] ?? new Tag( 'a' ); $this->button = $target; // Initialization $this->addClasses( [ 'oo-ui-buttonElement' ] ); $this->button->addClasses( [ 'oo-ui-buttonElement-button' ] ); $this->toggleFramed( $config['framed'] ?? true ); // Add `role="button"` on `<a>` elements, where it's needed if ( strtolower( $this->button->getTag() ) === 'a' ) { $this->button->setAttributes( [ 'role' => 'button', ] ); } $this->registerConfigCallback( function ( &$config ) { if ( $this->framed !== true ) { $config['framed'] = $this->framed; } } ); } /** * Toggle frame. * * @param bool|null $framed Make button framed, omit to toggle * @return $this */ public function toggleFramed( $framed = null ) { $this->framed = $framed !== null ? (bool)$framed : !$this->framed; $this->toggleClasses( [ 'oo-ui-buttonElement-framed' ], $this->framed ); $this->toggleClasses( [ 'oo-ui-buttonElement-frameless' ], !$this->framed ); return $this; } /** * Check if button has a frame. * * @return bool Button is framed */ public function isFramed() { return $this->framed; } /** * Toggle CSS classes. * * @param array $classes List of classes to add * @param bool|null $toggle Add classes * @return $this */ abstract public function toggleClasses( array $classes, $toggle = null ); /** * @param callable $func */ abstract public function registerConfigCallback( callable $func ); } PK ! � K�� � mixins/IconElement.phpnu �Iw�� <?php namespace OOUI; /** * Element containing an icon. * * Icons are graphics, about the size of normal text. They can be used to aid the user in locating * a control or convey information in a more space efficient way. Icons should rarely be used * without labels; such as in a toolbar where space is at a premium or within a context where the * meaning is very clear to the user. * * @abstract */ trait IconElement { /** * Symbolic icon name. * * @var ?string */ protected $iconName = null; /** * @var Tag */ protected $icon; /** * @param array $config Configuration options * - string $config['icon'] Symbolic icon name */ public function initializeIconElement( array $config = [] ) { // Properties // FIXME 'iconElement' is a very stupid way to call '$icon' $this->icon = $config['iconElement'] ?? new Tag( 'span' ); // Initialization $this->icon->addClasses( [ 'oo-ui-iconElement-icon' ] ); $this->setIcon( $config['icon'] ?? null ); $this->registerConfigCallback( function ( &$config ) { if ( $this->iconName !== null ) { $config['icon'] = $this->iconName; } } ); } /** * Set icon name. * * @param string|null $icon Symbolic icon name * @return $this */ public function setIcon( $icon = null ) { if ( $this->iconName !== null ) { $this->icon->removeClasses( [ 'oo-ui-icon-' . $this->iconName ] ); } if ( $icon !== null ) { $this->icon->addClasses( [ 'oo-ui-icon-' . $icon ] ); } $this->iconName = $icon; $this->toggleClasses( [ 'oo-ui-iconElement' ], (bool)$this->iconName ); $this->icon->toggleClasses( [ 'oo-ui-iconElement-noIcon' ], !$this->iconName ); return $this; } /** * Get icon name. * * @return string Icon name */ public function getIcon() { return $this->iconName; } /** * Do not use outside of Theme::updateElementClasses * * @protected * @return Tag */ public function getIconElement() { return $this->icon; } /** * Toggle CSS classes. * * @param array $classes List of classes to add * @param bool|null $toggle Add classes * @return $this */ abstract public function toggleClasses( array $classes, $toggle = null ); /** * @param callable $func */ abstract public function registerConfigCallback( callable $func ); } PK ! POq q mixins/FlaggedElement.phpnu �Iw�� <?php namespace OOUI; /** * Element with named flags that can be added, removed, listed and checked. * * A flag, when set, adds a CSS class on the `$element` by combining `oo-ui-flaggedElement-` with * the flag name. Flags are primarily useful for styling. * * @abstract */ trait FlaggedElement { /** * Flags. * * @var bool[] * @phan-var array<string,bool> */ protected $flags = []; /** * @var Element */ protected $flagged; /** * @param array $config Configuration options * - string|string[] $config['flags'] Flags describing importance and functionality, e.g. * 'primary', 'safe', 'progressive', or 'destructive'. */ public function initializeFlaggedElement( array $config = [] ) { // Properties $this->flagged = $config['flagged'] ?? $this; // Initialization $this->setFlags( $config['flags'] ?? null ); $this->registerConfigCallback( function ( &$config ) { if ( $this->flags ) { $config['flags'] = $this->getFlags(); } } ); } /** * Check if a flag is set. * * @param string $flag Name of flag * @return bool Has flag */ public function hasFlag( $flag ) { return isset( $this->flags[$flag] ); } /** * Get the names of all flags set. * * @return string[] Flag names */ public function getFlags() { return array_keys( $this->flags ); } /** * Clear all flags. * * @return $this */ public function clearFlags() { $remove = []; $classPrefix = 'oo-ui-flaggedElement-'; foreach ( $this->flags as $flag => $value ) { $remove[] = $classPrefix . $flag; } $this->flagged->removeClasses( $remove ); $this->flags = []; return $this; } /** * Add one or more flags. * * @param string|array $flags One or more flags to add, or an array keyed by flag name * containing boolean set/remove instructions. * @return $this */ public function setFlags( $flags ) { $add = []; $remove = []; $classPrefix = 'oo-ui-flaggedElement-'; if ( is_string( $flags ) ) { // Set if ( !isset( $this->flags[$flags] ) ) { $this->flags[$flags] = true; $add[] = $classPrefix . $flags; } } elseif ( is_array( $flags ) ) { foreach ( $flags as $key => $value ) { if ( is_numeric( $key ) ) { // Set if ( !isset( $this->flags[$value] ) ) { $this->flags[$value] = true; $add[] = $classPrefix . $value; } } else { if ( $value ) { // Set if ( !isset( $this->flags[$key] ) ) { $this->flags[$key] = true; $add[] = $classPrefix . $key; } } else { // Remove if ( isset( $this->flags[$key] ) ) { unset( $this->flags[$key] ); $remove[] = $classPrefix . $key; } } } } } $this->flagged ->addClasses( $add ) ->removeClasses( $remove ); return $this; } /** * @param callable $func */ abstract public function registerConfigCallback( callable $func ); } PK ! ��(�B) B) layouts/FieldLayout.phpnu �Iw�� <?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; /** * Warning messages. * * @var array */ protected $warnings; /** * Success messages. * * @var array */ protected $successMessages; /** * Notice messages. * * @var array */ protected $notices; /** * @var ButtonWidget|string */ protected $help; /** @var Tag */ protected $field; /** @var Tag */ protected $header; /** @var Tag */ protected $body; /** @var Tag */ protected $messages; /** @var string */ protected $helpText; /** @var string|false */ protected $helpInline; /** * @param Widget $fieldWidget Field widget. An exception is thrown if no widget is specified. * @param array $config Configuration options * - string $config['align'] Alignment mode, either 'left', 'right', 'top' or 'inline' * (default: 'left') * - string[]|HtmlSnippet[] $config['errors'] Error messages about the widget. * - string[]|HtmlSnippet[] $config['warnings'] Warning messages about the widget. * - string[]|HtmlSnippet[] $config['notices'] Notices about the widget. * - string|HtmlSnippet $config['help'] Explanatory text shown as a '?' icon, or inline. * - bool $config['helpInline'] Whether or not the help should be inline, * or shown when the "help" icon is clicked. (default: false) */ 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 if ( ( $config['help'] ?? '' ) !== '' && ( $config['label'] ?? '' ) === '' ) { // Add an empty label. For some combinations of 'helpInline' and 'align' // there would be no space in the interface to display the help text otherwise. $config['label'] = ' '; } // Parent constructor parent::__construct( $config ); // Properties $this->fieldWidget = $fieldWidget; $this->errors = $config['errors'] ?? []; $this->warnings = $config['warnings'] ?? []; $this->successMessages = $config['successMessages'] ?? []; $this->notices = $config['notices'] ?? []; $this->field = $this->isFieldInline() ? new Tag( 'span' ) : new Tag( 'div' ); $this->messages = new Tag( 'div' ); $this->header = new Tag( 'span' ); $this->body = new Tag( 'div' ); $this->helpText = $config['help'] ?? ''; $this->helpInline = $config['helpInline'] ?? false; // Traits $this->initializeLabelElement( array_merge( [ 'labelElement' => new Tag( 'label' ) ], $config ) ); $this->initializeTitledElement( array_merge( [ 'titled' => $this->label ], $config ) ); // Initialization $this->help = $this->helpText === '' ? '' : $this->createHelpElement(); if ( $this->fieldWidget->getInputId() ) { $this->label->setAttributes( [ 'for' => $this->fieldWidget->getInputId() ] ); if ( $this->helpText !== '' && $this->helpInline ) { $this->help->setAttributes( [ 'for' => $this->fieldWidget->getInputId() ] ); } } else { // We can't use `label for` with non-form elements, use `aria-labelledby` instead $id = Tag::generateElementId(); $this->label->setAttributes( [ 'id' => $id ] ); $this->fieldWidget->setLabelledBy( $id ); } $this ->addClasses( [ 'oo-ui-fieldLayout' ] ) ->toggleClasses( [ 'oo-ui-fieldLayout-disabled' ], $this->fieldWidget->isDisabled() ) ->appendContent( $this->body ); if ( count( $this->errors ) || count( $this->warnings ) || count( $this->successMessages ) || 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->errors as $text ) { $this->messages->appendContent( $this->makeMessage( 'error', $text ) ); } foreach ( $this->warnings as $text ) { $this->messages->appendContent( $this->makeMessage( 'warning', $text ) ); } foreach ( $this->successMessages as $text ) { $this->messages->appendContent( $this->makeMessage( 'success', $text ) ); } foreach ( $this->notices as $text ) { $this->messages->appendContent( $this->makeMessage( 'notice', $text ) ); } $this->setAlignment( $config['align'] ?? 'left' ); // Call this again to take into account the widget's accessKey $this->updateTitle(); } /** * @param string $kind 'error', 'warning', 'success' or 'notice' * @param string|HtmlSnippet $text * @return Tag */ private function makeMessage( $kind, $text ) { return new MessageWidget( [ 'type' => $kind, 'inline' => true, 'label' => $text, ] ); } /** * 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' ) ) { // @phan-suppress-next-line PhanUndeclaredMethod return $this->fieldWidget->formatTitleWithAccessKey( $title ); } return $title; } /** @inheritDoc */ public function getConfig( &$config ) { $config['fieldWidget'] = $this->fieldWidget; if ( $this->align !== 'left' ) { $config['align'] = $this->align; } if ( count( $this->errors ) ) { $config['errors'] = $this->errors; } if ( count( $this->warnings ) ) { $config['warnings'] = $this->warnings; } if ( count( $this->successMessages ) ) { $config['successMessages'] = $this->successMessages; } if ( count( $this->notices ) ) { $config['notices'] = $this->notices; } if ( $this->helpText !== '' ) { $config['help'] = $this->helpText; } if ( $this->helpInline ) { $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, // TODO We have no way to use localisation messages in PHP // (and to use different languages when used from MediaWiki) // 'label' => msg( 'ooui-field-help' ), // 'invisibleLabel' => true, ] ); } } } PK ! :�q� � layouts/ActionFieldLayout.phpnu �Iw�� <?php namespace OOUI; /** * Layout made of a field, button and optional label. */ class ActionFieldLayout extends FieldLayout { /** * Button widget to be laid out. * * @var Widget */ protected $buttonWidget; /** * @var Tag */ protected $button; /** * @var Tag */ protected $input; /** * @param Widget $fieldWidget Field widget * @param ButtonWidget|ButtonInputWidget $buttonWidget Field widget * @param array $config Configuration options * @suppress PhanTypeMismatchDefault Overloaded method */ public function __construct( $fieldWidget, $buttonWidget = false, array $config = [] ) { // Allow passing positional parameters inside the config array if ( is_array( $fieldWidget ) && isset( $fieldWidget['fieldWidget'] ) ) { $config = $fieldWidget; [ 'fieldWidget' => $fieldWidget, 'buttonWidget' => $buttonWidget ] = $config; } // Parent constructor parent::__construct( $fieldWidget, $config ); // Properties $this->buttonWidget = $buttonWidget; $this->button = new Tag( 'span' ); $this->input = $this->isFieldInline() ? new Tag( 'span' ) : new Tag( 'div' ); // Initialization $this->addClasses( [ 'oo-ui-actionFieldLayout' ] ); $this->button ->addClasses( [ 'oo-ui-actionFieldLayout-button' ] ) ->appendContent( $this->buttonWidget ); $this->input ->addClasses( [ 'oo-ui-actionFieldLayout-input' ] ) ->appendContent( $this->fieldWidget ); $this->field ->clearContent() ->appendContent( $this->input, $this->button ); } /** @inheritDoc */ public function getConfig( &$config ) { $config['buttonWidget'] = $this->buttonWidget; return parent::getConfig( $config ); } } PK ! +We�$ $ layouts/IndexLayout.phpnu �Iw�� <?php namespace OOUI; /** * IndexLayouts contain TabPanelLayout layouts as well as TabSelectWidget tabs that allow users * to navigate through the tab panels and select which one to display. * * Default php rendering shows all the tabs */ class IndexLayout extends MenuLayout { /** * @var StackLayout */ protected $stackLayout; /** * @var PanelLayout */ protected $tabPanel; /** * @var TabPanelLayout[] */ protected $tabPanels; /** * @var TabSelectWidget */ protected $tabSelectWidget; /** * @var bool */ protected $autoFocus; /** * @var bool */ protected $continuous; /** * @var string */ protected $currentTabPanelName; /** * @param array $config Configuration options * - bool $config['continuous'] Focus on the first focusable element when a new tab panel is * displayed. Disabled on mobile. (default: false) * - bool $config['autoFocus'] (default: true) * - bool $config['framed'] (default: true) */ public function __construct( array $config = [] ) { $config = array_merge( $config, [ 'menuPosition' => 'top' ] ); parent::__construct( $config ); $this->tabPanels = []; $this->continuous = $config['continuous'] ?? false; $this->stackLayout = $this->contentPanel ?? new StackLayout( [ 'continuous' => $this->continuous, 'expanded' => $this->expanded ] ); $this->setContentPanel( $this->stackLayout ); $this->autoFocus = $config['autoFocus'] ?? true; $this->tabSelectWidget = new TabSelectWidget( [ 'framed' => $config['framed'] ?? true ] ); $this->tabPanel = $this->menuPanel ?? new PanelLayout( [ 'expanded' => $this->expanded, 'preserveContent' => false ] ); $this->setMenuPanel( $this->tabPanel ); $this->toggleMenu( true ); $this->addClasses( [ 'oo-ui-indexLayout' ] ); $this->stackLayout->addClasses( [ 'oo-ui-indexLayout-stackLayout' ] ); $this->tabPanel ->addClasses( [ 'oo-ui-indexLayout-tabPanel' ] ) ->appendContent( $this->tabSelectWidget ); } /** @inheritDoc */ public function getConfig( &$config ) { $config = parent::getConfig( $config ); if ( !$this->autoFocus ) { $config['autoFocus'] = $this->autoFocus; } if ( $this->continuous ) { $config['continuous'] = $this->continuous; } if ( count( $this->tabPanels ) ) { $config['tabPanels'] = $this->tabPanels; } // menuPosition is not configurable unset( $config['menuPosition'] ); $config['tabSelectWidget'] = $this->tabSelectWidget; // stackLayout and tabPanel are identical to // contentPanel and menuPanel in MenuLayout return $config; } /** * Get the tabs widget. * * @return TabSelectWidget Tabs widget */ public function getTabs() { return $this->tabSelectWidget; } /** * Get a tab panel by its symbolic name. * * @param string $name Symbolic name of table panel * @return TabPanelLayout|null Tab panel, if found */ public function getTabPanel( $name ): ?TabPanelLayout { return $this->tabPanels[$name] ?? null; } /** * @return TabPanelLayout|null */ public function getCurrentTabPanel() { $name = $this->getCurrentTabPanelName(); return $name ? $this->getTabPanel( $name ) : null; } /** * @return string */ public function getCurrentTabPanelName() { return $this->currentTabPanelName; } /** * Add tab panels to the index layout * * When tab panels are added with the same names as existing tab panels, the existing tab panels * will be automatically removed before the new tab panels are added. * * @param TabPanelLayout[] $tabPanels Tab panels to add */ public function addTabPanels( array $tabPanels ) { $tabItems = []; foreach ( $tabPanels as $tabPanel ) { $this->tabPanels[ $tabPanel->getName() ] = $tabPanel; $tabItem = new TabOptionWidget( array_merge( [ 'data' => $tabPanel->getName(), 'label' => $tabPanel->getLabel(), ], $tabPanel->getTabItemConfig() ) ); // TODO: Set aria-labelledby/aria-controls as in .js $tabItems[] = $tabItem; } $this->tabSelectWidget->addItems( $tabItems ); $this->stackLayout->addItems( $tabPanels ); // Select the first item $this->getTabs()->selectItem( $tabItems[ 0 ] ); } /** * Set the current tab panel by symbolic name. * * @param string $name Symbolic name of tab panel */ public function setTabPanel( $name ) { if ( $name !== $this->currentTabPanelName ) { $tabPanel = $this->getTabPanel( $name ); $previousTabPanel = $this->getCurrentTabPanel(); $selectedItem = $this->getTabs()->findSelectedItem(); if ( !$selectedItem || $selectedItem->getData() !== $name ) { $this->getTabs()->selectItemByData( $name ); } if ( $tabPanel ) { if ( $previousTabPanel ) { $previousTabPanel->setActive( false ); } $this->currentTabPanelName = $name; $tabPanel->setActive( true ); $this->stackLayout->setItem( $tabPanel ); } } } } PK ! �� � layouts/HorizontalLayout.phpnu �Iw�� <?php namespace OOUI; /** * HorizontalLayout arranges its contents in a single line (using `display: inline-block` for its * items), with small margins between them. */ class HorizontalLayout extends Layout { use GroupElement; /** * @param array $config Configuration options * - Widget[]|Layout[] $config['items'] Widgets or other layouts to add to the layout. */ public function __construct( array $config = [] ) { // Parent constructor parent::__construct( $config ); // Traits $this->initializeGroupElement( array_merge( [ 'group' => $this ], $config ) ); // Initialization $this->addClasses( [ 'oo-ui-horizontalLayout' ] ); if ( isset( $config['items'] ) ) { $this->addItems( $config['items'] ); } } } PK ! ��Ӥ � layouts/StackLayout.phpnu �Iw�� <?php namespace OOUI; /** * StackLayouts contain a series of PanelLayouts */ class StackLayout extends PanelLayout { use GroupElement; /** @var bool */ protected $continuous; /** @var PanelLayout|null */ protected $currentItem; /** * @param array $config Configuration options * - bool $config['continuous'] Show all panels, one after another (default: false) * - PanelLayout[] $config['items'] Panel layouts to add to the stack layout. */ public function __construct( array $config = [] ) { $config = array_merge( [ 'preserveContent' => false, 'scrollable' => $config['continuous'] ?? false ], $config ); // Parent constructor parent::__construct( $config ); // Properties $this->continuous = $config['continuous'] ?? false; // Traits $this->initializeGroupElement( array_merge( $config, [ 'group' => $this ] ) ); // Initialization $this->addClasses( [ 'oo-ui-stackLayout' ] ); if ( $this->continuous ) { $this->addClasses( [ 'oo-ui-stackLayout-continuous' ] ); } $this->addItems( $config['items'] ?? [] ); } /** * @param PanelLayout|null $item */ public function setItem( $item ) { if ( $item !== $this->currentItem ) { $items = $this->getItems(); $this->updateHiddenState( $items, $item ); $this->currentItem = $item; } } /** * @param Element[] $items * @param PanelLayout|null $selectedItem */ private function updateHiddenState( $items, $selectedItem ) { if ( !$this->continuous ) { foreach ( $items as $item ) { if ( !$selectedItem || $selectedItem !== $item ) { $item->toggle( false ); $item->setAttributes( [ 'aria-hidden' => 'true' ] ); } } if ( $selectedItem ) { $selectedItem->toggle( true ); $selectedItem->removeAttributes( [ 'aria-hidden' ] ); } } } /** @inheritDoc */ public function getConfig( &$config ) { $config = parent::getConfig( $config ); if ( $this->continuous ) { $config['continuous'] = $this->continuous; // scrollable default has changed to true if ( !$this->hasClass( 'oo-ui-panelLayout-scrollable' ) ) { $config['scrollable'] = false; } else { unset( $config['scrollable'] ); } } return $config; } } PK ! �N� � layouts/PanelLayout.phpnu �Iw�� <?php namespace OOUI; /** * Layout that expands to cover the entire area of its parent, with optional scrolling and padding. */ class PanelLayout extends Layout { /** @var bool */ protected $preserveContent; /** * @param array $config Configuration options * - bool $config['scrollable'] Allow vertical scrolling (default: false) * - bool $config['padded'] Pad the content from the edges (default: false) * - bool $config['expanded'] Expand size to fill the entire parent element * (default: true) * - bool $config['framed'] Wrap in a frame to visually separate from outside content * (default: false) * - bool $config['preserveContent'] Preserve DOM content when infusing (default: true) */ public function __construct( array $config = [] ) { $this->preserveContent = $config['preserveContent'] ?? true; // Parent constructor parent::__construct( $config ); // Initialization $this->addClasses( [ 'oo-ui-panelLayout' ] ); if ( $config['scrollable'] ?? false ) { $this->addClasses( [ 'oo-ui-panelLayout-scrollable' ] ); } if ( $config['padded'] ?? false ) { $this->addClasses( [ 'oo-ui-panelLayout-padded' ] ); } if ( $config['expanded'] ?? true ) { $this->addClasses( [ 'oo-ui-panelLayout-expanded' ] ); } if ( $config['framed'] ?? false ) { $this->addClasses( [ 'oo-ui-panelLayout-framed' ] ); } } /** @inheritDoc */ public function getConfig( &$config ) { if ( !$this->preserveContent ) { $config['preserveContent'] = false; } if ( $this->hasClass( 'oo-ui-panelLayout-scrollable' ) ) { $config['scrollable'] = true; } if ( $this->hasClass( 'oo-ui-panelLayout-padded' ) ) { $config['padded'] = true; } if ( !$this->hasClass( 'oo-ui-panelLayout-expanded' ) ) { $config['expanded'] = false; } if ( $this->hasClass( 'oo-ui-panelLayout-framed' ) ) { $config['framed'] = true; } return parent::getConfig( $config ); } } PK ! ��/� layouts/FormLayout.phpnu �Iw�� <?php namespace OOUI; /** * Layout with an HTML form. */ class FormLayout extends Layout { use GroupElement; /* Static Properties */ /** @var string */ public static $tagName = 'form'; /** * @param array $config Configuration options * - string $config['method'] HTML form `method` attribute * - string $config['action'] HTML form `action` attribute * - string $config['enctype'] HTML form `enctype` attribute * - FieldsetLayout[] $config['items'] Items to add */ public function __construct( array $config = [] ) { // Parent constructor parent::__construct( $config ); // Traits $this->initializeGroupElement( array_merge( [ 'group' => $this ], $config ) ); // Initialization $attributeAllowList = [ 'method', 'action', 'enctype' ]; $this ->addClasses( [ 'oo-ui-formLayout' ] ) ->setAttributes( array_intersect_key( $config, array_flip( $attributeAllowList ) ) ); if ( isset( $config['items'] ) ) { $this->addItems( $config['items'] ); } } /** @inheritDoc */ public function getConfig( &$config ) { foreach ( [ 'method', 'action', 'enctype' ] as $attr ) { $value = $this->getAttribute( $attr ); if ( $value !== null ) { $config[$attr] = $value; } } return parent::getConfig( $config ); } } PK ! ��D D layouts/TabPanelLayout.phpnu �Iw�� <?php namespace OOUI; /** * TabPanelLayouts are used within IndexLayouts to create tab panels that * users can select and display from the index's optional TabSelectWidget * navigation. TabPanels are usually not instantiated directly, rather extended to include the * required content and functionality. * * Each tab panel must have a unique symbolic name, which is passed to the constructor. */ class TabPanelLayout extends PanelLayout { /** * @var string */ protected $name; /** * @var string|HtmlSnippet|null */ protected $label; /** * @var bool */ protected $active; /** * @var array Config for a {@see TabOptionWidget} */ protected $tabItemConfig; /** * @param string $name Unique symbolic name of tab panel * @param array $config Configuration options * - string|HtmlSnippet $config['label'] Label for tab panel's tab * - array $config['tabItemConfig'] Additional config for the {@see TabOptionWidget} that * represents this panel in an {@see IndexLayout} */ public function __construct( $name, array $config = [] ) { // Allow passing positional parameters inside the config array if ( is_array( $name ) && isset( $name['name'] ) ) { $config = $name; $name = $config['name']; } $config = array_merge( [ 'scrollable' => true ], $config ); // Parent constructor parent::__construct( $config ); // Initialization $this->name = $name; $this->label = $config['label'] ?? null; $this->tabItemConfig = $config['tabItemConfig'] ?? []; $this->addClasses( [ 'oo-ui-tabPanelLayout' ] ); $this->setAttributes( [ 'role' => 'tabpanel', ] ); } /** @inheritDoc */ public function getConfig( &$config ) { $config['name'] = $this->name; $config['label'] = $this->label; if ( $this->tabItemConfig ) { $config['tabItemConfig'] = $this->tabItemConfig; } // scrollable default has changed to true if ( !$this->hasClass( 'oo-ui-panelLayout-scrollable' ) ) { $config['scrollable'] = false; } else { unset( $config['scrollable'] ); } return parent::getConfig( $config ); } /** * @return string */ public function getName() { return $this->name; } /** * @return array */ public function getTabItemConfig() { return $this->tabItemConfig; } /** * @return string|HtmlSnippet|null */ public function getLabel() { return $this->label; } /** * @param bool $active */ public function setActive( $active ) { $this->active = $active; $this->removeClasses( [ 'oo-ui-tabPanelLayout-active' ] ); if ( $active ) { $this->addClasses( [ 'oo-ui-tabPanelLayout-active' ] ); } } } PK ! �2� layouts/FieldsetLayout.phpnu �Iw�� <?php namespace OOUI; /** * Layout made of a fieldset and optional legend. * * Just add FieldLayout items. */ class FieldsetLayout extends Layout { use IconElement; use LabelElement; use GroupElement; /* Static Properties */ /** @var string */ public static $tagName = 'fieldset'; /** @var Tag */ protected $header; /** @var string */ protected $helpText; /** @var string|false */ protected $helpInline; /** * @param array $config Configuration options * - FieldLayout[] $config['items'] Items to add * - string|HtmlSnippet $config['help'] Explanatory text shown as a '?' icon, or inline. * - bool $config['helpInline'] Whether or not the help should be inline, * or shown when the "help" icon is clicked. (default: false) */ public function __construct( array $config = [] ) { // Parent constructor parent::__construct( $config ); // Traits $this->initializeIconElement( $config ); $this->initializeLabelElement( $config ); $this->initializeGroupElement( $config ); // Properties $this->header = new Tag( 'legend' ); $this->helpText = $config['help'] ?? ''; $this->helpInline = $config['helpInline'] ?? false; // Initialization $this->header ->addClasses( [ 'oo-ui-fieldsetLayout-header' ] ) ->appendContent( $this->icon, $this->label ); $this->group->addClasses( [ 'oo-ui-fieldsetLayout-group' ] ); $this ->addClasses( [ 'oo-ui-fieldsetLayout' ] ) ->prependContent( $this->header, $this->group ); if ( $this->helpText ) { if ( $this->helpInline ) { $helpWidget = new LabelWidget( [ 'classes' => [ 'oo-ui-inline-help' ], 'label' => $this->helpText, ] ); $this->prependContent( $this->header, $helpWidget, $this->group ); } else { $helpWidget = new ButtonWidget( [ 'classes' => [ 'oo-ui-fieldsetLayout-help' ], 'framed' => false, 'icon' => 'info', 'title' => $this->helpText, // TODO We have no way to use localisation messages in PHP // (and to use different languages when used from MediaWiki) // 'label' => msg( 'ooui-field-help' ), // 'invisibleLabel' => true, ] ); $this->header->appendContent( $helpWidget ); } } if ( isset( $config['items'] ) ) { $this->addItems( $config['items'] ); } } /** @inheritDoc */ public function getConfig( &$config ) { $config['$overlay'] = true; if ( $this->helpText !== '' ) { $config['help'] = $this->helpText; } if ( $this->helpInline ) { $config['helpInline'] = $this->helpInline; } return parent::getConfig( $config ); } } PK ! ���W W layouts/MenuLayout.phpnu �Iw�� <?php namespace OOUI; /** * MenuLayouts combine a menu and a content PanelLayout panel. * * The menu is positioned relative to the content (after, before, top, or bottom) */ class MenuLayout extends Layout { /** * @var Tag */ protected $menuWrapper; /** * @var Tag */ protected $contentWrapper; /** * @var ?PanelLayout */ protected $menuPanel; /** * @var ?PanelLayout */ protected $contentPanel; /** * @var string */ protected $menuPosition; /** * @var bool */ protected $expanded; /** * @param array $config Configuration options * - PanelLayout $config['menuPanel'] Menu panel * - PanelLayout $config['contentPanel'] Content panel * - bool $config['expanded'] Expand content to fill the parent element (default: true) * - bool $config['showMenu'] Show menu (default: true) * - string $config['menuPosition'] top, after, bottom, before (default: before) * @phpcs:ignore Generic.Files.LineLength * @phan-param array{menuPanel:PanelLayout,contentPanel:PanelLayout,expanded?:bool,showMenu?:bool,menuPosition?:string} $config */ public function __construct( array $config = [] ) { parent::__construct( $config ); $this->menuPanel = null; $this->contentPanel = null; $this->expanded = $config['expanded'] ?? true; $this->menuWrapper = new Tag( 'div' ); $this->contentWrapper = new Tag( 'div' ); $this->menuWrapper->addClasses( [ 'oo-ui-menuLayout-menu' ] ); $this->contentWrapper->addClasses( [ 'oo-ui-menuLayout-content' ] ); $this->addClasses( [ 'oo-ui-menuLayout', $this->expanded ? 'oo-ui-menuLayout-expanded' : 'oo-ui-menuLayout-static', ] ); if ( !empty( $config['menuPanel'] ) ) { $this->setMenuPanel( $config['menuPanel'] ); } if ( !empty( $config['contentPanel'] ) ) { $this->setContentPanel( $config['contentPanel'] ); } $this->setMenuPosition( $config['menuPosition'] ?? 'before' ); $this->toggleMenu( (bool)( $config['showMenu'] ?? true ) ); } /** @inheritDoc */ public function getConfig( &$config ) { $config = parent::getConfig( $config ); if ( $this->menuPosition !== 'before' ) { $config['menuPosition'] = $this->menuPosition; } if ( !$this->expanded ) { $config['expanded'] = $this->expanded; } $showMenu = $this->hasClass( 'oo-ui-menuLayout-showMenu' ); if ( !$showMenu ) { $config['showMenu'] = $showMenu; } if ( $this->menuPanel ) { $config['menuPanel'] = $this->menuPanel; } if ( $this->contentPanel ) { $config['contentPanel'] = $this->contentPanel; } return $config; } /** * @param bool $showMenu */ public function toggleMenu( $showMenu ) { $this->toggleClasses( [ 'oo-ui-menuLayout-showMenu' ], $showMenu ); $this->toggleClasses( [ 'oo-ui-menuLayout-hideMenu' ], !$showMenu ); $this->menuWrapper->setAttributes( [ 'aria-hidden' => $showMenu ? 'false' : 'true' ] ); } /** * @param string $position */ public function setMenuPosition( $position ) { if ( !in_array( $position, [ 'top', 'bottom', 'before', 'after' ], true ) ) { $position = 'before'; } $this->removeClasses( [ 'oo-ui-menuLayout-' . $this->menuPosition ] ); $this->menuPosition = $position; $this->clearContent(); if ( $this->menuPosition == 'top' || $this->menuPosition == 'before' ) { $this->appendContent( $this->menuWrapper, $this->contentWrapper ); } else { $this->appendContent( $this->contentWrapper, $this->menuWrapper ); } $this->addClasses( [ 'oo-ui-menuLayout-' . $position ] ); } /** * @param PanelLayout $menuPanel */ public function setMenuPanel( PanelLayout $menuPanel ) { $this->menuPanel = $menuPanel; $this->menuWrapper->appendContent( $this->menuPanel ); } /** * @param PanelLayout $contentPanel */ public function setContentPanel( PanelLayout $contentPanel ) { $this->contentPanel = $contentPanel; $this->contentWrapper->appendContent( $this->contentPanel ); } } PK ! 8�O O widgets/ButtonWidget.phpnu �Iw�� <?php namespace OOUI; /** * Generic widget for buttons. */ class ButtonWidget extends Widget { use ButtonElement; use IconElement; use IndicatorElement; use LabelElement; use TitledElement; use FlaggedElement; use TabIndexedElement; use AccessKeyedElement; /* Static Properties */ /** @var string */ public static $tagName = 'span'; /* Properties */ /** * Whether button is active. * * @var bool */ protected $active = false; /** * Hyperlink to visit when clicked. * * @var string */ protected $href = null; /** * Target to open hyperlink in. * * @var string */ protected $target = null; /** * Search engine traversal hint. * * True if search engines should avoid following this hyperlink. * * @var bool */ protected $noFollow = true; /** * Relationship attributes, such as the noFollow field above, or noopener for the hyperlink. * * @var string[] */ protected $rel = []; /** * @param array $config Configuration options * - bool $config['active'] Whether button should be shown as active (default: false) * - string $config['href'] Hyperlink to visit when clicked * - string $config['target'] Target to open hyperlink in * - bool $config['noFollow'] Search engine traversal hint (default: true) * - string|string[] $config['rel'] Relationship attributes for the hyperlink */ public function __construct( array $config = [] ) { // Parent constructor parent::__construct( $config ); // Traits $this->initializeButtonElement( $config ); $this->initializeIconElement( $config ); $this->initializeIndicatorElement( $config ); $this->initializeLabelElement( $config ); $this->initializeTitledElement( array_merge( [ 'titled' => $this->button ], $config ) ); $this->initializeFlaggedElement( $config ); $this->initializeTabIndexedElement( array_merge( [ 'tabIndexed' => $this->button ], $config ) ); $this->initializeAccessKeyedElement( array_merge( [ 'accessKeyed' => $this->button ], $config ) ); // Initialization $this->button->appendContent( $this->icon, $this->label, $this->indicator ); $this ->addClasses( [ 'oo-ui-buttonWidget' ] ) ->appendContent( $this->button ); $this->setActive( $config['active'] ?? false ); $this->setHref( $config['href'] ?? null ); $this->setTarget( $config['target'] ?? null ); $rel = [ 'nofollow' ]; if ( isset( $config['rel'] ) ) { $rel = $config['rel']; } elseif ( isset( $config[ 'noFollow' ] ) && $config[ 'noFollow' ] === false ) { $rel = []; } $this->setRel( $rel ); } /** * Get hyperlink location. * * @return string Hyperlink location */ public function getHref() { return $this->href; } /** * Get hyperlink target. * * @return string Hyperlink target */ public function getTarget() { return $this->target; } /** * Get search engine traversal hint. * * @return bool Whether search engines should avoid traversing this hyperlink */ public function getNoFollow() { return $this->noFollow; } /** * Get the relationship attribute of the hyperlink. * * @return string[] Relationship attributes that apply to the hyperlink */ public function getRel() { return $this->rel; } /** * Set hyperlink location. * * @param string|null $href Hyperlink location, null to remove * @return $this */ public function setHref( $href ) { $this->href = is_string( $href ) ? $href : null; $this->updateHref(); return $this; } /** * Update the href attribute, in case of changes to href or disabled * state. * * @return $this */ public function updateHref() { if ( $this->href !== null && !$this->isDisabled() ) { $this->button->setAttributes( [ 'href' => $this->href ] ); } else { $this->button->removeAttributes( [ 'href' ] ); } return $this; } /** * Set hyperlink target. * * @param string|null $target Hyperlink target, null to remove * @return $this */ public function setTarget( $target ) { $this->target = is_string( $target ) ? $target : null; if ( $this->target !== null ) { $this->button->setAttributes( [ 'target' => $target ] ); } else { $this->button->removeAttributes( [ 'target' ] ); } return $this; } /** * Set search engine traversal hint. * * @param bool $noFollow True if search engines should avoid traversing this hyperlink * @return $this */ public function setNoFollow( $noFollow ) { if ( $noFollow !== $this->noFollow ) { if ( $noFollow ) { $rel = array_merge( $this->rel, [ 'nofollow' ] ); } else { $rel = array_diff( $this->rel, [ 'nofollow' ] ); } $this->setRel( $rel ); } return $this; } /** * Set the relationship attribute of the hyperlink. * * @param string|string[] $rel Relationship attributes for the hyperlink * @return $this */ public function setRel( $rel ) { $this->rel = $rel === '' ? [] : (array)$rel; // For backwards compatibility $this->noFollow = in_array( 'nofollow', $this->rel ); $value = implode( ' ', $this->rel ); if ( $value !== '' ) { $this->button->setAttributes( [ 'rel' => $value ] ); } else { $this->button->removeAttributes( [ 'rel' ] ); } return $this; } /** * Toggle active state. * * A button should be marked as active when clicking it would only refresh the page. * * @param bool|null $active Make button active * @return $this */ public function setActive( $active = null ) { $this->active = (bool)$active; $this->toggleClasses( [ 'oo-ui-buttonElement-active' ], $this->active ); return $this; } /** * Check if button is active. * * @return bool Button is active */ public function isActive() { return $this->active; } /** @inheritDoc */ public function getConfig( &$config ) { if ( $this->active !== false ) { $config['active'] = $this->active; } if ( $this->href !== null ) { $config['href'] = $this->href; } if ( $this->target !== null ) { $config['target'] = $this->target; } if ( $this->noFollow !== true ) { $config['noFollow'] = $this->noFollow; } if ( $this->rel !== [] ) { $config['rel'] = $this->rel; } return parent::getConfig( $config ); } } PK ! �E�@� � widgets/SearchInputWidget.phpnu �Iw�� <?php namespace OOUI; /** * Input widget with a text field. */ class SearchInputWidget extends TextInputWidget { /** * @param array $config */ public function __construct( array $config = [] ) { // Config initialization $config = array_merge( [ 'icon' => 'search', ], $config ); // Parent constructor parent::__construct( $config ); } /** @inheritDoc */ protected function getValidType( $config ) { return 'search'; } } PK ! ���i i widgets/SelectWidget.phpnu �Iw�� <?php namespace OOUI; /** * A SelectWidget is of a generic selection of options. * * Should be used in conjunction with OptionWidget * * @method OptionWidget[] getItems() */ class SelectWidget extends Widget { use GroupWidget; /** * @var bool */ protected $multiselect; /** * @param array $config Configuration options * - OptionWidget[] $config['items'] OptionWidget objects to add to the select * - bool $config['multiselect'] Allow for multiple selections */ public function __construct( array $config = [] ) { $config = array_merge( [ 'items' => [] ], $config ); $this->initializeGroupElement( array_merge( $config, [ 'group' => $this ] ) ); $this->multiselect = $config['multiselect'] ?? false; $this->addClasses( [ 'oo-ui-selectWidget', 'oo-ui-selectWidget-unpressed', ] ); $this->setAttributes( [ 'role' => 'listbox', 'aria-multiselectable' => $this->multiselect ? 'true' : 'false', ] ); $this->addItems( $config['items'] ); parent::__construct( $config ); } /** * @return OptionWidget[]|OptionWidget|null */ public function findSelectedItems() { /** @var OptionWidget[] $selected */ $selected = array_filter( $this->getItems(), static function ( $item ) { return $item->isSelected(); } ); return $this->multiselect ? $selected : ( count( $selected ) ? $selected[ 0 ] : null ); } /** * @return OptionWidget[]|OptionWidget|null */ public function findSelectedItem() { return $this->findSelectedItems(); } /** * Programmatically select an option by its data. If the `data` parameter is omitted, * or if the item does not exist, all options will be deselected. * * @param mixed $data Value of the item to select, omit to deselect all * @return $this */ public function selectItemByData( $data = null ) { $itemFromData = $this->findItemFromData( $data ); '@phan-var OptionWidget|null $itemFromData'; if ( $data === null || $itemFromData === null ) { return $this->selectItem(); } return $this->selectItem( $itemFromData ); } /** * Unselect an option by its reference. * * @param OptionWidget $item Item to unselect, omit to deselect all * @return $this */ public function unselectItem( $item ) { if ( $item ) { $item->setSelected( false ); } else { foreach ( $this->getItems() as $i ) { if ( $i->isSelected() ) { $i->setSelected( false ); } } } return $this; } /** * Select an option by its reference. * * @param OptionWidget|null $item Item to select, omit to deselect all * @return $this */ public function selectItem( $item = null ) { if ( $this->multiselect && $item ) { $item->setSelected( true ); } else { foreach ( $this->getItems() as $i ) { $selected = $item === $i; if ( $i->isSelected() !== $selected ) { $i->setSelected( $selected ); } } } return $this; } } PK ! ~�*Ž � widgets/RadioInputWidget.phpnu �Iw�� <?php namespace OOUI; /** * Radio input widget. */ class RadioInputWidget extends InputWidget { use RequiredElement; /* Static Properties */ /** @var string */ public static $tagName = 'span'; /** * @param array $config Configuration options * - bool $config['selected'] Whether the radio button is initially selected * (default: false) */ public function __construct( array $config = [] ) { // Parent constructor parent::__construct( $config ); // Traits $this->initializeRequiredElement( array_merge( [ 'indicatorElement' => null ], $config ) ); // Initialization $this->addClasses( [ 'oo-ui-radioInputWidget' ] ); // Required for pretty styling in WikimediaUI theme $this->appendContent( new Tag( 'span' ) ); $this->setSelected( $config['selected'] ?? false ); } /** @inheritDoc */ protected function getInputElement( $config ) { return ( new Tag( 'input' ) )->setAttributes( [ 'type' => 'radio' ] ); } /** * Set selection state of this radio button. * * @param bool $state Whether the button is selected * @return $this */ public function setSelected( $state ) { // RadioInputWidget doesn't track its state. if ( $state ) { $this->input->setAttributes( [ 'checked' => 'checked' ] ); } else { $this->input->removeAttributes( [ 'checked' ] ); } return $this; } /** * Check if this radio button is selected. * * @return bool Radio is selected */ public function isSelected() { return $this->input->getAttribute( 'checked' ) === 'checked'; } /** @inheritDoc */ public function getConfig( &$config ) { if ( $this->isSelected() ) { $config['selected'] = true; } return parent::getConfig( $config ); } } PK ! ��Y5 5 widgets/LabelWidget.phpnu �Iw�� <?php namespace OOUI; /** * Label widget. */ class LabelWidget extends Widget { use LabelElement; /* Static Properties */ /** @var string */ public static $tagName = 'label'; /* Properties */ /** * Associated input element. * * @var InputWidget|null */ protected $input; /** * @param array $config Configuration options * - InputWidget $config['input'] Input widget this label is for */ public function __construct( array $config = [] ) { // Parent constructor parent::__construct( $config ); // Traits $this->initializeLabelElement( array_merge( [ 'labelElement' => $this ], $config ) ); // Properties $this->input = $config['input'] ?? null; // Initialization if ( $this->input && $this->input->getInputId() ) { $this->setAttributes( [ 'for' => $this->input->getInputId() ] ); } $this->addClasses( [ 'oo-ui-labelWidget' ] ); } /** @inheritDoc */ public function getConfig( &$config ) { if ( $this->input !== null ) { $config['input'] = $this->input; } return parent::getConfig( $config ); } } PK ! �-��� � widgets/HiddenInputWidget.phpnu �Iw�� <?php namespace OOUI; /** * Data widget intended for creating 'hidden'-type inputs. */ class HiddenInputWidget extends Widget { /** * @var string */ public static $tagName = 'input'; /** * DataWidget constructor. * * @param array $config Configuration options * - string $config['value'] The data the input contains. (default: '') * - string $config['name'] The name of the hidden input. (default: '') */ public function __construct( array $config ) { // Parent constructor parent::__construct( $config ); // Initialization $this->setAttributes( [ 'type' => 'hidden', 'value' => $config['value'] ?? '', 'name' => $config['name'] ?? '', ] ); $this->removeAttributes( [ 'aria-disabled' ] ); } /** @inheritDoc */ public function getConfig( &$config ) { $config['value'] = $this->getAttribute( 'value' ); $config['name'] = $this->getAttribute( 'name' ); return parent::getConfig( $config ); } } PK ! �3�(� � "