Break some long lines in maintenance, skins, tests
[lhc/web/wiklou.git] / skins / Vector / VectorTemplate.php
1 <?php
2 /**
3 * Vector - Modern version of MonoBook with fresh look and many usability
4 * improvements.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 * @file
22 * @ingroup Skins
23 */
24
25 /**
26 * QuickTemplate class for Vector skin
27 * @ingroup Skins
28 */
29 class VectorTemplate extends BaseTemplate {
30 /* Functions */
31
32 /**
33 * Outputs the entire contents of the (X)HTML page
34 */
35 public function execute() {
36 global $wgVectorUseIconWatch;
37
38 // Build additional attributes for navigation urls
39 $nav = $this->data['content_navigation'];
40
41 if ( $wgVectorUseIconWatch ) {
42 $mode = $this->getSkin()->getUser()->isWatched( $this->getSkin()->getRelevantTitle() )
43 ? 'unwatch'
44 : 'watch';
45
46 if ( isset( $nav['actions'][$mode] ) ) {
47 $nav['views'][$mode] = $nav['actions'][$mode];
48 $nav['views'][$mode]['class'] = rtrim( 'icon ' . $nav['views'][$mode]['class'], ' ' );
49 $nav['views'][$mode]['primary'] = true;
50 unset( $nav['actions'][$mode] );
51 }
52 }
53
54 $xmlID = '';
55 foreach ( $nav as $section => $links ) {
56 foreach ( $links as $key => $link ) {
57 if ( $section == 'views' && !( isset( $link['primary'] ) && $link['primary'] ) ) {
58 $link['class'] = rtrim( 'collapsible ' . $link['class'], ' ' );
59 }
60
61 $xmlID = isset( $link['id'] ) ? $link['id'] : 'ca-' . $xmlID;
62 $nav[$section][$key]['attributes'] =
63 ' id="' . Sanitizer::escapeId( $xmlID ) . '"';
64 if ( $link['class'] ) {
65 $nav[$section][$key]['attributes'] .=
66 ' class="' . htmlspecialchars( $link['class'] ) . '"';
67 unset( $nav[$section][$key]['class'] );
68 }
69 if ( isset( $link['tooltiponly'] ) && $link['tooltiponly'] ) {
70 $nav[$section][$key]['key'] =
71 Linker::tooltip( $xmlID );
72 } else {
73 $nav[$section][$key]['key'] =
74 Xml::expandAttributes( Linker::tooltipAndAccesskeyAttribs( $xmlID ) );
75 }
76 }
77 }
78 $this->data['namespace_urls'] = $nav['namespaces'];
79 $this->data['view_urls'] = $nav['views'];
80 $this->data['action_urls'] = $nav['actions'];
81 $this->data['variant_urls'] = $nav['variants'];
82
83 // Reverse horizontally rendered navigation elements
84 if ( $this->data['rtl'] ) {
85 $this->data['view_urls'] =
86 array_reverse( $this->data['view_urls'] );
87 $this->data['namespace_urls'] =
88 array_reverse( $this->data['namespace_urls'] );
89 $this->data['personal_urls'] =
90 array_reverse( $this->data['personal_urls'] );
91 }
92 // Output HTML Page
93 $this->html( 'headelement' );
94 ?>
95 <div id="mw-page-base" class="noprint"></div>
96 <div id="mw-head-base" class="noprint"></div>
97 <div id="content" class="mw-body" role="main">
98 <a id="top"></a>
99
100 <?php
101 if ( $this->data['sitenotice'] ) {
102 ?>
103 <div id="siteNotice"><?php $this->html( 'sitenotice' ) ?></div>
104 <?php
105 }
106 ?>
107 <h1 id="firstHeading" class="firstHeading" lang="<?php
108 $this->data['pageLanguage'] =
109 $this->getSkin()->getTitle()->getPageViewLanguage()->getHtmlCode();
110 $this->text( 'pageLanguage' );
111 ?>"><span dir="auto"><?php $this->html( 'title' ) ?></span></h1>
112 <?php $this->html( 'prebodyhtml' ) ?>
113 <div id="bodyContent" class="mw-body-content">
114 <?php
115 if ( $this->data['isarticle'] ) {
116 ?>
117 <div id="siteSub"><?php $this->msg( 'tagline' ) ?></div>
118 <?php
119 }
120 ?>
121 <div id="contentSub"<?php
122 $this->html( 'userlangattributes' )
123 ?>><?php $this->html( 'subtitle' ) ?></div>
124 <?php
125 if ( $this->data['undelete'] ) {
126 ?>
127 <div id="contentSub2"><?php $this->html( 'undelete' ) ?></div>
128 <?php
129 }
130 ?>
131 <?php
132 if ( $this->data['newtalk'] ) {
133 ?>
134 <div class="usermessage"><?php $this->html( 'newtalk' ) ?></div>
135 <?php
136 }
137 ?>
138 <div id="jump-to-nav" class="mw-jump">
139 <?php $this->msg( 'jumpto' ) ?>
140 <a href="#mw-navigation"><?php
141 $this->msg( 'jumptonavigation' )
142 ?></a><?php
143 $this->msg( 'comma-separator' )
144 ?>
145 <a href="#p-search"><?php $this->msg( 'jumptosearch' ) ?></a>
146 </div>
147 <?php $this->html( 'bodycontent' ) ?>
148 <?php
149 if ( $this->data['printfooter'] ) {
150 ?>
151 <div class="printfooter">
152 <?php $this->html( 'printfooter' ); ?>
153 </div>
154 <?php
155 }
156 ?>
157 <?php
158 if ( $this->data['catlinks'] ) {
159 ?>
160 <?php
161 $this->html( 'catlinks' );
162 ?>
163 <?php
164 }
165 ?>
166 <?php
167 if ( $this->data['dataAfterContent'] ) {
168 ?>
169 <?php
170 $this->html( 'dataAfterContent' );
171 ?>
172 <?php
173 }
174 ?>
175 <div class="visualClear"></div>
176 <?php $this->html( 'debughtml' ); ?>
177 </div>
178 </div>
179 <div id="mw-navigation">
180 <h2><?php $this->msg( 'navigation-heading' ) ?></h2>
181
182 <div id="mw-head">
183 <?php $this->renderNavigation( 'PERSONAL' ); ?>
184 <div id="left-navigation">
185 <?php $this->renderNavigation( array( 'NAMESPACES', 'VARIANTS' ) ); ?>
186 </div>
187 <div id="right-navigation">
188 <?php $this->renderNavigation( array( 'VIEWS', 'ACTIONS', 'SEARCH' ) ); ?>
189 </div>
190 </div>
191 <div id="mw-panel">
192 <div id="p-logo" role="banner"><a style="background-image: url(<?php
193 $this->text( 'logopath' )
194 ?>);" href="<?php
195 echo htmlspecialchars( $this->data['nav_urls']['mainpage']['href'] )
196 ?>" <?php
197 echo Xml::expandAttributes( Linker::tooltipAndAccesskeyAttribs( 'p-logo' ) )
198 ?>></a></div>
199 <?php $this->renderPortals( $this->data['sidebar'] ); ?>
200 </div>
201 </div>
202 <div id="footer" role="contentinfo"<?php $this->html( 'userlangattributes' ) ?>>
203 <?php
204 foreach ( $this->getFooterLinks() as $category => $links ) {
205 ?>
206 <ul id="footer-<?php
207 echo $category
208 ?>">
209 <?php
210 foreach ( $links as $link ) {
211 ?>
212 <li id="footer-<?php
213 echo $category
214 ?>-<?php
215 echo $link
216 ?>"><?php
217 $this->html( $link )
218 ?></li>
219 <?php
220 }
221 ?>
222 </ul>
223 <?php
224 }
225 ?>
226 <?php $footericons = $this->getFooterIcons( "icononly" );
227 if ( count( $footericons ) > 0 ) {
228 ?>
229 <ul id="footer-icons" class="noprint">
230 <?php
231 foreach ( $footericons as $blockName => $footerIcons ) {
232 ?>
233 <li id="footer-<?php
234 echo htmlspecialchars( $blockName ); ?>ico">
235 <?php
236 foreach ( $footerIcons as $icon ) {
237 ?>
238 <?php
239 echo $this->getSkin()->makeFooterIcon( $icon );
240 ?>
241
242 <?php
243 }
244 ?>
245 </li>
246 <?php
247 }
248 ?>
249 </ul>
250 <?php
251 }
252 ?>
253 <div style="clear:both"></div>
254 </div>
255 <?php $this->printTrail(); ?>
256
257 </body>
258 </html>
259 <?php
260 }
261
262 /**
263 * Render a series of portals
264 *
265 * @param array $portals
266 */
267 protected function renderPortals( $portals ) {
268 // Force the rendering of the following portals
269 if ( !isset( $portals['SEARCH'] ) ) {
270 $portals['SEARCH'] = true;
271 }
272 if ( !isset( $portals['TOOLBOX'] ) ) {
273 $portals['TOOLBOX'] = true;
274 }
275 if ( !isset( $portals['LANGUAGES'] ) ) {
276 $portals['LANGUAGES'] = true;
277 }
278 // Render portals
279 foreach ( $portals as $name => $content ) {
280 if ( $content === false ) {
281 continue;
282 }
283
284 switch ( $name ) {
285 case 'SEARCH':
286 break;
287 case 'TOOLBOX':
288 $this->renderPortal( 'tb', $this->getToolbox(), 'toolbox', 'SkinTemplateToolboxEnd' );
289 break;
290 case 'LANGUAGES':
291 if ( $this->data['language_urls'] !== false ) {
292 $this->renderPortal( 'lang', $this->data['language_urls'], 'otherlanguages' );
293 }
294 break;
295 default:
296 $this->renderPortal( $name, $content );
297 break;
298 }
299 }
300 }
301
302 /**
303 * @param string $name
304 * @param array $content
305 * @param null|string $msg
306 * @param null|string|array $hook
307 */
308 protected function renderPortal( $name, $content, $msg = null, $hook = null ) {
309 if ( $msg === null ) {
310 $msg = $name;
311 }
312 $msgObj = wfMessage( $msg );
313 ?>
314 <div class="portal" role="navigation" id='<?php
315 echo Sanitizer::escapeId( "p-$name" )
316 ?>'<?php
317 echo Linker::tooltip( 'p-' . $name )
318 ?> aria-labelledby='<?php echo Sanitizer::escapeId( "p-$name-label" ) ?>'>
319 <h3<?php
320 $this->html( 'userlangattributes' )
321 ?> id='<?php
322 echo Sanitizer::escapeId( "p-$name-label" )
323 ?>'><?php
324 echo htmlspecialchars( $msgObj->exists() ? $msgObj->text() : $msg );
325 ?></h3>
326
327 <div class="body">
328 <?php
329 if ( is_array( $content ) ) {
330 ?>
331 <ul>
332 <?php
333 foreach ( $content as $key => $val ) {
334 ?>
335 <?php echo $this->makeListItem( $key, $val ); ?>
336
337 <?php
338 }
339 if ( $hook !== null ) {
340 wfRunHooks( $hook, array( &$this, true ) );
341 }
342 ?>
343 </ul>
344 <?php
345 } else {
346 ?>
347 <?php
348 echo $content; /* Allow raw HTML block to be defined by extensions */
349 }
350
351 $this->renderAfterPortlet( $name );
352 ?>
353 </div>
354 </div>
355 <?php
356 }
357
358 /**
359 * Render one or more navigations elements by name, automatically reveresed
360 * when UI is in RTL mode
361 *
362 * @param array $elements
363 */
364 protected function renderNavigation( $elements ) {
365 global $wgVectorUseSimpleSearch;
366
367 // If only one element was given, wrap it in an array, allowing more
368 // flexible arguments
369 if ( !is_array( $elements ) ) {
370 $elements = array( $elements );
371 // If there's a series of elements, reverse them when in RTL mode
372 } elseif ( $this->data['rtl'] ) {
373 $elements = array_reverse( $elements );
374 }
375 // Render elements
376 foreach ( $elements as $name => $element ) {
377 switch ( $element ) {
378 case 'NAMESPACES':
379 ?>
380 <div id="p-namespaces" role="navigation" class="vectorTabs<?php
381 if ( count( $this->data['namespace_urls'] ) == 0 ) {
382 echo ' emptyPortlet';
383 }
384 ?>" aria-labelledby="p-namespaces-label">
385 <h3 id="p-namespaces-label"><?php $this->msg( 'namespaces' ) ?></h3>
386 <ul<?php $this->html( 'userlangattributes' ) ?>>
387 <?php
388 foreach ( $this->data['namespace_urls'] as $link ) {
389 ?>
390 <li <?php
391 echo $link['attributes']
392 ?>><span><a href="<?php
393 echo htmlspecialchars( $link['href'] )
394 ?>" <?php
395 echo $link['key']
396 ?>><?php
397 echo htmlspecialchars( $link['text'] )
398 ?></a></span></li>
399 <?php
400 }
401 ?>
402 </ul>
403 </div>
404 <?php
405 break;
406 case 'VARIANTS':
407 ?>
408 <div id="p-variants" role="navigation" class="vectorMenu<?php
409 if ( count( $this->data['variant_urls'] ) == 0 ) {
410 echo ' emptyPortlet';
411 }
412 ?>" aria-labelledby="p-variants-label">
413 <?php
414 // Replace the label with the name of currently chosen variant, if any
415 $variantLabel = $this->getMsg( 'variants' )->text();
416 foreach ( $this->data['variant_urls'] as $link ) {
417 if ( stripos( $link['attributes'], 'selected' ) !== false ) {
418 $variantLabel = $link['text'];
419 break;
420 }
421 }
422 ?>
423 <h3 id="p-variants-label"><span
424 style="display: block;" <?php /* Temporary WMF deployment hack, to be removed before 1.24 release */ ?>
425 ><?php echo htmlspecialchars( $variantLabel ) ?></span><a href="#"></a></h3>
426
427 <div class="menu">
428 <ul>
429 <?php
430 foreach ( $this->data['variant_urls'] as $link ) {
431 ?>
432 <li<?php
433 echo $link['attributes']
434 ?>><a href="<?php
435 echo htmlspecialchars( $link['href'] )
436 ?>" lang="<?php
437 echo htmlspecialchars( $link['lang'] )
438 ?>" hreflang="<?php
439 echo htmlspecialchars( $link['hreflang'] )
440 ?>" <?php
441 echo $link['key']
442 ?>><?php
443 echo htmlspecialchars( $link['text'] )
444 ?></a></li>
445 <?php
446 }
447 ?>
448 </ul>
449 </div>
450 </div>
451 <?php
452 break;
453 case 'VIEWS':
454 ?>
455 <div id="p-views" role="navigation" class="vectorTabs<?php
456 if ( count( $this->data['view_urls'] ) == 0 ) {
457 echo ' emptyPortlet';
458 }
459 ?>" aria-labelledby="p-views-label">
460 <h3 id="p-views-label"><?php $this->msg( 'views' ) ?></h3>
461 <ul<?php
462 $this->html( 'userlangattributes' )
463 ?>>
464 <?php
465 foreach ( $this->data['view_urls'] as $link ) {
466 ?>
467 <li<?php
468 echo $link['attributes']
469 ?>><span><a href="<?php
470 echo htmlspecialchars( $link['href'] )
471 ?>" <?php
472 echo $link['key']
473 ?>><?php
474 // $link['text'] can be undefined - bug 27764
475 if ( array_key_exists( 'text', $link ) ) {
476 echo array_key_exists( 'img', $link )
477 ? '<img src="' . $link['img'] . '" alt="' . $link['text'] . '" />'
478 : htmlspecialchars( $link['text'] );
479 }
480 ?></a></span></li>
481 <?php
482 }
483 ?>
484 </ul>
485 </div>
486 <?php
487 break;
488 case 'ACTIONS':
489 ?>
490 <div id="p-cactions" role="navigation" class="vectorMenu<?php
491 if ( count( $this->data['action_urls'] ) == 0 ) {
492 echo ' emptyPortlet';
493 }
494 ?>" aria-labelledby="p-cactions-label">
495 <h3 id="p-cactions-label"><span><?php
496 $this->msg( 'vector-more-actions' )
497 ?></span><a href="#"></a></h3>
498
499 <div class="menu">
500 <ul<?php $this->html( 'userlangattributes' ) ?>>
501 <?php
502 foreach ( $this->data['action_urls'] as $link ) {
503 ?>
504 <li<?php
505 echo $link['attributes']
506 ?>>
507 <a href="<?php
508 echo htmlspecialchars( $link['href'] )
509 ?>" <?php
510 echo $link['key'] ?>><?php echo htmlspecialchars( $link['text'] )
511 ?></a>
512 </li>
513 <?php
514 }
515 ?>
516 </ul>
517 </div>
518 </div>
519 <?php
520 break;
521 case 'PERSONAL':
522 ?>
523 <div id="p-personal" role="navigation" class="<?php
524 if ( count( $this->data['personal_urls'] ) == 0 ) {
525 echo ' emptyPortlet';
526 }
527 ?>" aria-labelledby="p-personal-label">
528 <h3 id="p-personal-label"><?php $this->msg( 'personaltools' ) ?></h3>
529 <ul<?php $this->html( 'userlangattributes' ) ?>>
530 <?php
531 $personalTools = $this->getPersonalTools();
532 foreach ( $personalTools as $key => $item ) {
533 echo $this->makeListItem( $key, $item );
534 }
535 ?>
536 </ul>
537 </div>
538 <?php
539 break;
540 case 'SEARCH':
541 ?>
542 <div id="p-search" role="search">
543 <h3<?php $this->html( 'userlangattributes' ) ?>>
544 <label for="searchInput"><?php $this->msg( 'search' ) ?></label>
545 </h3>
546
547 <form action="<?php $this->text( 'wgScript' ) ?>" id="searchform">
548 <?php
549 if ( $wgVectorUseSimpleSearch ) {
550 ?>
551 <div id="simpleSearch">
552 <?php
553 } else {
554 ?>
555 <div>
556 <?php
557 }
558 ?>
559 <?php
560 echo $this->makeSearchInput( array( 'id' => 'searchInput' ) );
561 echo Html::hidden( 'title', $this->get( 'searchtitle' ) );
562 // We construct two buttons (for 'go' and 'fulltext' search modes),
563 // but only one will be visible and actionable at a time (they are
564 // overlaid on top of each other in CSS).
565 // * Browsers will use the 'fulltext' one by default (as it's the
566 // first in tree-order), which is desirable when they are unable
567 // to show search suggestions (either due to being broken or
568 // having JavaScript turned off).
569 // * The mediawiki.searchSuggest module, after doing tests for the
570 // broken browsers, removes the 'fulltext' button and handles
571 // 'fulltext' search itself; this will reveal the 'go' button and
572 // cause it to be used.
573 echo $this->makeSearchButton(
574 'fulltext',
575 array( 'id' => 'mw-searchButton', 'class' => 'searchButton mw-fallbackSearchButton' )
576 );
577 echo $this->makeSearchButton(
578 'go',
579 array( 'id' => 'searchButton', 'class' => 'searchButton' )
580 );
581 ?>
582 </div>
583 </form>
584 </div>
585 <?php
586
587 break;
588 }
589 }
590 }
591 }