]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - vendor/oojs/oojs-ui/php/Element.php
MediaWiki 1.30.2-scripts
[autoinstallsdev/mediawiki.git] / vendor / oojs / oojs-ui / php / Element.php
1 <?php
2
3 namespace OOUI;
4
5 /**
6  * DOM element abstraction.
7  *
8  * @abstract
9  */
10 class Element extends Tag {
11
12         /* Static Properties */
13
14         /**
15          * HTML tag name.
16          *
17          * This may be ignored if getTagName() is overridden.
18          *
19          * @var string
20          */
21         public static $tagName = 'div';
22
23         /**
24          * Default text direction, used for some layout calculations. Use setDefaultDir() to change.
25          *
26          * Currently only per-document directionality is supported.
27          *
28          * @var string
29          */
30         public static $defaultDir = 'ltr';
31
32         /* Properties */
33
34         /**
35          * Element data.
36          *
37          * @var mixed
38          */
39         protected $data = null;
40
41         /**
42          * Strings of the CSS classes explicitly configured for this element (as opposed to #$classes,
43          * which contains all classes for this element).
44          *
45          * @var array
46          */
47         protected $ownClasses = [];
48
49         /**
50          * @var callable[]
51          */
52         protected $configCallbacks = [];
53
54         /* Methods */
55
56         /**
57          * @param array $config Configuration options
58          * @param string[] $config['classes'] CSS class names to add
59          * @param string $config['id'] HTML id attribute
60          * @param string $config['text'] Text to insert
61          * @param array $config['content'] Content to append (after text), strings
62          *   or Element objects. Strings will be HTML-escaped for output, use an
63          *   HtmlSnippet instance to prevent that.
64          * @param mixed $config['data'] Element data
65          */
66         public function __construct( array $config = [] ) {
67                 // Parent constructor
68                 parent::__construct( $this->getTagName() );
69
70                 // Initialization
71                 if ( isset( $config['infusable'] ) && is_bool( $config['infusable'] ) ) {
72                         $this->setInfusable( $config['infusable'] );
73                 }
74                 if ( isset( $config['data'] ) ) {
75                         $this->setData( $config['data'] );
76                 }
77                 if ( isset( $config['classes'] ) && is_array( $config['classes'] ) ) {
78                         $this->ownClasses = $config['classes'];
79                         $this->addClasses( $this->ownClasses );
80                 }
81                 if ( isset( $config['id'] ) ) {
82                         $this->setAttributes( [ 'id' => $config['id'] ] );
83                 }
84                 if ( isset( $config['text'] ) ) {
85                         // JS compatibility
86                         $this->appendContent( $config['text'] );
87                 }
88                 if ( isset( $config['content'] ) ) {
89                         $this->appendContent( $config['content'] );
90                 }
91         }
92
93         /**
94          * Get the HTML tag name.
95          *
96          * Override this method to base the result on instance information.
97          *
98          * @return string HTML tag name
99          */
100         public function getTagName() {
101                 return $this::$tagName;
102         }
103
104         /**
105          * Get element data.
106          *
107          * @return mixed Element data
108          */
109         public function getData() {
110                 return $this->data;
111         }
112
113         /**
114          * Set element data.
115          *
116          * @param mixed $data Element data
117          * @return $this
118          */
119         public function setData( $data ) {
120                 $this->data = $data;
121                 return $this;
122         }
123
124         /**
125          * Check if element supports one or more methods.
126          *
127          * @param string|string[] $methods Method or list of methods to check
128          * @return bool All methods are supported
129          */
130         public function supports( $methods ) {
131                 $support = 0;
132                 $methods = (array)$methods;
133
134                 foreach ( $methods as $method ) {
135                         if ( method_exists( $this, $method ) ) {
136                                 $support++;
137                                 continue;
138                         }
139                 }
140
141                 return count( $methods ) === $support;
142         }
143
144         /**
145          * Register an additional function to call when building the config. See ::getConfig().
146          *
147          * @param callable $func The function. Parameters and return value are the same as ::getConfig().
148          */
149         public function registerConfigCallback( callable $func ) {
150                 $this->configCallbacks[] = $func;
151         }
152
153         /**
154          * Add the necessary properties to the given `$config` array to allow
155          * reconstruction of this widget via its constructor.
156          * @param array &$config An array which will be mutated to add the necessary configuration
157          *   properties.  Unless you are implementing a subclass, you should
158          *   always pass a new empty array `[]`.
159          * @return array A configuration array which can be passed to this object's
160          *   constructor to recreate it.  This is a return value to allow
161          *   the safe use of copy-by-value functions like `array_merge` in
162          *   the implementation.
163          */
164         public function getConfig( &$config ) {
165                 // If there are traits, add their config
166                 foreach ( $this->configCallbacks as $func ) {
167                         call_user_func_array( $func, [ &$config ] );
168                 }
169
170                 if ( $this->data !== null ) {
171                         $config['data'] = $this->data;
172                 }
173                 if ( $this->ownClasses !== [] ) {
174                         $config['classes'] = $this->ownClasses;
175                 }
176                 return $config;
177         }
178
179         /**
180          * Create a modified version of the configuration array suitable for
181          * JSON serialization by replacing `Tag` references and
182          * `HtmlSnippet`s.
183          *
184          * @return array A serialized configuration array.
185          */
186         private function getSerializedConfig() {
187                 // Ensure that '_' comes first in the output.
188                 $config = [ '_' => true ];
189                 $config = $this->getConfig( $config );
190                 // Post-process config array to turn Tag references into ID references
191                 // and HtmlSnippet references into a { html: 'string' } JSON form.
192                 $replaceElements = function ( &$item ) {
193                         if ( $item instanceof Tag ) {
194                                 $item->ensureInfusableId();
195                                 $item = [ 'tag' => $item->getAttribute( 'id' ) ];
196                         } elseif ( $item instanceof HtmlSnippet ) {
197                                 $item = [ 'html' => (string)$item ];
198                         }
199                 };
200                 array_walk_recursive( $config, $replaceElements );
201                 // Set '_' last to ensure that subclasses can't accidentally step on it.
202                 $config['_'] = $this->getJavaScriptClassName();
203                 return $config;
204         }
205
206         /**
207          * The class name of the JavaScript version of this widget
208          * @return string
209          */
210         protected function getJavaScriptClassName() {
211                 return str_replace( 'OOUI\\', 'OO.ui.', get_class( $this ) );
212         }
213
214         protected function getGeneratedAttributes() {
215                 $attributesArray = parent::getGeneratedAttributes();
216                 // Add `data-ooui` attribute from serialized config array.
217                 if ( $this->infusable ) {
218                         $serialized = $this->getSerializedConfig();
219                         $attributesArray['data-ooui'] = json_encode( $serialized );
220                 }
221                 return $attributesArray;
222         }
223
224         /**
225          * Render element into HTML.
226          *
227          * @return string HTML serialization
228          */
229         public function toString() {
230                 Theme::singleton()->updateElementClasses( $this );
231                 if ( $this->isInfusable() ) {
232                         $this->ensureInfusableId();
233                 }
234                 return parent::toString();
235         }
236
237         /**
238          * Get the direction of the user interface for a given element.
239          *
240          * Currently only per-document directionality is supported.
241          *
242          * @param Tag $element Element to check
243          * @return string Text direction, either 'ltr' or 'rtl'
244          */
245         public static function getDir( Tag $element ) {
246                 return self::$defaultDir;
247         }
248
249         /**
250          * Set the default direction of the user interface.
251          *
252          * @param string $dir Text direction, either 'ltr' or 'rtl'
253          */
254         public static function setDefaultDir( $dir ) {
255                 self::$defaultDir = $dir === 'rtl' ? 'rtl' : 'ltr';
256         }
257
258         /**
259          * A helper method to massage an array of HTML attributes into a format that is more likely to
260          * work with an OOjs UI PHP element, camel-casing attribute names and setting values of boolean
261          * ones to true. Intended as a convenience to be used when refactoring legacy systems using HTML
262          * to use OOjs UI.
263          *
264          * @param array $attrs HTML attributes, e.g. `[ 'disabled' => '', 'accesskey' => 'k' ]`
265          * @return array OOjs UI PHP element config, e.g. `[ 'disabled' => true, 'accessKey' => 'k' ]`
266          */
267         public static function configFromHtmlAttributes( array $attrs ) {
268                 $booleanAttrs = [
269                         'disabled' => true,
270                         'required' => true,
271                         'autofocus' => true,
272                         'multiple' => true,
273                         'readonly' => true,
274                 ];
275                 $attributeToConfig = [
276                         'maxlength' => 'maxLength',
277                         'readonly' => 'readOnly',
278                         'tabindex' => 'tabIndex',
279                         'accesskey' => 'accessKey',
280                 ];
281                 $config = [];
282                 foreach ( $attrs as $key => $value ) {
283                         if ( isset( $booleanAttrs[$key] ) && $value !== false && $value !== null ) {
284                                 $value = true;
285                         }
286                         if ( isset( $attributeToConfig[$key] ) ) {
287                                 $key = $attributeToConfig[$key];
288                         }
289                         $config[$key] = $value;
290                 }
291                 return $config;
292         }
293 }