r79383 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r79382‎ | r79383 | r79384 >
Date:23:30, 31 December 2010
Author:dantman
Status:resolved (Comments)
Tags:
Comment:
Merging Vector's navigation_urls and SkinTemplate's content_actions code into content_navigation. content_actions is now built by folding content_navigation and cleaning it up a bit.
content_actions hooks no longer work and have been dropped from the code, the hooks that affected vector before now affect all skins.
A few logic changes were made to make for a clean merge:
- vector was using vector-???-??? messages while SkinTemplate was using '???' messages. So as a side effect of merging that together all skins now support messages like '$skinname-view-history' which will fallback to the standard message if not defined.
- For MediaWiki: pages where the page does not exist but the message does in the i18n system SkinTemplate displayed "Edit" while Vector displayed "Create"; All skins now display "Edit".
- For users without undelete permissions SkinTemplate displayed an "Undelete" tab if the user had deletedhistory and deletedtext permissions. Vector would only display the tab for users with both deletedhistory and undelete permissions; The new behavior in all skins is to always display a tab if you have deletedhistory (since Special:Undelete will always have something to display) but display a "View ... deleted" instead of "Undelete" message if you do not have undelete permissions.
- Skins no longer need to hardcode tests for the &action= to decide if they should ignore the accesskey on some tabs, tabs which should not have an accesskey in the current page now have a "tooltiponly" key set to true.
Modified paths:
  • /trunk/phase3/docs/hooks.txt (modified) (history)
  • /trunk/phase3/includes/GlobalFunctions.php (modified) (history)
  • /trunk/phase3/includes/SkinTemplate.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesEn.php (modified) (history)
  • /trunk/phase3/maintenance/language/messages.inc (modified) (history)
  • /trunk/phase3/skins/MonoBook.php (modified) (history)
  • /trunk/phase3/skins/Vector.php (modified) (history)

Diff [purge]

Index: trunk/phase3/maintenance/language/messages.inc
@@ -221,6 +221,7 @@
222222 'printableversion',
223223 'permalink',
224224 'print',
 225+ 'view',
225226 'edit',
226227 'create',
227228 'editthispage',
@@ -228,6 +229,7 @@
229230 'delete',
230231 'deletethispage',
231232 'undelete_short',
 233+ 'viewdeleted_short',
232234 'protect',
233235 'protect_change',
234236 'protectthispage',
Index: trunk/phase3/skins/Vector.php
@@ -50,296 +50,6 @@
5151 parent::setupSkinUserCss( $out );
5252 $out->addModuleStyles( 'skins.vector' );
5353 }
54 -
55 - /**
56 - * Builds a structured array of links used for tabs and menus
57 - * @return array
58 - * @private
59 - */
60 - function buildNavigationUrls() {
61 - global $wgContLang, $wgLang, $wgOut, $wgUser, $wgRequest, $wgArticle;
62 - global $wgDisableLangConversion, $wgVectorUseIconWatch;
63 -
64 - wfProfileIn( __METHOD__ );
65 -
66 - $links = array(
67 - 'namespaces' => array(),
68 - 'views' => array(),
69 - 'actions' => array(),
70 - 'variants' => array()
71 - );
72 -
73 - // Detects parameters
74 - $action = $wgRequest->getVal( 'action', 'view' );
75 - $section = $wgRequest->getVal( 'section' );
76 -
77 - $userCanRead = $this->mTitle->userCanRead();
78 -
79 - // Checks if page is some kind of content
80 - if( $this->iscontent ) {
81 - // Gets page objects for the related namespaces
82 - $subjectPage = $this->mTitle->getSubjectPage();
83 - $talkPage = $this->mTitle->getTalkPage();
84 -
85 - // Determines if this is a talk page
86 - $isTalk = $this->mTitle->isTalkPage();
87 -
88 - // Generates XML IDs from namespace names
89 - $subjectId = $this->mTitle->getNamespaceKey( '' );
90 -
91 - if ( $subjectId == 'main' ) {
92 - $talkId = 'talk';
93 - } else {
94 - $talkId = "{$subjectId}_talk";
95 - }
96 -
97 - // Adds namespace links
98 - $links['namespaces'][$subjectId] = $this->tabAction(
99 - $subjectPage, 'nstab-' . $subjectId, !$isTalk, '', $userCanRead
100 - );
101 - $links['namespaces'][$subjectId]['context'] = 'subject';
102 - $links['namespaces'][$talkId] = $this->tabAction(
103 - $talkPage, 'talk', $isTalk, '', $userCanRead
104 - );
105 - $links['namespaces'][$talkId]['context'] = 'talk';
106 -
107 - // Adds view view link
108 - if ( $this->mTitle->exists() && $userCanRead ) {
109 - $links['views']['view'] = $this->tabAction(
110 - $isTalk ? $talkPage : $subjectPage,
111 - 'vector-view-view', ( $action == 'view' ), '', true
112 - );
113 - }
114 -
115 - wfProfileIn( __METHOD__ . '-edit' );
116 -
117 - // Checks if user can...
118 - if (
119 - // read and edit the current page
120 - $userCanRead && $this->mTitle->quickUserCan( 'edit' ) &&
121 - (
122 - // if it exists
123 - $this->mTitle->exists() ||
124 - // or they can create one here
125 - $this->mTitle->quickUserCan( 'create' )
126 - )
127 - ) {
128 - // Builds CSS class for talk page links
129 - $isTalkClass = $isTalk ? ' istalk' : '';
130 -
131 - // Determines if we're in edit mode
132 - $selected = (
133 - ( $action == 'edit' || $action == 'submit' ) &&
134 - ( $section != 'new' )
135 - );
136 - $links['views']['edit'] = array(
137 - 'class' => ( $selected ? 'selected' : '' ) . $isTalkClass,
138 - 'text' => $this->mTitle->exists()
139 - ? wfMsg( 'vector-view-edit' )
140 - : wfMsg( 'vector-view-create' ),
141 - 'href' =>
142 - $this->mTitle->getLocalURL( $this->editUrlOptions() )
143 - );
144 - // Checks if this is a current rev of talk page and we should show a new
145 - // section link
146 - if ( ( $isTalk && $wgArticle && $wgArticle->isCurrent() ) || ( $wgOut->showNewSectionLink() ) ) {
147 - // Checks if we should ever show a new section link
148 - if ( !$wgOut->forceHideNewSectionLink() ) {
149 - // Adds new section link
150 - //$links['actions']['addsection']
151 - $links['views']['addsection'] = array(
152 - 'class' => 'collapsible ' . ( $section == 'new' ? 'selected' : false ),
153 - 'text' => wfMsg( 'vector-action-addsection' ),
154 - 'href' => $this->mTitle->getLocalURL(
155 - 'action=edit&section=new'
156 - )
157 - );
158 - }
159 - }
160 - // Checks if the page has some kind of viewable content
161 - } elseif ( $this->mTitle->hasSourceText() && $userCanRead ) {
162 - // Adds view source view link
163 - $links['views']['viewsource'] = array(
164 - 'class' => ( $action == 'edit' ) ? 'selected' : false,
165 - 'text' => wfMsg( 'vector-view-viewsource' ),
166 - 'href' =>
167 - $this->mTitle->getLocalURL( $this->editUrlOptions() )
168 - );
169 - }
170 - wfProfileOut( __METHOD__ . '-edit' );
171 -
172 - wfProfileIn( __METHOD__ . '-live' );
173 -
174 - // Checks if the page exists
175 - if ( $this->mTitle->exists() && $userCanRead ) {
176 - // Adds history view link
177 - $links['views']['history'] = array(
178 - 'class' => 'collapsible ' . ( ( $action == 'history' ) ? 'selected' : false ),
179 - 'text' => wfMsg( 'vector-view-history' ),
180 - 'href' => $this->mTitle->getLocalURL( 'action=history' ),
181 - 'rel' => 'archives',
182 - );
183 -
184 - if( $wgUser->isAllowed( 'delete' ) ) {
185 - $links['actions']['delete'] = array(
186 - 'class' => ( $action == 'delete' ) ? 'selected' : false,
187 - 'text' => wfMsg( 'vector-action-delete' ),
188 - 'href' => $this->mTitle->getLocalURL( 'action=delete' )
189 - );
190 - }
191 - if ( $this->mTitle->quickUserCan( 'move' ) ) {
192 - $moveTitle = SpecialPage::getTitleFor(
193 - 'Movepage', $this->thispage
194 - );
195 - $links['actions']['move'] = array(
196 - 'class' => $this->mTitle->isSpecial( 'Movepage' ) ?
197 - 'selected' : false,
198 - 'text' => wfMsg( 'vector-action-move' ),
199 - 'href' => $moveTitle->getLocalURL()
200 - );
201 - }
202 -
203 - if (
204 - $this->mTitle->getNamespace() !== NS_MEDIAWIKI &&
205 - $wgUser->isAllowed( 'protect' )
206 - ) {
207 - if ( !$this->mTitle->isProtected() ) {
208 - $links['actions']['protect'] = array(
209 - 'class' => ( $action == 'protect' ) ?
210 - 'selected' : false,
211 - 'text' => wfMsg( 'vector-action-protect' ),
212 - 'href' =>
213 - $this->mTitle->getLocalURL( 'action=protect' )
214 - );
215 -
216 - } else {
217 - $links['actions']['unprotect'] = array(
218 - 'class' => ( $action == 'unprotect' ) ?
219 - 'selected' : false,
220 - 'text' => wfMsg( 'vector-action-unprotect' ),
221 - 'href' =>
222 - $this->mTitle->getLocalURL( 'action=unprotect' )
223 - );
224 - }
225 - }
226 - } else {
227 - // article doesn't exist or is deleted
228 - if (
229 - $wgUser->isAllowed( 'deletedhistory' ) &&
230 - $wgUser->isAllowed( 'undelete' )
231 - ) {
232 - $n = $this->mTitle->isDeleted();
233 - if( $n ) {
234 - $undelTitle = SpecialPage::getTitleFor( 'Undelete' );
235 - $links['actions']['undelete'] = array(
236 - 'class' => false,
237 - 'text' => wfMsgExt(
238 - 'vector-action-undelete',
239 - array( 'parsemag' ),
240 - $wgLang->formatNum( $n )
241 - ),
242 - 'href' => $undelTitle->getLocalURL(
243 - 'target=' . urlencode( $this->thispage )
244 - )
245 - );
246 - }
247 - }
248 -
249 - if (
250 - $this->mTitle->getNamespace() !== NS_MEDIAWIKI &&
251 - $wgUser->isAllowed( 'protect' )
252 - ) {
253 - if ( !$this->mTitle->getRestrictions( 'create' ) ) {
254 - $links['actions']['protect'] = array(
255 - 'class' => ( $action == 'protect' ) ?
256 - 'selected' : false,
257 - 'text' => wfMsg( 'vector-action-protect' ),
258 - 'href' =>
259 - $this->mTitle->getLocalURL( 'action=protect' )
260 - );
261 -
262 - } else {
263 - $links['actions']['unprotect'] = array(
264 - 'class' => ( $action == 'unprotect' ) ?
265 - 'selected' : false,
266 - 'text' => wfMsg( 'vector-action-unprotect' ),
267 - 'href' =>
268 - $this->mTitle->getLocalURL( 'action=unprotect' )
269 - );
270 - }
271 - }
272 - }
273 - wfProfileOut( __METHOD__ . '-live' );
274 - /**
275 - * The following actions use messages which, if made particular to
276 - * the Vector skin, would break the Ajax code which makes this
277 - * action happen entirely inline. Skin::makeGlobalVariablesScript
278 - * defines a set of messages in a javascript object - and these
279 - * messages are assumed to be global for all skins. Without making
280 - * a change to that procedure these messages will have to remain as
281 - * the global versions.
282 - */
283 - // Checks if the user is logged in
284 - if ( $this->loggedin ) {
285 - if ( $wgVectorUseIconWatch ) {
286 - $class = 'icon';
287 - $place = 'views';
288 - } else {
289 - $class = '';
290 - $place = 'actions';
291 - }
292 - $mode = $this->mTitle->userIsWatching() ? 'unwatch' : 'watch';
293 - $links[$place][$mode] = array(
294 - 'class' => $class . ( ( $action == 'watch' || $action == 'unwatch' ) ? ' selected' : false ),
295 - 'text' => wfMsg( $mode ), // uses 'watch' or 'unwatch' message
296 - 'href' => $this->mTitle->getLocalURL( 'action=' . $mode )
297 - );
298 - }
299 - // This is instead of SkinTemplateTabs - which uses a flat array
300 - wfRunHooks( 'SkinTemplateNavigation', array( &$this, &$links ) );
301 -
302 - // If it's not content, it's got to be a special page
303 - } else {
304 - $links['namespaces']['special'] = array(
305 - 'class' => 'selected',
306 - 'text' => wfMsg( 'nstab-special' ),
307 - 'href' => $wgRequest->getRequestURL()
308 - );
309 - // Equiv to SkinTemplateBuildContentActionUrlsAfterSpecialPage
310 - wfRunHooks( 'SkinTemplateNavigation::SpecialPage', array( &$this, &$links ) );
311 - }
312 -
313 - // Gets list of language variants
314 - $variants = $wgContLang->getVariants();
315 - // Checks that language conversion is enabled and variants exist
316 - if( !$wgDisableLangConversion && count( $variants ) > 1 ) {
317 - // Gets preferred variant
318 - $preferred = $wgContLang->getPreferredVariant();
319 - // Loops over each variant
320 - foreach( $variants as $code ) {
321 - // Gets variant name from language code
322 - $varname = $wgContLang->getVariantname( $code );
323 - // Checks if the variant is marked as disabled
324 - if( $varname == 'disable' ) {
325 - // Skips this variant
326 - continue;
327 - }
328 - // Appends variant link
329 - $links['variants'][] = array(
330 - 'class' => ( $code == $preferred ) ? 'selected' : false,
331 - 'text' => $varname,
332 - 'href' => $this->mTitle->getLocalURL( '', $code )
333 - );
334 - }
335 - }
336 -
337 - // Equiv to SkinTemplateContentActions
338 - wfRunHooks( 'SkinTemplateNavigation::Universal', array( &$this, &$links ) );
339 -
340 - wfProfileOut( __METHOD__ );
341 -
342 - return $links;
343 - }
34454 }
34555
34656 /**
@@ -361,39 +71,38 @@
36272 * Outputs the entire contents of the XHTML page
36373 */
36474 public function execute() {
365 - global $wgRequest, $wgLang;
 75+ global $wgRequest, $wgLang, $wgVectorUseIconWatch;
36676
36777 $this->skin = $this->data['skin'];
36878 $action = $wgRequest->getText( 'action' );
36979
37080 // Build additional attributes for navigation urls
371 - $nav = $this->skin->buildNavigationUrls();
 81+ //$nav = $this->skin->buildNavigationUrls();
 82+ $nav = $this->data['content_navigation'];
 83+
 84+ if ( $wgVectorUseIconWatch ) {
 85+ $mode = $this->skin->mTitle->userIsWatching() ? 'unwatch' : 'watch';
 86+ $nav['views'][$mode] = $nav['actions'][$mode];
 87+ $nav['views'][$mode]['class'] = rtrim('icon ' . $nav['views'][$mode]['class'], ' ');
 88+ $nav['views'][$mode]['primary'] = true;
 89+ unset($nav['actions'][$mode]);
 90+ }
 91+
37292 foreach ( $nav as $section => $links ) {
37393 foreach ( $links as $key => $link ) {
374 - $xmlID = $key;
375 - if ( isset( $link['context'] ) && $link['context'] == 'subject' ) {
376 - $xmlID = 'ca-nstab-' . $xmlID;
377 - } else if ( isset( $link['context'] ) && $link['context'] == 'talk' ) {
378 - $xmlID = 'ca-talk';
379 - } else {
380 - $xmlID = 'ca-' . $xmlID;
 94+ if ( $section == "views" && !(isset($link["primary"]) && $link["primary"]) ) {
 95+ $link['class'] = rtrim('collapsible ' . $link['class'], ' ');
38196 }
 97+
 98+ $xmlID = isset($link["id"]) ? $link["id"] : 'ca-' . $xmlID;
38299 $nav[$section][$key]['attributes'] =
383100 ' id="' . Sanitizer::escapeId( $xmlID ) . '"';
384 - if ( $nav[$section][$key]['class'] ) {
 101+ if ( $link['class'] ) {
385102 $nav[$section][$key]['attributes'] .=
386103 ' class="' . htmlspecialchars( $link['class'] ) . '"';
387104 unset( $nav[$section][$key]['class'] );
388105 }
389 - // We don't want to give the watch tab an accesskey if the page
390 - // is being edited, because that conflicts with the accesskey on
391 - // the watch checkbox. We also don't want to give the edit tab
392 - // an accesskey, because that's fairly superfluous and conflicts
393 - // with an accesskey (Ctrl-E) often used for editing in Safari.
394 - if (
395 - in_array( $action, array( 'edit', 'submit' ) ) &&
396 - in_array( $key, array( 'edit', 'watch', 'unwatch' ) )
397 - ) {
 106+ if ( isset($link['tooltiponly']) && $link['tooltiponly'] ) {
398107 $nav[$section][$key]['key'] =
399108 $this->skin->tooltip( $xmlID );
400109 } else {
Index: trunk/phase3/skins/MonoBook.php
@@ -107,14 +107,7 @@
108108 echo ' class="'.htmlspecialchars($tab['class']).'"';
109109 }
110110 echo '><a href="'.htmlspecialchars($tab['href']).'"';
111 - # We don't want to give the watch tab an accesskey if the
112 - # page is being edited, because that conflicts with the
113 - # accesskey on the watch checkbox. We also don't want to
114 - # give the edit tab an accesskey, because that's fairly su-
115 - # perfluous and conflicts with an accesskey (Ctrl-E) often
116 - # used for editing in Safari.
117 - if( in_array( $action, array( 'edit', 'submit' ) )
118 - && in_array( $key, array( 'edit', 'watch', 'unwatch' ))) {
 111+ if( $tab["tooltiponly"] ) {
119112 echo $skin->tooltip( "ca-$key" );
120113 } else {
121114 echo $skin->tooltipAndAccesskey( "ca-$key" );
Index: trunk/phase3/docs/hooks.txt
@@ -1488,24 +1488,14 @@
14891489 If true is returned, $subpages will be ignored and the rest of
14901490 subPageSubtitle() will run.
14911491
1492 -'SkinTemplateBuildContentActionUrlsAfterSpecialPage': after the single tab
1493 -when showing a special page
1494 -$sktemplate: SkinTemplate object
1495 -$content_actions: array of tabs
1496 -
14971492 'SkinTemplateBuildNavUrlsNav_urlsAfterPermalink': after creating the
14981493 "permanent link" tab
14991494 $sktemplate: SkinTemplate object
15001495 $nav_urls: array of tabs
15011496
1502 -'SkinTemplateContentActions': Alter the "content action" links in SkinTemplates
1503 -&$content_actions: Content actions
1504 -[See http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/examples/Content_action.php
1505 -for an example]
1506 -
15071497 Alter the structured navigation links in SkinTemplates, there are three of these hooks called in different spots.
1508 -'SkinTemplateNavigation': Called on content pages before variants have been added
1509 -'SkinTemplateNavigation::SpecialPage': Called on special pages before variands have been added
 1498+'SkinTemplateNavigation': Called on content pages after the tabs have been added but before before variants have been added
 1499+'SkinTemplateNavigation::SpecialPage': Called on special pages after the special tab is added but before variants have been added
15101500 'SkinTemplateNavigation::Universal': Called on both content and special pages after variants have been added
15111501 &$sktemplate: SkinTemplate object
15121502 &$links: Structured navigation links
@@ -1536,10 +1526,6 @@
15371527 &$text: Link text.
15381528 &$result: Complete assoc. array if you want to return true.
15391529
1540 -'SkinTemplateTabs': called when finished to build the actions tabs
1541 -$sktemplate: SkinTemplate object
1542 -$content_actions: array of tabs
1543 -
15441530 'SkinTemplateToolboxEnd': Called by SkinTemplate skins after toolbox links have
15451531 been rendered (useful for adding more)
15461532 $tools: array of tools
Index: trunk/phase3/includes/GlobalFunctions.php
@@ -596,6 +596,26 @@
597597 }
598598
599599 /**
 600+ * This function accepts multiple message keys and returns a message instance
 601+ * for the first message which is non-empty. If all messages are empty then an
 602+ * instance of the first message key is returned.
 603+ * Varargs: message keys
 604+ * @return \type{Message}
 605+ * @since 1.18
 606+ */
 607+function wfMessageFallback( /*...*/ ) {
 608+ $keys = func_get_args();
 609+ $first = $keys[0];
 610+ foreach ( $keys as $key ) {
 611+ if ( wfEmptyMsg( $key ) ) {
 612+ continue;
 613+ }
 614+ return wfMessage( $key );
 615+ }
 616+ return wfMessage( $first );
 617+}
 618+
 619+/**
600620 * Get a message from anywhere, for the current user language.
601621 *
602622 * Use wfMsgForContent() instead if the message should NOT
Index: trunk/phase3/includes/SkinTemplate.php
@@ -495,7 +495,9 @@
496496 wfProfileIn( __METHOD__ . '-stuff5' );
497497 # Personal toolbar
498498 $tpl->set( 'personal_urls', $this->buildPersonalUrls() );
499 - $content_actions = $this->buildContentActionUrls();
 499+ $content_navigation = $this->buildContentNavigationUrls();
 500+ $content_actions = $this->buildContentActionUrls( $content_navigation );
 501+ $tpl->setRef( 'content_navigation', $content_navigation );
500502 $tpl->setRef( 'content_actions', $content_actions );
501503
502504 $tpl->set( 'sidebar', $this->buildSidebar() );
@@ -720,7 +722,8 @@
721723 return array(
722724 'class' => implode( ' ', $classes ),
723725 'text' => $text,
724 - 'href' => $title->getLocalUrl( $query ) );
 726+ 'href' => $title->getLocalUrl( $query ),
 727+ 'primary' => true );
725728 }
726729
727730 function makeTalkUrlDetails( $name, $urlaction = '' ) {
@@ -747,204 +750,363 @@
748751 }
749752
750753 /**
751 - * an array of edit links by default used for the tabs
 754+ * a structured array of links usually used for the tabs in a skin
 755+ *
 756+ * There are 4 standard sections
 757+ * namespaces: Used for namespace tabs like special, page, and talk namespaces
 758+ * views: Used for primary page views like read, edit, history
 759+ * actions: Used for most extra page actions like deletion, protection, etc...
 760+ * variants: Used to list the language variants for the page
 761+ *
 762+ * Each section's value is a key/value array of links for that section.
 763+ * The links themseves have these common keys:
 764+ * - class: The css classes to apply to the tab
 765+ * - text: The text to display on the tab
 766+ * - href: The href for the tab to point to
 767+ * - rel: An optional rel= for the tab's link
 768+ * - redundant: If true the tab will be dropped in skins using content_actions
 769+ * this is useful for tabs like "Read" which only have meaning in skins that
 770+ * take special meaning from the grouped structure of content_navigation
 771+ *
 772+ * Views also have an extra key which can be used:
 773+ * - primary: If this is not true skins like vector may try to hide the tab
 774+ * when the user has limited space in their browser window
 775+ *
 776+ * content_navigation using code also expects these ids to be present on the
 777+ * links, however these are usually automatically generated by SkinTemplate
 778+ * itself and are not necessary when using a hook. The only things these may
 779+ * matter to are people modifying content_navigation after it's initial creation:
 780+ * - id: A "preferred" id, most skins are best off outputting this preferred id for best compatibility
 781+ * - tooltiponly: This is set to true for some tabs in cases where the system
 782+ * believes that the accesskey should not be added to the tab.
 783+ *
752784 * @return array
753785 * @private
754786 */
755 - function buildContentActionUrls() {
 787+ function buildContentNavigationUrls() {
756788 global $wgContLang, $wgLang, $wgOut, $wgUser, $wgRequest, $wgArticle;
 789+ global $wgDisableLangConversion;
757790
758791 wfProfileIn( __METHOD__ );
 792+
 793+ $content_navigation = array(
 794+ 'namespaces' => array(),
 795+ 'views' => array(),
 796+ 'actions' => array(),
 797+ 'variants' => array()
 798+ );
759799
 800+ // parameters
760801 $action = $wgRequest->getVal( 'action', 'view' );
761802 $section = $wgRequest->getVal( 'section' );
762 - $content_actions = array();
 803+
763804 $userCanRead = $this->mTitle->userCanRead();
 805+ $skname = $this->skinname;
764806
765 - $prevent_active_tabs = false;
766 - wfRunHooks( 'SkinTemplatePreventOtherActiveTabs', array( &$this, &$prevent_active_tabs ) );
 807+ $preventActiveTabs = false;
 808+ wfRunHooks( 'SkinTemplatePreventOtherActiveTabs', array( &$this, &$preventActiveTabs ) );
767809
 810+ // Checks if page is some kind of content
768811 if( $this->iscontent ) {
769 - $subjpage = $this->mTitle->getSubjectPage();
770 - $talkpage = $this->mTitle->getTalkPage();
 812+ // Gets page objects for the related namespaces
 813+ $subjectPage = $this->mTitle->getSubjectPage();
 814+ $talkPage = $this->mTitle->getTalkPage();
771815
772 - $nskey = $this->mTitle->getNamespaceKey();
773 - $content_actions[$nskey] = $this->tabAction(
774 - $subjpage,
775 - $nskey,
776 - !$this->mTitle->isTalkPage() && !$prevent_active_tabs,
777 - '', $userCanRead
778 - );
 816+ // Determines if this is a talk page
 817+ $isTalk = $this->mTitle->isTalkPage();
779818
780 - $content_actions['talk'] = $this->tabAction(
781 - $talkpage,
782 - 'talk',
783 - $this->mTitle->isTalkPage() && !$prevent_active_tabs,
784 - '',
785 - $userCanRead
 819+ // Generates XML IDs from namespace names
 820+ $subjectId = $this->mTitle->getNamespaceKey( '' );
 821+
 822+ if ( $subjectId == 'main' ) {
 823+ $talkId = 'talk';
 824+ } else {
 825+ $talkId = "{$subjectId}_talk";
 826+ }
 827+
 828+ // Adds namespace links
 829+ $content_navigation['namespaces'][$subjectId] = $this->tabAction(
 830+ $subjectPage, 'nstab-' . $subjectId, !$isTalk && !$preventActiveTabs, '', $userCanRead
786831 );
 832+ $content_navigation['namespaces'][$subjectId]['context'] = 'subject';
 833+ $content_navigation['namespaces'][$talkId] = $this->tabAction(
 834+ $talkPage, 'talk', $isTalk && !$preventActiveTabs, '', $userCanRead
 835+ );
 836+ $content_navigation['namespaces'][$talkId]['context'] = 'talk';
787837
 838+ // Adds view view link
 839+ if ( $this->mTitle->exists() && $userCanRead ) {
 840+ $content_navigation['views']['view'] = $this->tabAction(
 841+ $isTalk ? $talkPage : $subjectPage,
 842+ !wfEmptyMsg( "$skname-view-view" ) ? "$skname-view-view" : 'view',
 843+ ( $action == 'view' ), '', true
 844+ );
 845+ $content_navigation['views']['view']['redundant'] = true; // signal to hide this from simple content_actions
 846+ }
 847+
788848 wfProfileIn( __METHOD__ . '-edit' );
789 - if ( $userCanRead && $this->mTitle->quickUserCan( 'edit' ) && ( $this->mTitle->exists() || $this->mTitle->quickUserCan( 'create' ) ) ) {
790 - $istalk = $this->mTitle->isTalkPage();
791 - $istalkclass = $istalk?' istalk':'';
792 - $content_actions['edit'] = array(
793 - 'class' => ( ( ( $action == 'edit' or $action == 'submit' ) and $section != 'new' ) ? 'selected' : '' ) . $istalkclass,
794 - 'text' => ( $this->mTitle->exists() || ( $this->mTitle->getNamespace() == NS_MEDIAWIKI && !wfEmptyMsg( $this->mTitle->getText() ) ) )
795 - ? wfMsg( 'edit' )
796 - : wfMsg( 'create' ),
797 - 'href' => $this->mTitle->getLocalUrl( $this->editUrlOptions() )
 849+
 850+ // Checks if user can...
 851+ if (
 852+ // read and edit the current page
 853+ $userCanRead && $this->mTitle->quickUserCan( 'edit' ) &&
 854+ (
 855+ // if it exists
 856+ $this->mTitle->exists() ||
 857+ // or they can create one here
 858+ $this->mTitle->quickUserCan( 'create' )
 859+ )
 860+ ) {
 861+ // Builds CSS class for talk page links
 862+ $isTalkClass = $isTalk ? ' istalk' : '';
 863+
 864+ // Determines if we're in edit mode
 865+ $selected = (
 866+ ( $action == 'edit' || $action == 'submit' ) &&
 867+ ( $section != 'new' )
798868 );
799 -
800 - // adds new section link if page is a current revision of a talk page or
801 - if ( ( $wgArticle && $wgArticle->isCurrent() && $istalk ) || $wgOut->showNewSectionLink() ) {
 869+ $msgKey = $this->mTitle->exists() || ( $this->mTitle->getNamespace() == NS_MEDIAWIKI && !wfEmptyMsg( $this->mTitle->getText() ) ) ?
 870+ "edit" : "create";
 871+ $content_navigation['views']['edit'] = array(
 872+ 'class' => ( $selected ? 'selected' : '' ) . $isTalkClass,
 873+ 'text' => wfMessageFallback( "$skname-view-$msgKey", $msgKey )->plain(),
 874+ 'href' => $this->mTitle->getLocalURL( $this->editUrlOptions() ),
 875+ 'primary' => true, // don't collapse this in vector
 876+ );
 877+ // Checks if this is a current rev of talk page and we should show a new
 878+ // section link
 879+ if ( ( $isTalk && $wgArticle && $wgArticle->isCurrent() ) || ( $wgOut->showNewSectionLink() ) ) {
 880+ // Checks if we should ever show a new section link
802881 if ( !$wgOut->forceHideNewSectionLink() ) {
803 - $content_actions['addsection'] = array(
 882+ // Adds new section link
 883+ //$content_navigation['actions']['addsection']
 884+ $content_navigation['views']['addsection'] = array(
804885 'class' => $section == 'new' ? 'selected' : false,
805 - 'text' => wfMsg( 'addsection' ),
806 - 'href' => $this->mTitle->getLocalUrl( 'action=edit&section=new' )
 886+ 'text' => wfMessageFallback( "$skname-action-addsection", 'addsection' )->plain(),
 887+ 'href' => $this->mTitle->getLocalURL( 'action=edit&section=new' )
807888 );
808889 }
809890 }
 891+ // Checks if the page has some kind of viewable content
810892 } elseif ( $this->mTitle->hasSourceText() && $userCanRead ) {
811 - $content_actions['viewsource'] = array(
812 - 'class' => ($action == 'edit') ? 'selected' : false,
813 - 'text' => wfMsg( 'viewsource' ),
814 - 'href' => $this->mTitle->getLocalUrl( $this->editUrlOptions() )
 893+ // Adds view source view link
 894+ $content_navigation['views']['viewsource'] = array(
 895+ 'class' => ( $action == 'edit' ) ? 'selected' : false,
 896+ 'text' => wfMessageFallback( "$skname-action-viewsource", 'viewsource' )->plain(),
 897+ 'href' => $this->mTitle->getLocalURL( $this->editUrlOptions() ),
 898+ 'primary' => true, // don't collapse this in vector
815899 );
816900 }
817901 wfProfileOut( __METHOD__ . '-edit' );
818902
819903 wfProfileIn( __METHOD__ . '-live' );
 904+
 905+ // Checks if the page exists
820906 if ( $this->mTitle->exists() && $userCanRead ) {
821 -
822 - $content_actions['history'] = array(
823 - 'class' => ($action == 'history') ? 'selected' : false,
824 - 'text' => wfMsg( 'history_short' ),
825 - 'href' => $this->mTitle->getLocalUrl( 'action=history' ),
 907+ // Adds history view link
 908+ $content_navigation['views']['history'] = array(
 909+ 'class' => ( $action == 'history' ) ? 'selected' : false,
 910+ 'text' => wfMessageFallback( "$skname-view-history", 'history_short' )->plain(),
 911+ 'href' => $this->mTitle->getLocalURL( 'action=history' ),
826912 'rel' => 'archives',
827913 );
828914
829915 if( $wgUser->isAllowed( 'delete' ) ) {
830 - $content_actions['delete'] = array(
831 - 'class' => ($action == 'delete') ? 'selected' : false,
832 - 'text' => wfMsg( 'delete' ),
833 - 'href' => $this->mTitle->getLocalUrl( 'action=delete' )
 916+ $content_navigation['actions']['delete'] = array(
 917+ 'class' => ( $action == 'delete' ) ? 'selected' : false,
 918+ 'text' => wfMessageFallback( "$skname-action-delete", 'delete' )->plain(),
 919+ 'href' => $this->mTitle->getLocalURL( 'action=delete' )
834920 );
835921 }
836922 if ( $this->mTitle->quickUserCan( 'move' ) ) {
837923 $moveTitle = SpecialPage::getTitleFor( 'Movepage', $this->thispage );
838 - $content_actions['move'] = array(
 924+ $content_navigation['actions']['move'] = array(
839925 'class' => $this->mTitle->isSpecial( 'Movepage' ) ? 'selected' : false,
840 - 'text' => wfMsg( 'move' ),
841 - 'href' => $moveTitle->getLocalUrl()
 926+ 'text' => wfMessageFallback( "$skname-action-move", 'move' )->plain(),
 927+ 'href' => $moveTitle->getLocalURL()
842928 );
843929 }
844930
845931 if ( $this->mTitle->getNamespace() !== NS_MEDIAWIKI && $wgUser->isAllowed( 'protect' ) ) {
846 - if( !$this->mTitle->isProtected() ){
847 - $content_actions['protect'] = array(
848 - 'class' => ($action == 'protect') ? 'selected' : false,
849 - 'text' => wfMsg( 'protect' ),
850 - 'href' => $this->mTitle->getLocalUrl( 'action=protect' )
851 - );
852 -
853 - } else {
854 - $content_actions['unprotect'] = array(
855 - 'class' => ($action == 'unprotect') ? 'selected' : false,
856 - 'text' => wfMsg( 'unprotect' ),
857 - 'href' => $this->mTitle->getLocalUrl( 'action=unprotect' )
858 - );
859 - }
 932+ $mode = !$this->mTitle->isProtected() ? 'protect' : 'unprotect';
 933+ $content_navigation['actions'][$mode] = array(
 934+ 'class' => ( $action == $mode ) ? 'selected' : false,
 935+ 'text' => wfMessageFallback( "$skname-action-$mode", $mode )->plain(),
 936+ 'href' => $this->mTitle->getLocalURL( "action=$mode" )
 937+ );
860938 }
861939 } else {
862 - //article doesn't exist or is deleted
863 - if( $wgUser->isAllowed( 'deletedhistory' ) && $wgUser->isAllowed( 'deletedtext' ) ) {
 940+ // article doesn't exist or is deleted
 941+ if ( $wgUser->isAllowed( 'deletedhistory' ) ) {
864942 $n = $this->mTitle->isDeleted();
865943 if( $n ) {
866944 $undelTitle = SpecialPage::getTitleFor( 'Undelete' );
867 - $content_actions['undelete'] = array(
 945+ // If the user can't undelete but can view deleted history show them a "View .. deleted" tab instead
 946+ $msgKey = $wgUser->isAllowed( 'undelete' ) ? 'undelete' : 'viewdeleted';
 947+ $content_navigation['actions']['undelete'] = array(
868948 'class' => false,
869 - 'text' => wfMsgExt( 'undelete_short', array( 'parsemag' ), $wgLang->formatNum( $n ) ),
870 - 'href' => $undelTitle->getLocalUrl( 'target=' . urlencode( $this->thispage ) )
871 - #'href' => self::makeSpecialUrl( "Undelete/$this->thispage" )
 949+ 'text' => wfMessageFallback( "$skname-action-$msgKey", "{$msgKey}_short" )
 950+ ->params( $wgLang->formatNum( $n ) )->text(),
 951+ 'href' => $undelTitle->getLocalURL( array( 'target' => $this->thispage ) )
872952 );
873953 }
874954 }
875955
876956 if ( $this->mTitle->getNamespace() !== NS_MEDIAWIKI && $wgUser->isAllowed( 'protect' ) ) {
877 - if( !$this->mTitle->getRestrictions( 'create' ) ) {
878 - $content_actions['protect'] = array(
879 - 'class' => ($action == 'protect') ? 'selected' : false,
880 - 'text' => wfMsg( 'protect' ),
881 - 'href' => $this->mTitle->getLocalUrl( 'action=protect' )
882 - );
883 -
884 - } else {
885 - $content_actions['unprotect'] = array(
886 - 'class' => ($action == 'unprotect') ? 'selected' : false,
887 - 'text' => wfMsg( 'unprotect' ),
888 - 'href' => $this->mTitle->getLocalUrl( 'action=unprotect' )
889 - );
890 - }
 957+ $mode = !$this->mTitle->getRestrictions( 'create' ) ? 'protect' : 'unprotect';
 958+ $content_navigation['actions'][$mode] = array(
 959+ 'class' => ( $action == $mode ) ? 'selected' : false,
 960+ 'text' => wfMessageFallback( "$skname-action-$mode", $mode )->plain(),
 961+ 'href' => $this->mTitle->getLocalURL( "action=$mode" )
 962+ );
891963 }
892964 }
893 -
894965 wfProfileOut( __METHOD__ . '-live' );
895966
896 - if( $this->loggedin ) {
897 - if( !$this->mTitle->userIsWatching()) {
898 - $content_actions['watch'] = array(
899 - 'class' => ($action == 'watch' or $action == 'unwatch') ? 'selected' : false,
900 - 'text' => wfMsg( 'watch' ),
901 - 'href' => $this->mTitle->getLocalUrl( 'action=watch' )
902 - );
903 - } else {
904 - $content_actions['unwatch'] = array(
905 - 'class' => ($action == 'unwatch' or $action == 'watch') ? 'selected' : false,
906 - 'text' => wfMsg( 'unwatch' ),
907 - 'href' => $this->mTitle->getLocalUrl( 'action=unwatch' )
908 - );
909 - }
 967+ // Checks if the user is logged in
 968+ if ( $this->loggedin ) {
 969+ /**
 970+ * The following actions use messages which, if made particular to
 971+ * the any specific skins, would break the Ajax code which makes this
 972+ * action happen entirely inline. Skin::makeGlobalVariablesScript
 973+ * defines a set of messages in a javascript object - and these
 974+ * messages are assumed to be global for all skins. Without making
 975+ * a change to that procedure these messages will have to remain as
 976+ * the global versions.
 977+ */
 978+ $mode = $this->mTitle->userIsWatching() ? 'unwatch' : 'watch';
 979+ $content_navigation['actions'][$mode] = array(
 980+ 'class' => ( $action == 'watch' || $action == 'unwatch' ) ? 'selected' : false,
 981+ 'text' => wfMsg( $mode ), // uses 'watch' or 'unwatch' message
 982+ 'href' => $this->mTitle->getLocalURL( 'action=' . $mode )
 983+ );
910984 }
911 -
912 -
913 - wfRunHooks( 'SkinTemplateTabs', array( $this, &$content_actions ) );
 985+
 986+ wfRunHooks( 'SkinTemplateNavigation', array( &$this, &$content_navigation ) );
914987 } else {
915 - /* show special page tab */
916 -
917 - $content_actions[$this->mTitle->getNamespaceKey()] = array(
 988+ // If it's not content, it's got to be a special page
 989+ $content_navigation['namespaces']['special'] = array(
918990 'class' => 'selected',
919 - 'text' => wfMsg('nstab-special'),
 991+ 'text' => wfMsg( 'nstab-special' ),
920992 'href' => $wgRequest->getRequestURL(), // @bug 2457, 2510
 993+ 'context' => 'subject'
921994 );
922 -
923 - wfRunHooks( 'SkinTemplateBuildContentActionUrlsAfterSpecialPage', array( &$this, &$content_actions ) );
 995+
 996+ wfRunHooks( 'SkinTemplateNavigation::SpecialPage', array( &$this, &$content_navigation ) );
924997 }
925998
926 - /* show links to different language variants */
927 - global $wgDisableLangConversion;
 999+ // Gets list of language variants
9281000 $variants = $wgContLang->getVariants();
929 - if( !$wgDisableLangConversion && sizeof( $variants ) > 1 ) {
 1001+ // Checks that language conversion is enabled and variants exist
 1002+ if( !$wgDisableLangConversion && count( $variants ) > 1 ) {
 1003+ // Gets preferred variant
9301004 $preferred = $wgContLang->getPreferredVariant();
931 - $vcount=0;
 1005+ // Loops over each variant
9321006 foreach( $variants as $code ) {
 1007+ // Gets variant name from language code
9331008 $varname = $wgContLang->getVariantname( $code );
934 - if( $varname == 'disable' )
 1009+ // Checks if the variant is marked as disabled
 1010+ if( $varname == 'disable' ) {
 1011+ // Skips this variant
9351012 continue;
936 - $selected = ( $code == $preferred )? 'selected' : false;
937 - $content_actions['varlang-' . $vcount] = array(
938 - 'class' => $selected,
 1013+ }
 1014+ // Appends variant link
 1015+ $content_navigation['variants'][] = array(
 1016+ 'class' => ( $code == $preferred ) ? 'selected' : false,
9391017 'text' => $varname,
9401018 'href' => $this->mTitle->getLocalURL( '', $code )
9411019 );
942 - $vcount ++;
9431020 }
9441021 }
9451022
946 - wfRunHooks( 'SkinTemplateContentActions', array( &$content_actions ) );
 1023+ // Equiv to SkinTemplateContentActions
 1024+ wfRunHooks( 'SkinTemplateNavigation::Universal', array( &$this, &$content_navigation ) );
9471025
 1026+ // Setup xml ids and tooltip info
 1027+ foreach ( $content_navigation as $section => &$links ) {
 1028+ foreach ( $links as $key => &$link ) {
 1029+ $xmlID = $key;
 1030+ if ( isset( $link['context'] ) && $link['context'] == 'subject' ) {
 1031+ $xmlID = 'ca-nstab-' . $xmlID;
 1032+ } elseif ( isset( $link['context'] ) && $link['context'] == 'talk' ) {
 1033+ $xmlID = 'ca-talk';
 1034+ } elseif ( $section == "variants" ) {
 1035+ $xmlID = 'ca-varlang-' . $xmlID;
 1036+ } else {
 1037+ $xmlID = 'ca-' . $xmlID;
 1038+ }
 1039+ $link['id'] = $xmlID;
 1040+ }
 1041+ }
 1042+
 1043+ # We don't want to give the watch tab an accesskey if the
 1044+ # page is being edited, because that conflicts with the
 1045+ # accesskey on the watch checkbox. We also don't want to
 1046+ # give the edit tab an accesskey, because that's fairly su-
 1047+ # perfluous and conflicts with an accesskey (Ctrl-E) often
 1048+ # used for editing in Safari.
 1049+ if( in_array( $action, array( 'edit', 'submit' ) ) ) {
 1050+ if ( isset($content_navigation['views']['edit']) ) {
 1051+ $content_navigation['views']['edit']['tooltiponly'] = true;
 1052+ }
 1053+ if ( isset($content_navigation['actions']['watch']) ) {
 1054+ $content_navigation['actions']['watch']['tooltiponly'] = true;
 1055+ }
 1056+ if ( isset($content_navigation['actions']['unwatch']) ) {
 1057+ $content_navigation['actions']['unwatch']['tooltiponly'] = true;
 1058+ }
 1059+ }
 1060+
9481061 wfProfileOut( __METHOD__ );
 1062+
 1063+ return $content_navigation;
 1064+ }
 1065+
 1066+ /**
 1067+ * an array of edit links by default used for the tabs
 1068+ * @return array
 1069+ * @private
 1070+ */
 1071+ function buildContentActionUrls( $content_navigation ) {
 1072+
 1073+ wfProfileIn( __METHOD__ );
 1074+
 1075+ // content_actions has been replaced with content_navigation for backwards
 1076+ // compatibility and also for skins that just want simple tabs content_actions
 1077+ // is now built by flattening the content_navigation arrays into one
 1078+
 1079+ $content_actions = array();
 1080+
 1081+ foreach ( $content_navigation as $section => $links ) {
 1082+
 1083+ foreach ( $links as $key => $value ) {
 1084+
 1085+ if ( isset($value["redundant"]) && $value["redundant"] ) {
 1086+ // Redundant tabs are dropped from content_actions
 1087+ continue;
 1088+ }
 1089+
 1090+ // content_actions used to have ids built using the "ca-$key" pattern
 1091+ // so the xmlID based id is much closer to the actual $key that we want
 1092+ // for that reason we'll just strip out the ca- if present and use
 1093+ // the latter potion of the "id" as the $key
 1094+ if ( isset($value["id"]) && substr($value["id"], 0, 3) == "ca-" ) {
 1095+ $key = substr($value["id"], 3);
 1096+ }
 1097+
 1098+ if ( isset($content_actions[$key]) ) {
 1099+ wfDebug( __METHOD__ . ": Found a duplicate key for $key while flattening content_navigation into content_actions." );
 1100+ continue;
 1101+ }
 1102+
 1103+ $content_actions[$key] = $value;
 1104+
 1105+ }
 1106+
 1107+ }
 1108+
 1109+ wfProfileOut( __METHOD__ );
 1110+
9491111 return $content_actions;
9501112 }
9511113
Index: trunk/phase3/languages/messages/MessagesEn.php
@@ -817,6 +817,7 @@
818818 'printableversion' => 'Printable version',
819819 'permalink' => 'Permanent link',
820820 'print' => 'Print',
 821+'view' => 'View',
821822 'edit' => 'Edit',
822823 'create' => 'Create',
823824 'editthispage' => 'Edit this page',
@@ -824,6 +825,7 @@
825826 'delete' => 'Delete',
826827 'deletethispage' => 'Delete this page',
827828 'undelete_short' => 'Undelete {{PLURAL:$1|one edit|$1 edits}}',
 829+'viewdeleted_short' => 'View {{PLURAL:$1|one deleted edit|$1 deleted edits}}',
828830 'protect' => 'Protect',
829831 'protect_change' => 'change',
830832 'protectthispage' => 'Protect this page',

Follow-up revisions

RevisionCommit summaryAuthorDate
r79389Followup r79383, missing message documentation.dantman23:48, 31 December 2010
r79397Fix php notice in vector from r79383.dantman00:59, 1 January 2011
r80241Fix r79383, I used Message->plain() under the impression it was the proper re...dantman09:28, 14 January 2011
r92713RELEASE-NOTES for r79383catrope23:44, 20 July 2011

Comments

#Comment by Krinkle (talk | contribs)   23:36, 31 December 2010

I'm haven't checked the actual file but I believe a /qqq entry for message view and viewdeleted_short is missing. Especially with a key as short as "view" an explaination as to where this message is used is extremely important for translators.

See for example: http://translatewiki.net/wiki/MediaWiki:Vector-view-view/qqq

#Comment by Nikerabbit (talk | contribs)   09:45, 1 January 2011

Some of the comments are a bit redundant, but then I noticed that you didn't add them in the first place.

- // Gets preferred variant
- $preferred = $wgContLang->getPreferredVariant();

In wfMessageFallback you could use $msg = wfMessage( ... ); if !$msg->exists() to avoid double calls to message cache.

And yay for code removing big chunk of duplicated code!

#Comment by IAlex (talk | contribs)   16:02, 27 January 2011

SkinTemplateTabs hook is still called in Skin.php.

#Comment by Dantman (talk | contribs)   20:48, 2 February 2011
  • sigh* It is... the question is, do I perpetuate the hack by hacking in a SkinTemplateNavigation hook replacement (which itself is tricky and ugly). Or do I help port these old skins to SkinTemplate and we finally get rid of the old, old, old, style of skins.
#Comment by Nikerabbit (talk | contribs)   20:14, 20 March 2011

I think this causes bug 27764. If not you probably know best how to fix.

#Comment by Dantman (talk | contribs)   16:05, 26 March 2011

Note: That bug seams to already be marked as fixed.

#Comment by Reedy (talk | contribs)   18:05, 28 June 2011

RELEASE-NOTE are needed for the hook rename

#Comment by Catrope (talk | contribs)   23:45, 20 July 2011

RELEASE-NOTES added. There doesn't seem to be anything else wrong with this revision (bug 27764 is caused by misuse in an extension), so I'm marking it new.

#Comment by 😂 (talk | contribs)   21:30, 21 July 2011

You didn't mark it new. Doing that now :)

Status & tagging log