MediaWiki  1.34.0
VectorTemplate.php
Go to the documentation of this file.
1 <?php
30 
34  public function execute() {
35  $this->data['namespace_urls'] = $this->data['content_navigation']['namespaces'];
36  $this->data['view_urls'] = $this->data['content_navigation']['views'];
37  $this->data['action_urls'] = $this->data['content_navigation']['actions'];
38  $this->data['variant_urls'] = $this->data['content_navigation']['variants'];
39 
40  // Move the watch/unwatch star outside of the collapsed "actions" menu to the main "views" menu
41  if ( $this->config->get( 'VectorUseIconWatch' ) ) {
42  $mode = $this->getSkin()->getUser()->isWatched( $this->getSkin()->getRelevantTitle() )
43  ? 'unwatch'
44  : 'watch';
45 
46  if ( isset( $this->data['action_urls'][$mode] ) ) {
47  $this->data['view_urls'][$mode] = $this->data['action_urls'][$mode];
48  unset( $this->data['action_urls'][$mode] );
49  }
50  }
51 
52  // Naming conventions for Mustache parameters:
53  // - Prefix "is" for boolean values.
54  // - Prefix "msg-" for interface messages.
55  // - Prefix "page-" for data relating to the current page (e.g. Title, WikiPage, or OutputPage).
56  // - Prefix "html-" for raw HTML (in front of other keys, if applicable).
57  // - Conditional values are null if absent.
58  $params = [
59  'html-headelement' => $this->get( 'headelement', '' ),
60  'html-sitenotice' => $this->get( 'sitenotice', null ),
61  'html-indicators' => $this->getIndicators(),
62  'page-langcode' => $this->getSkin()->getTitle()->getPageViewLanguage()->getHtmlCode(),
63  'page-isarticle' => (bool)$this->data['isarticle'],
64 
65  // Remember that the string '0' is a valid title.
66  // From OutputPage::getPageTitle, via ::setPageTitle().
67  'html-title' => $this->get( 'title', '' ),
68 
69  'html-prebodyhtml' => $this->get( 'prebodyhtml', '' ),
70  'msg-tagline' => $this->getMsg( 'tagline' )->text(),
71  // TODO: mediawiki/SkinTemplate should expose langCode and langDir properly.
72  'html-userlangattributes' => $this->get( 'userlangattributes', '' ),
73  // From OutputPage::getSubtitle()
74  'html-subtitle' => $this->get( 'subtitle', '' ),
75 
76  // TODO: Use directly Skin::getUndeleteLink() directly.
77  // Always returns string, cast to null if empty.
78  'html-undelete' => $this->get( 'undelete', null ) ?: null,
79 
80  // From Skin::getNewtalks(). Always returns string, cast to null if empty.
81  'html-newtalk' => $this->get( 'newtalk', '' ) ?: null,
82 
83  'msg-jumptonavigation' => $this->getMsg( 'vector-jumptonavigation' )->text(),
84  'msg-jumptosearch' => $this->getMsg( 'vector-jumptosearch' )->text(),
85 
86  // Result of OutputPage::addHTML calls
87  'html-bodycontent' => $this->get( 'bodycontent' ),
88 
89  'html-printfooter' => $this->get( 'printfooter', null ),
90  'html-catlinks' => $this->get( 'catlinks', '' ),
91  'html-dataAfterContent' => $this->get( 'dataAfterContent', '' ),
92  // From MWDebug::getHTMLDebugLog (when $wgShowDebug is enabled)
93  'html-debuglog' => $this->get( 'debughtml', '' ),
94  // From BaseTemplate::getTrail (handles bottom JavaScript)
95  'html-printtail' => $this->getTrail(),
96  ];
97 
98  // TODO: Convert the rest to Mustache
99  ob_start();
100  ?>
101  <div id="mw-navigation">
102  <h2><?php $this->msg( 'navigation-heading' ) ?></h2>
103  <div id="mw-head">
104  <?php $this->renderNavigation( [ 'PERSONAL' ] ); ?>
105  <div id="left-navigation">
106  <?php $this->renderNavigation( [ 'NAMESPACES', 'VARIANTS' ] ); ?>
107  </div>
108  <div id="right-navigation">
109  <?php $this->renderNavigation( [ 'VIEWS', 'ACTIONS', 'SEARCH' ] ); ?>
110  </div>
111  </div>
112  <div id="mw-panel">
113  <div id="p-logo" role="banner"><a class="mw-wiki-logo" href="<?php
114  echo htmlspecialchars( $this->data['nav_urls']['mainpage']['href'] )
115  ?>"<?php
117  ?>></a></div>
118  <?php $this->renderPortals( $this->data['sidebar'] ); ?>
119  </div>
120  </div>
121  <?php Hooks::run( 'VectorBeforeFooter' ); ?>
122  <div id="footer" role="contentinfo"<?php $this->html( 'userlangattributes' ) ?>>
123  <?php
124  foreach ( $this->getFooterLinks() as $category => $links ) {
125  ?>
126  <ul id="footer-<?php echo $category ?>">
127  <?php
128  foreach ( $links as $link ) {
129  ?>
130  <li id="footer-<?php echo $category ?>-<?php echo $link ?>"><?php $this->html( $link ) ?></li>
131  <?php
132  }
133  ?>
134  </ul>
135  <?php
136  }
137  ?>
138  <?php $footericons = $this->getFooterIcons( 'icononly' );
139  if ( count( $footericons ) > 0 ) {
140  ?>
141  <ul id="footer-icons" class="noprint">
142  <?php
143  foreach ( $footericons as $blockName => $footerIcons ) {
144  ?>
145  <li id="footer-<?php echo htmlspecialchars( $blockName ); ?>ico">
146  <?php
147  foreach ( $footerIcons as $icon ) {
148  echo $this->getSkin()->makeFooterIcon( $icon );
149  }
150  ?>
151  </li>
152  <?php
153  }
154  ?>
155  </ul>
156  <?php
157  }
158  ?>
159  <div style="clear: both;"></div>
160  </div>
161  <?php
162  $params['html-unported'] = ob_get_contents();
163  ob_end_clean();
164 
165  // Prepare and output the HTML response
166  $templates = new TemplateParser( __DIR__ . '/templates' );
167  echo $templates->processTemplate( 'index', $params );
168  }
169 
175  protected function renderPortals( array $portals ) {
176  // Force the rendering of the following portals
177  if ( !isset( $portals['TOOLBOX'] ) ) {
178  $portals['TOOLBOX'] = true;
179  }
180  if ( !isset( $portals['LANGUAGES'] ) ) {
181  $portals['LANGUAGES'] = true;
182  }
183  // Render portals
184  foreach ( $portals as $name => $content ) {
185  if ( $content === false ) {
186  continue;
187  }
188 
189  // Numeric strings gets an integer when set as key, cast back - T73639
190  $name = (string)$name;
191 
192  switch ( $name ) {
193  case 'SEARCH':
194  break;
195  case 'TOOLBOX':
196  $this->renderPortal( 'tb', $this->getToolbox(), 'toolbox', 'SkinTemplateToolboxEnd' );
197  Hooks::run( 'VectorAfterToolbox' );
198  break;
199  case 'LANGUAGES':
200  if ( $this->data['language_urls'] !== false ) {
201  $this->renderPortal( 'lang', $this->data['language_urls'], 'otherlanguages' );
202  }
203  break;
204  default:
205  $this->renderPortal( $name, $content );
206  break;
207  }
208  }
209  }
210 
217  protected function renderPortal( $name, $content, $msg = null, $hook = null ) {
218  if ( $msg === null ) {
219  $msg = $name;
220  }
221  $msgObj = $this->getMsg( $msg );
222  $labelId = Sanitizer::escapeIdForAttribute( "p-$name-label" );
223  ?>
224  <div class="portal" role="navigation" id="<?php
225  echo htmlspecialchars( Sanitizer::escapeIdForAttribute( "p-$name" ) )
226  ?>"<?php
227  echo Linker::tooltip( 'p-' . $name )
228  ?> aria-labelledby="<?php echo htmlspecialchars( $labelId ) ?>">
229  <h3<?php $this->html( 'userlangattributes' ) ?> id="<?php echo htmlspecialchars( $labelId )
230  ?>"><?php
231  echo htmlspecialchars( $msgObj->exists() ? $msgObj->text() : $msg );
232  ?></h3>
233  <div class="body">
234  <?php
235  if ( is_array( $content ) ) {
236  ?>
237  <ul>
238  <?php
239  foreach ( $content as $key => $val ) {
240  echo $this->makeListItem( $key, $val );
241  }
242  if ( $hook !== null ) {
243  // Avoid PHP 7.1 warning
244  $skin = $this;
245  Hooks::run( $hook, [ &$skin, true ] );
246  }
247  ?>
248  </ul>
249  <?php
250  } else {
251  // Allow raw HTML block to be defined by extensions
252  echo $content;
253  }
254 
255  $this->renderAfterPortlet( $name );
256  ?>
257  </div>
258  </div>
259  <?php
260  }
261 
268  protected function renderNavigation( array $elements ) {
269  // Render elements
270  foreach ( $elements as $name => $element ) {
271  switch ( $element ) {
272  case 'NAMESPACES':
273  ?>
274  <div id="p-namespaces" role="navigation" class="vectorTabs<?php
275  if ( count( $this->data['namespace_urls'] ) == 0 ) {
276  echo ' emptyPortlet';
277  }
278  ?>" aria-labelledby="p-namespaces-label">
279  <h3 id="p-namespaces-label"><?php $this->msg( 'namespaces' ) ?></h3>
280  <ul<?php $this->html( 'userlangattributes' ) ?>>
281  <?php
282  foreach ( $this->data['namespace_urls'] as $key => $item ) {
283  echo $this->makeListItem( $key, $item, [
284  'vector-wrap' => true,
285  ] );
286  }
287  ?>
288  </ul>
289  </div>
290  <?php
291  break;
292  case 'VARIANTS':
293  ?>
294  <div id="p-variants" role="navigation" class="vectorMenu<?php
295  if ( count( $this->data['variant_urls'] ) == 0 ) {
296  echo ' emptyPortlet';
297  }
298  ?>" aria-labelledby="p-variants-label">
299  <?php
300  // Replace the label with the name of currently chosen variant, if any
301  $variantLabel = $this->getMsg( 'variants' )->text();
302  foreach ( $this->data['variant_urls'] as $item ) {
303  if ( isset( $item['class'] ) && stripos( $item['class'], 'selected' ) !== false ) {
304  $variantLabel = $item['text'];
305  break;
306  }
307  }
308  ?>
309  <input type="checkbox" class="vectorMenuCheckbox" aria-labelledby="p-variants-label" />
310  <h3 id="p-variants-label">
311  <span><?php echo htmlspecialchars( $variantLabel ) ?></span>
312  </h3>
313  <ul class="menu">
314  <?php
315  foreach ( $this->data['variant_urls'] as $key => $item ) {
316  echo $this->makeListItem( $key, $item );
317  }
318  ?>
319  </ul>
320  </div>
321  <?php
322  break;
323  case 'VIEWS':
324  ?>
325  <div id="p-views" role="navigation" class="vectorTabs<?php
326  if ( count( $this->data['view_urls'] ) == 0 ) {
327  echo ' emptyPortlet';
328  }
329  ?>" aria-labelledby="p-views-label">
330  <h3 id="p-views-label"><?php $this->msg( 'views' ) ?></h3>
331  <ul<?php $this->html( 'userlangattributes' ) ?>>
332  <?php
333  foreach ( $this->data['view_urls'] as $key => $item ) {
334  echo $this->makeListItem( $key, $item, [
335  'vector-wrap' => true,
336  'vector-collapsible' => true,
337  ] );
338  }
339  ?>
340  </ul>
341  </div>
342  <?php
343  break;
344  case 'ACTIONS':
345  ?>
346  <div id="p-cactions" role="navigation" class="vectorMenu<?php
347  if ( count( $this->data['action_urls'] ) == 0 ) {
348  echo ' emptyPortlet';
349  }
350  ?>" aria-labelledby="p-cactions-label">
351  <input type="checkbox" class="vectorMenuCheckbox" aria-labelledby="p-cactions-label" />
352  <h3 id="p-cactions-label"><span><?php
353  $this->msg( 'vector-more-actions' )
354  ?></span></h3>
355  <ul class="menu"<?php $this->html( 'userlangattributes' ) ?>>
356  <?php
357  foreach ( $this->data['action_urls'] as $key => $item ) {
358  echo $this->makeListItem( $key, $item );
359  }
360  ?>
361  </ul>
362  </div>
363  <?php
364  break;
365  case 'PERSONAL':
366  ?>
367  <div id="p-personal" role="navigation"<?php
368  if ( count( $this->data['personal_urls'] ) == 0 ) {
369  echo ' class="emptyPortlet"';
370  }
371  ?> aria-labelledby="p-personal-label">
372  <h3 id="p-personal-label"><?php $this->msg( 'personaltools' ) ?></h3>
373  <ul<?php $this->html( 'userlangattributes' ) ?>>
374  <?php
376 
377  if ( !$this->getSkin()->getUser()->isLoggedIn() &&
378  User::groupHasPermission( '*', 'edit' )
379  ) {
380  $notLoggedIn =
381  Html::element( 'li',
382  [ 'id' => 'pt-anonuserpage' ],
383  $this->getMsg( 'notloggedin' )->text()
384  );
385  }
386 
388 
390  if ( array_key_exists( 'uls', $personalTools ) ) {
391  $langSelector = $this->makeListItem( 'uls', $personalTools[ 'uls' ] );
392  unset( $personalTools[ 'uls' ] );
393  }
394 
395  echo $langSelector;
396  echo $notLoggedIn;
397  foreach ( $personalTools as $key => $item ) {
398  echo $this->makeListItem( $key, $item );
399  }
400  ?>
401  </ul>
402  </div>
403  <?php
404  break;
405  case 'SEARCH':
406  ?>
407  <div id="p-search" role="search">
408  <h3<?php $this->html( 'userlangattributes' ) ?>>
409  <label for="searchInput"><?php $this->msg( 'search' ) ?></label>
410  </h3>
411  <form action="<?php $this->text( 'wgScript' ) ?>" id="searchform">
412  <div<?php echo $this->config->get( 'VectorUseSimpleSearch' ) ? ' id="simpleSearch"' : '' ?>>
413  <?php
414  echo $this->makeSearchInput( [ 'id' => 'searchInput' ] );
415  echo Html::hidden( 'title', $this->get( 'searchtitle' ) );
416  /* We construct two buttons (for 'go' and 'fulltext' search modes),
417  * but only one will be visible and actionable at a time (they are
418  * overlaid on top of each other in CSS).
419  * * Browsers will use the 'fulltext' one by default (as it's the
420  * first in tree-order), which is desirable when they are unable
421  * to show search suggestions (either due to being broken or
422  * having JavaScript turned off).
423  * * The mediawiki.searchSuggest module, after doing tests for the
424  * broken browsers, removes the 'fulltext' button and handles
425  * 'fulltext' search itself; this will reveal the 'go' button and
426  * cause it to be used.
427  */
428  echo $this->makeSearchButton(
429  'fulltext',
430  [ 'id' => 'mw-searchButton', 'class' => 'searchButton mw-fallbackSearchButton' ]
431  );
432  echo $this->makeSearchButton(
433  'go',
434  [ 'id' => 'searchButton', 'class' => 'searchButton' ]
435  );
436  ?>
437  </div>
438  </form>
439  </div>
440  <?php
441 
442  break;
443  }
444  }
445  }
446 
450  public function makeLink( $key, $item, $options = [] ) {
451  $html = parent::makeLink( $key, $item, $options );
452  // Add an extra wrapper because our CSS is weird
453  if ( isset( $options['vector-wrap'] ) && $options['vector-wrap'] ) {
454  $html = Html::rawElement( 'span', [], $html );
455  }
456  return $html;
457  }
458 
462  public function makeListItem( $key, $item, $options = [] ) {
463  // For fancy styling of watch/unwatch star
464  if (
465  $this->config->get( 'VectorUseIconWatch' )
466  && ( $key === 'watch' || $key === 'unwatch' )
467  ) {
468  $item['class'] = rtrim( 'icon ' . $item['class'], ' ' );
469  $item['primary'] = true;
470  }
471 
472  // Add CSS class 'collapsible' to links which are not marked as "primary"
473  if (
474  isset( $options['vector-collapsible'] ) && $options['vector-collapsible'] ) {
475  $item['class'] = rtrim( 'collapsible ' . $item['class'], ' ' );
476  }
477 
478  return parent::makeListItem( $key, $item, $options );
479  }
480 }
BaseTemplate\getPersonalTools
getPersonalTools()
Create an array of personal tools items from the data in the quicktemplate stored by SkinTemplate.
Definition: BaseTemplate.php:127
BaseTemplate\getFooterLinks
getFooterLinks( $option=null)
Returns an array of footerlinks trimmed down to only those footer links that are valid.
Definition: BaseTemplate.php:581
BaseTemplate\msg
msg( $str)
Definition: BaseTemplate.php:42
Xml\expandAttributes
static expandAttributes( $attribs)
Given an array of ('attributename' => 'value'), it generates the code to set the XML attributes : att...
Definition: Xml.php:67
VectorTemplate\$notLoggedIn
case __pad3__ if(count( $this->data['personal_urls'])==0) $this msg('personaltools') $this html('userlangattributes') $notLoggedIn
Definition: VectorTemplate.php:375
BaseTemplate\makeSearchButton
makeSearchButton( $mode, $attrs=[])
Definition: BaseTemplate.php:531
VectorTemplate\$langSelector
$langSelector
Definition: VectorTemplate.php:389
getUser
getUser()
VectorTemplate\renderNavigation
renderNavigation(array $elements)
Render one or more navigations elements by name, automatically reversed by css when UI is in RTL mode...
Definition: VectorTemplate.php:268
User\groupHasPermission
static groupHasPermission( $group, $role)
Check, if the given group has the given permission.
Definition: User.php:4775
QuickTemplate\getSkin
getSkin()
Get the Skin object related to this object.
Definition: QuickTemplate.php:166
Linker\tooltipAndAccesskeyAttribs
static tooltipAndAccesskeyAttribs( $name, array $msgParams=[], $options=null)
Returns the attributes for the tooltip and access key.
Definition: Linker.php:2195
VectorTemplate\$templates
$templates
Definition: VectorTemplate.php:166
VectorTemplate
QuickTemplate subclass for Vector.
Definition: VectorTemplate.php:29
VectorTemplate\makeListItem
makeListItem( $key, $item, $options=[])
Generates a list item for a navigation, portlet, portal, sidebar...listUsually a key from the list yo...
Definition: VectorTemplate.php:462
VectorTemplate\$footericons
$this html('userlangattributes') foreach( $this->getFooterLinks() as $category=> $links) foreach( $links as $link) $this html($link) $footericons
Definition: VectorTemplate.php:138
VectorTemplate\makeLink
makeLink( $key, $item, $options=[])
Makes a link, usually used by makeListItem to generate a link for an item in a list used in navigatio...
Definition: VectorTemplate.php:450
VectorTemplate\execute
execute()
Outputs the entire contents of the HTML page.
Definition: VectorTemplate.php:34
VectorTemplate\renderPortal
renderPortal( $name, $content, $msg=null, $hook=null)
Definition: VectorTemplate.php:217
BaseTemplate\getIndicators
getIndicators()
Get the suggested HTML for page status indicators: icons (or short text snippets) usually displayed i...
Definition: BaseTemplate.php:725
VectorTemplate\$params
if(count( $footericons) > 0) foreach( $footerIcons as $icon) $params['html-unported']
Definition: VectorTemplate.php:162
$content
$content
Definition: router.php:78
BaseTemplate\renderAfterPortlet
renderAfterPortlet( $name)
Definition: BaseTemplate.php:283
BaseTemplate\makeSearchInput
makeSearchInput( $attrs=[])
Definition: BaseTemplate.php:521
VectorTemplate\renderPortals
renderPortals(array $portals)
Render a series of portals.
Definition: VectorTemplate.php:175
Linker\tooltip
static tooltip( $name, $options=null)
Returns raw bits of HTML, use titleAttrib()
Definition: Linker.php:2223
BaseTemplate\getToolbox
getToolbox()
Create an array of common toolbox items from the data in the quicktemplate stored by SkinTemplate.
Definition: BaseTemplate.php:61
BaseTemplate\getTrail
getTrail()
Get the basic end-page trail including bottomscripts, reporttime, and debug stuff.
Definition: BaseTemplate.php:756
BaseTemplate\getMsg
getMsg( $name,... $params)
Get a Message object with its context set.
Definition: BaseTemplate.php:38
VectorTemplate\$personalTools
if(! $this->getSkin() ->getUser() ->isLoggedIn() &&User::groupHasPermission(' *', 'edit') $personalTools)
Definition: VectorTemplate.php:387
VectorTemplate\$variantLabel
case __pad0__ if(count( $this->data['variant_urls'])==0) $variantLabel
Definition: VectorTemplate.php:301
BaseTemplate\getFooterIcons
getFooterIcons( $option=null)
Returns an array of footer icons filtered down by options relevant to how the skin wishes to display ...
Definition: BaseTemplate.php:618
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
BaseTemplate
New base template for a skin's template extended from QuickTemplate this class features helper method...
Definition: BaseTemplate.php:29
VectorTemplate\html
$this html( 'userlangattributes')
Definition: VectorTemplate.php:229
VectorTemplate\text
case __pad4__ $this html('userlangattributes') $this msg('search') $this text( 'wgScript')
Definition: VectorTemplate.php:411