Merging Vector's navigation_urls and SkinTemplate's content_actions code into content...
authorDaniel Friesen <dantman@users.mediawiki.org>
Fri, 31 Dec 2010 23:30:00 +0000 (23:30 +0000)
committerDaniel Friesen <dantman@users.mediawiki.org>
Fri, 31 Dec 2010 23:30:00 +0000 (23:30 +0000)
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.

docs/hooks.txt
includes/GlobalFunctions.php
includes/SkinTemplate.php
languages/messages/MessagesEn.php
maintenance/language/messages.inc
skins/MonoBook.php
skins/Vector.php

index d166a24..1bd62b2 100644 (file)
@@ -1488,24 +1488,14 @@ subPageSubtitle() generates.
 If true is returned, $subpages will be ignored and the rest of
 subPageSubtitle() will run.
 
-'SkinTemplateBuildContentActionUrlsAfterSpecialPage': after the single tab
-when showing a special page
-$sktemplate: SkinTemplate object
-$content_actions: array of tabs
-
 'SkinTemplateBuildNavUrlsNav_urlsAfterPermalink': after creating the
 "permanent link" tab
 $sktemplate: SkinTemplate object
 $nav_urls: array of tabs
 
-'SkinTemplateContentActions': Alter the "content action" links in SkinTemplates
-&$content_actions: Content actions
-[See http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/examples/Content_action.php
-for an example]
-
 Alter the structured navigation links in SkinTemplates, there are three of these hooks called in different spots.
-'SkinTemplateNavigation': Called on content pages before variants have been added
-'SkinTemplateNavigation::SpecialPage': Called on special pages before variands have been added
+'SkinTemplateNavigation': Called on content pages after the tabs have been added but before before variants have been added
+'SkinTemplateNavigation::SpecialPage': Called on special pages after the special tab is added but before variants have been added
 'SkinTemplateNavigation::Universal': Called on both content and special pages after variants have been added
 &$sktemplate: SkinTemplate object
 &$links: Structured navigation links
@@ -1536,10 +1526,6 @@ $checkEdit: Whether or not the action=edit query should be added if appropriate.
 &$text: Link text.
 &$result: Complete assoc. array if you want to return true.
 
-'SkinTemplateTabs': called when finished to build the actions tabs
-$sktemplate: SkinTemplate object
-$content_actions: array of tabs
-
 'SkinTemplateToolboxEnd': Called by SkinTemplate skins after toolbox links have
 been rendered (useful for adding more)
 $tools: array of tools
index cf0c4b6..d636b44 100644 (file)
@@ -595,6 +595,26 @@ function wfMessage( $key /*...*/) {
        return new Message( $key, $params );
 }
 
+/**
+ * This function accepts multiple message keys and returns a message instance
+ * for the first message which is non-empty. If all messages are empty then an
+ * instance of the first message key is returned.
+ * Varargs: message keys
+ * @return \type{Message}
+ * @since 1.18
+ */
+function wfMessageFallback( /*...*/ ) {
+       $keys = func_get_args();
+       $first = $keys[0];
+       foreach ( $keys as $key ) {
+               if ( wfEmptyMsg( $key ) ) {
+                       continue;
+               }
+               return wfMessage( $key );
+       }
+       return wfMessage( $first );
+}
+
 /**
  * Get a message from anywhere, for the current user language.
  *
index f44bca3..60c52d6 100644 (file)
@@ -495,7 +495,9 @@ class SkinTemplate extends Skin {
                wfProfileIn( __METHOD__ . '-stuff5' );
                # Personal toolbar
                $tpl->set( 'personal_urls', $this->buildPersonalUrls() );
-               $content_actions = $this->buildContentActionUrls();
+               $content_navigation = $this->buildContentNavigationUrls();
+               $content_actions = $this->buildContentActionUrls( $content_navigation );
+               $tpl->setRef( 'content_navigation', $content_navigation );
                $tpl->setRef( 'content_actions', $content_actions );
 
                $tpl->set( 'sidebar', $this->buildSidebar() );
@@ -720,7 +722,8 @@ class SkinTemplate extends Skin {
                return array(
                        'class' => implode( ' ', $classes ),
                        'text' => $text,
-                       'href' => $title->getLocalUrl( $query ) );
+                       'href' => $title->getLocalUrl( $query ),
+                       'primary' => true );
        }
 
        function makeTalkUrlDetails( $name, $urlaction = '' ) {
@@ -747,204 +750,363 @@ class SkinTemplate extends Skin {
        }
 
        /**
-        * an array of edit links by default used for the tabs
+        * a structured array of links usually used for the tabs in a skin
+        * 
+        * There are 4 standard sections
+        * namespaces: Used for namespace tabs like special, page, and talk namespaces
+        * views: Used for primary page views like read, edit, history
+        * actions: Used for most extra page actions like deletion, protection, etc...
+        * variants: Used to list the language variants for the page
+        * 
+        * Each section's value is a key/value array of links for that section.
+        * The links themseves have these common keys:
+        * - class: The css classes to apply to the tab
+        * - text: The text to display on the tab
+        * - href: The href for the tab to point to
+        * - rel: An optional rel= for the tab's link
+        * - redundant: If true the tab will be dropped in skins using content_actions
+        *   this is useful for tabs like "Read" which only have meaning in skins that
+        *   take special meaning from the grouped structure of content_navigation
+        * 
+        * Views also have an extra key which can be used:
+        * - primary: If this is not true skins like vector may try to hide the tab
+        *            when the user has limited space in their browser window
+        * 
+        * content_navigation using code also expects these ids to be present on the
+        * links, however these are usually automatically generated by SkinTemplate
+        * itself and are not necessary when using a hook. The only things these may
+        * matter to are people modifying content_navigation after it's initial creation:
+        * - id: A "preferred" id, most skins are best off outputting this preferred id for best compatibility
+        * - tooltiponly: This is set to true for some tabs in cases where the system
+        *                believes that the accesskey should not be added to the tab.
+        * 
         * @return array
         * @private
         */
-       function buildContentActionUrls() {
+       function buildContentNavigationUrls() {
                global $wgContLang, $wgLang, $wgOut, $wgUser, $wgRequest, $wgArticle;
+               global $wgDisableLangConversion;
 
                wfProfileIn( __METHOD__ );
+               
+               $content_navigation = array(
+                       'namespaces' => array(),
+                       'views' => array(),
+                       'actions' => array(),
+                       'variants' => array()
+               );
 
+               // parameters
                $action = $wgRequest->getVal( 'action', 'view' );
                $section = $wgRequest->getVal( 'section' );
-               $content_actions = array();
+
                $userCanRead = $this->mTitle->userCanRead();
+               $skname = $this->skinname;
 
-               $prevent_active_tabs = false;
-               wfRunHooks( 'SkinTemplatePreventOtherActiveTabs', array( &$this, &$prevent_active_tabs ) );
+               $preventActiveTabs = false;
+               wfRunHooks( 'SkinTemplatePreventOtherActiveTabs', array( &$this, &$preventActiveTabs ) );
 
+               // Checks if page is some kind of content
                if( $this->iscontent ) {
-                       $subjpage = $this->mTitle->getSubjectPage();
-                       $talkpage = $this->mTitle->getTalkPage();
-
-                       $nskey = $this->mTitle->getNamespaceKey();
-                       $content_actions[$nskey] = $this->tabAction(
-                               $subjpage,
-                               $nskey,
-                               !$this->mTitle->isTalkPage() && !$prevent_active_tabs,
-                               '', $userCanRead
-                       );
+                       // Gets page objects for the related namespaces
+                       $subjectPage = $this->mTitle->getSubjectPage();
+                       $talkPage = $this->mTitle->getTalkPage();
+
+                       // Determines if this is a talk page
+                       $isTalk = $this->mTitle->isTalkPage();
+
+                       // Generates XML IDs from namespace names
+                       $subjectId = $this->mTitle->getNamespaceKey( '' );
 
-                       $content_actions['talk'] = $this->tabAction(
-                               $talkpage,
-                               'talk',
-                               $this->mTitle->isTalkPage() && !$prevent_active_tabs,
-                               '',
-                               $userCanRead
+                       if ( $subjectId == 'main' ) {
+                               $talkId = 'talk';
+                       } else {
+                               $talkId = "{$subjectId}_talk";
+                       }
+
+                       // Adds namespace links
+                       $content_navigation['namespaces'][$subjectId] = $this->tabAction(
+                               $subjectPage, 'nstab-' . $subjectId, !$isTalk && !$preventActiveTabs, '', $userCanRead
+                       );
+                       $content_navigation['namespaces'][$subjectId]['context'] = 'subject';
+                       $content_navigation['namespaces'][$talkId] = $this->tabAction(
+                               $talkPage, 'talk', $isTalk && !$preventActiveTabs, '', $userCanRead
                        );
+                       $content_navigation['namespaces'][$talkId]['context'] = 'talk';
 
-                       wfProfileIn( __METHOD__ . '-edit' );
-                       if ( $userCanRead && $this->mTitle->quickUserCan( 'edit' ) && ( $this->mTitle->exists() || $this->mTitle->quickUserCan( 'create' ) ) ) {
-                               $istalk = $this->mTitle->isTalkPage();
-                               $istalkclass = $istalk?' istalk':'';
-                               $content_actions['edit'] = array(
-                                       'class' => ( ( ( $action == 'edit' or $action == 'submit' ) and $section != 'new' ) ? 'selected' : '' ) . $istalkclass,
-                                       'text' => ( $this->mTitle->exists() || ( $this->mTitle->getNamespace() == NS_MEDIAWIKI && !wfEmptyMsg( $this->mTitle->getText() ) ) )
-                                               ? wfMsg( 'edit' )
-                                               : wfMsg( 'create' ),
-                                       'href' => $this->mTitle->getLocalUrl( $this->editUrlOptions() )
+                       // Adds view view link
+                       if ( $this->mTitle->exists() && $userCanRead ) {
+                               $content_navigation['views']['view'] = $this->tabAction(
+                                       $isTalk ? $talkPage : $subjectPage,
+                                       !wfEmptyMsg( "$skname-view-view" ) ? "$skname-view-view" : 'view',
+                                       ( $action == 'view' ), '', true
                                );
+                               $content_navigation['views']['view']['redundant'] = true; // signal to hide this from simple content_actions
+                       }
 
-                               // adds new section link if page is a current revision of a talk page or
-                               if ( ( $wgArticle && $wgArticle->isCurrent() && $istalk ) || $wgOut->showNewSectionLink() ) {
+                       wfProfileIn( __METHOD__ . '-edit' );
+
+                       // Checks if user can...
+                       if (
+                               // read and edit the current page
+                               $userCanRead && $this->mTitle->quickUserCan( 'edit' ) &&
+                               (
+                                       // if it exists
+                                       $this->mTitle->exists() ||
+                                       // or they can create one here
+                                       $this->mTitle->quickUserCan( 'create' )
+                               )
+                       ) {
+                               // Builds CSS class for talk page links
+                               $isTalkClass = $isTalk ? ' istalk' : '';
+
+                               // Determines if we're in edit mode
+                               $selected = (
+                                       ( $action == 'edit' || $action == 'submit' ) &&
+                                       ( $section != 'new' )
+                               );
+                               $msgKey = $this->mTitle->exists() || ( $this->mTitle->getNamespace() == NS_MEDIAWIKI && !wfEmptyMsg( $this->mTitle->getText() ) ) ?
+                                       "edit" : "create";
+                               $content_navigation['views']['edit'] = array(
+                                       'class' => ( $selected ? 'selected' : '' ) . $isTalkClass,
+                                       'text' => wfMessageFallback( "$skname-view-$msgKey", $msgKey )->plain(),
+                                       'href' => $this->mTitle->getLocalURL( $this->editUrlOptions() ),
+                                       'primary' => true, // don't collapse this in vector
+                               );
+                               // Checks if this is a current rev of talk page and we should show a new
+                               // section link
+                               if ( ( $isTalk && $wgArticle && $wgArticle->isCurrent() ) || ( $wgOut->showNewSectionLink() ) ) {
+                                       // Checks if we should ever show a new section link
                                        if ( !$wgOut->forceHideNewSectionLink() ) {
-                                               $content_actions['addsection'] = array(
+                                               // Adds new section link
+                                               //$content_navigation['actions']['addsection']
+                                               $content_navigation['views']['addsection'] = array(
                                                        'class' => $section == 'new' ? 'selected' : false,
-                                                       'text' => wfMsg( 'addsection' ),
-                                                       'href' => $this->mTitle->getLocalUrl( 'action=edit&section=new' )
+                                                       'text' => wfMessageFallback( "$skname-action-addsection", 'addsection' )->plain(),
+                                                       'href' => $this->mTitle->getLocalURL( 'action=edit&section=new' )
                                                );
                                        }
                                }
+                       // Checks if the page has some kind of viewable content
                        } elseif ( $this->mTitle->hasSourceText() && $userCanRead ) {
-                               $content_actions['viewsource'] = array(
-                                       'class' => ($action == 'edit') ? 'selected' : false,
-                                       'text' => wfMsg( 'viewsource' ),
-                                       'href' => $this->mTitle->getLocalUrl( $this->editUrlOptions() )
+                               // Adds view source view link
+                               $content_navigation['views']['viewsource'] = array(
+                                       'class' => ( $action == 'edit' ) ? 'selected' : false,
+                                       'text' => wfMessageFallback( "$skname-action-viewsource", 'viewsource' )->plain(),
+                                       'href' => $this->mTitle->getLocalURL( $this->editUrlOptions() ),
+                                       'primary' => true, // don't collapse this in vector
                                );
                        }
                        wfProfileOut( __METHOD__ . '-edit' );
 
                        wfProfileIn( __METHOD__ . '-live' );
-                       if ( $this->mTitle->exists() && $userCanRead ) {
 
-                               $content_actions['history'] = array(
-                                       'class' => ($action == 'history') ? 'selected' : false,
-                                       'text' => wfMsg( 'history_short' ),
-                                       'href' => $this->mTitle->getLocalUrl( 'action=history' ),
+                       // Checks if the page exists
+                       if ( $this->mTitle->exists() && $userCanRead ) {
+                               // Adds history view link
+                               $content_navigation['views']['history'] = array(
+                                       'class' => ( $action == 'history' ) ? 'selected' : false,
+                                       'text' => wfMessageFallback( "$skname-view-history", 'history_short' )->plain(),
+                                       'href' => $this->mTitle->getLocalURL( 'action=history' ),
                                        'rel' => 'archives',
                                );
 
                                if( $wgUser->isAllowed( 'delete' ) ) {
-                                       $content_actions['delete'] = array(
-                                               'class' => ($action == 'delete') ? 'selected' : false,
-                                               'text' => wfMsg( 'delete' ),
-                                               'href' => $this->mTitle->getLocalUrl( 'action=delete' )
+                                       $content_navigation['actions']['delete'] = array(
+                                               'class' => ( $action == 'delete' ) ? 'selected' : false,
+                                               'text' => wfMessageFallback( "$skname-action-delete", 'delete' )->plain(),
+                                               'href' => $this->mTitle->getLocalURL( 'action=delete' )
                                        );
                                }
                                if ( $this->mTitle->quickUserCan( 'move' ) ) {
                                        $moveTitle = SpecialPage::getTitleFor( 'Movepage', $this->thispage );
-                                       $content_actions['move'] = array(
+                                       $content_navigation['actions']['move'] = array(
                                                'class' => $this->mTitle->isSpecial( 'Movepage' ) ? 'selected' : false,
-                                               'text' => wfMsg( 'move' ),
-                                               'href' => $moveTitle->getLocalUrl()
+                                               'text' => wfMessageFallback( "$skname-action-move", 'move' )->plain(),
+                                               'href' => $moveTitle->getLocalURL()
                                        );
                                }
 
                                if ( $this->mTitle->getNamespace() !== NS_MEDIAWIKI && $wgUser->isAllowed( 'protect' ) ) {
-                                       if( !$this->mTitle->isProtected() ){
-                                               $content_actions['protect'] = array(
-                                                       'class' => ($action == 'protect') ? 'selected' : false,
-                                                       'text' => wfMsg( 'protect' ),
-                                                       'href' => $this->mTitle->getLocalUrl( 'action=protect' )
-                                               );
-
-                                       } else {
-                                               $content_actions['unprotect'] = array(
-                                                       'class' => ($action == 'unprotect') ? 'selected' : false,
-                                                       'text' => wfMsg( 'unprotect' ),
-                                                       'href' => $this->mTitle->getLocalUrl( 'action=unprotect' )
-                                               );
-                                       }
+                                       $mode = !$this->mTitle->isProtected() ? 'protect' : 'unprotect';
+                                       $content_navigation['actions'][$mode] = array(
+                                               'class' => ( $action == $mode ) ? 'selected' : false,
+                                               'text' => wfMessageFallback( "$skname-action-$mode", $mode )->plain(),
+                                               'href' => $this->mTitle->getLocalURL( "action=$mode" )
+                                       );
                                }
                        } else {
-                               //article doesn't exist or is deleted
-                               if( $wgUser->isAllowed( 'deletedhistory' ) && $wgUser->isAllowed( 'deletedtext' ) ) {
+                               // article doesn't exist or is deleted
+                               if ( $wgUser->isAllowed( 'deletedhistory' ) ) {
                                        $n = $this->mTitle->isDeleted();
                                        if( $n ) {
                                                $undelTitle = SpecialPage::getTitleFor( 'Undelete' );
-                                               $content_actions['undelete'] = array(
+                                               // If the user can't undelete but can view deleted history show them a "View .. deleted" tab instead
+                                               $msgKey = $wgUser->isAllowed( 'undelete' ) ? 'undelete' : 'viewdeleted';
+                                               $content_navigation['actions']['undelete'] = array(
                                                        'class' => false,
-                                                       'text' => wfMsgExt( 'undelete_short', array( 'parsemag' ), $wgLang->formatNum( $n ) ),
-                                                       'href' => $undelTitle->getLocalUrl( 'target=' . urlencode( $this->thispage ) )
-                                                       #'href' => self::makeSpecialUrl( "Undelete/$this->thispage" )
+                                                       'text' => wfMessageFallback( "$skname-action-$msgKey", "{$msgKey}_short" )
+                                                               ->params( $wgLang->formatNum( $n ) )->text(),
+                                                       'href' => $undelTitle->getLocalURL( array( 'target' => $this->thispage ) )
                                                );
                                        }
                                }
 
                                if ( $this->mTitle->getNamespace() !== NS_MEDIAWIKI && $wgUser->isAllowed( 'protect' ) ) {
-                                       if( !$this->mTitle->getRestrictions( 'create' ) ) {
-                                               $content_actions['protect'] = array(
-                                                       'class' => ($action == 'protect') ? 'selected' : false,
-                                                       'text' => wfMsg( 'protect' ),
-                                                       'href' => $this->mTitle->getLocalUrl( 'action=protect' )
-                                               );
-
-                                       } else {
-                                               $content_actions['unprotect'] = array(
-                                                       'class' => ($action == 'unprotect') ? 'selected' : false,
-                                                       'text' => wfMsg( 'unprotect' ),
-                                                       'href' => $this->mTitle->getLocalUrl( 'action=unprotect' )
-                                               );
-                                       }
+                                       $mode = !$this->mTitle->getRestrictions( 'create' ) ? 'protect' : 'unprotect';
+                                       $content_navigation['actions'][$mode] = array(
+                                               'class' => ( $action == $mode ) ? 'selected' : false,
+                                               'text' => wfMessageFallback( "$skname-action-$mode", $mode )->plain(),
+                                               'href' => $this->mTitle->getLocalURL( "action=$mode" )
+                                       );
                                }
                        }
-
                        wfProfileOut( __METHOD__ . '-live' );
 
-                       if( $this->loggedin ) {
-                               if( !$this->mTitle->userIsWatching()) {
-                                       $content_actions['watch'] = array(
-                                               'class' => ($action == 'watch' or $action == 'unwatch') ? 'selected' : false,
-                                               'text' => wfMsg( 'watch' ),
-                                               'href' => $this->mTitle->getLocalUrl( 'action=watch' )
-                                       );
-                               } else {
-                                       $content_actions['unwatch'] = array(
-                                               'class' => ($action == 'unwatch' or $action == 'watch') ? 'selected' : false,
-                                               'text' => wfMsg( 'unwatch' ),
-                                               'href' => $this->mTitle->getLocalUrl( 'action=unwatch' )
-                                       );
-                               }
+                       // Checks if the user is logged in
+                       if ( $this->loggedin ) {
+                               /**
+                                * The following actions use messages which, if made particular to
+                                * the any specific skins, would break the Ajax code which makes this
+                                * action happen entirely inline. Skin::makeGlobalVariablesScript
+                                * defines a set of messages in a javascript object - and these
+                                * messages are assumed to be global for all skins. Without making
+                                * a change to that procedure these messages will have to remain as
+                                * the global versions.
+                                */
+                               $mode = $this->mTitle->userIsWatching() ? 'unwatch' : 'watch';
+                               $content_navigation['actions'][$mode] = array(
+                                       'class' => ( $action == 'watch' || $action == 'unwatch' ) ? 'selected' : false,
+                                       'text' => wfMsg( $mode ), // uses 'watch' or 'unwatch' message
+                                       'href' => $this->mTitle->getLocalURL( 'action=' . $mode )
+                               );
                        }
-
-
-                       wfRunHooks( 'SkinTemplateTabs', array( $this, &$content_actions ) );
+                       
+                       wfRunHooks( 'SkinTemplateNavigation', array( &$this, &$content_navigation ) );
                } else {
-                       /* show special page tab */
-
-                       $content_actions[$this->mTitle->getNamespaceKey()] = array(
+                       // If it's not content, it's got to be a special page
+                       $content_navigation['namespaces']['special'] = array(
                                'class' => 'selected',
-                               'text' => wfMsg('nstab-special'),
+                               'text' => wfMsg( 'nstab-special' ),
                                'href' => $wgRequest->getRequestURL(), // @bug 2457, 2510
+                               'context' => 'subject'
                        );
-
-                       wfRunHooks( 'SkinTemplateBuildContentActionUrlsAfterSpecialPage', array( &$this, &$content_actions ) );
+                       
+                       wfRunHooks( 'SkinTemplateNavigation::SpecialPage', array( &$this, &$content_navigation ) );
                }
 
-               /* show links to different language variants */
-               global $wgDisableLangConversion;
+               // Gets list of language variants
                $variants = $wgContLang->getVariants();
-               if( !$wgDisableLangConversion && sizeof( $variants ) > 1 ) {
+               // Checks that language conversion is enabled and variants exist
+               if( !$wgDisableLangConversion && count( $variants ) > 1 ) {
+                       // Gets preferred variant
                        $preferred = $wgContLang->getPreferredVariant();
-                       $vcount=0;
+                       // Loops over each variant
                        foreach( $variants as $code ) {
+                               // Gets variant name from language code
                                $varname = $wgContLang->getVariantname( $code );
-                               if( $varname == 'disable' )
+                               // Checks if the variant is marked as disabled
+                               if( $varname == 'disable' ) {
+                                       // Skips this variant
                                        continue;
-                               $selected = ( $code == $preferred )? 'selected' : false;
-                               $content_actions['varlang-' . $vcount] = array(
-                                       'class' => $selected,
+                               }
+                               // Appends variant link
+                               $content_navigation['variants'][] = array(
+                                       'class' => ( $code == $preferred ) ? 'selected' : false,
                                        'text' => $varname,
                                        'href' => $this->mTitle->getLocalURL( '', $code )
                                );
-                               $vcount ++;
                        }
                }
 
-               wfRunHooks( 'SkinTemplateContentActions', array( &$content_actions ) );
+               // Equiv to SkinTemplateContentActions
+               wfRunHooks( 'SkinTemplateNavigation::Universal', array( &$this,  &$content_navigation ) );
+
+               // Setup xml ids and tooltip info
+               foreach ( $content_navigation as $section => &$links ) {
+                       foreach ( $links as $key => &$link ) {
+                               $xmlID = $key;
+                               if ( isset( $link['context'] ) && $link['context'] == 'subject' ) {
+                                       $xmlID = 'ca-nstab-' . $xmlID;
+                               } elseif ( isset( $link['context'] ) && $link['context'] == 'talk' ) {
+                                       $xmlID = 'ca-talk';
+                               } elseif ( $section == "variants" ) {
+                                       $xmlID = 'ca-varlang-' . $xmlID;
+                               } else {
+                                       $xmlID = 'ca-' . $xmlID;
+                               }
+                               $link['id'] = $xmlID;
+                       }
+               }
+               
+               # We don't want to give the watch tab an accesskey if the
+               # page is being edited, because that conflicts with the
+               # accesskey on the watch checkbox.  We also don't want to
+               # give the edit tab an accesskey, because that's fairly su-
+               # perfluous and conflicts with an accesskey (Ctrl-E) often
+               # used for editing in Safari.
+               if( in_array( $action, array( 'edit', 'submit' ) ) ) {
+                       if ( isset($content_navigation['views']['edit']) ) {
+                               $content_navigation['views']['edit']['tooltiponly'] = true;
+                       }
+                       if ( isset($content_navigation['actions']['watch']) ) {
+                               $content_navigation['actions']['watch']['tooltiponly'] = true;
+                       }
+                       if ( isset($content_navigation['actions']['unwatch']) ) {
+                               $content_navigation['actions']['unwatch']['tooltiponly'] = true;
+                       }
+               }
+               
+               wfProfileOut( __METHOD__ );
+
+               return $content_navigation;
+       }
 
+       /**
+        * an array of edit links by default used for the tabs
+        * @return array
+        * @private
+        */
+       function buildContentActionUrls( $content_navigation ) {
+
+               wfProfileIn( __METHOD__ );
+
+               // content_actions has been replaced with content_navigation for backwards
+               // compatibility and also for skins that just want simple tabs content_actions
+               // is now built by flattening the content_navigation arrays into one
+               
+               $content_actions = array();
+               
+               foreach ( $content_navigation as $section => $links ) {
+                       
+                       foreach ( $links as $key => $value ) {
+                               
+                               if ( isset($value["redundant"]) && $value["redundant"] ) {
+                                       // Redundant tabs are dropped from content_actions
+                                       continue;
+                               }
+                               
+                               // content_actions used to have ids built using the "ca-$key" pattern
+                               // so the xmlID based id is much closer to the actual $key that we want
+                               // for that reason we'll just strip out the ca- if present and use
+                               // the latter potion of the "id" as the $key
+                               if ( isset($value["id"]) && substr($value["id"], 0, 3) == "ca-" ) {
+                                       $key = substr($value["id"], 3);
+                               }
+                               
+                               if ( isset($content_actions[$key]) ) {
+                                       wfDebug( __METHOD__ . ": Found a duplicate key for $key while flattening content_navigation into content_actions." );
+                                       continue;
+                               }
+                               
+                               $content_actions[$key] = $value;
+                               
+                       }
+                       
+               }
+               
                wfProfileOut( __METHOD__ );
+               
                return $content_actions;
        }
 
index 8b1c6e8..efc8c73 100644 (file)
@@ -817,6 +817,7 @@ XHTML id names.
 'printableversion'  => 'Printable version',
 'permalink'         => 'Permanent link',
 'print'             => 'Print',
+'view'              => 'View',
 'edit'              => 'Edit',
 'create'            => 'Create',
 'editthispage'      => 'Edit this page',
@@ -824,6 +825,7 @@ XHTML id names.
 'delete'            => 'Delete',
 'deletethispage'    => 'Delete this page',
 'undelete_short'    => 'Undelete {{PLURAL:$1|one edit|$1 edits}}',
+'viewdeleted_short' => 'View {{PLURAL:$1|one deleted edit|$1 deleted edits}}',
 'protect'           => 'Protect',
 'protect_change'    => 'change',
 'protectthispage'   => 'Protect this page',
index 56b0e56..7b5eb6a 100644 (file)
@@ -221,6 +221,7 @@ $wgMessageStructure = array(
                'printableversion',
                'permalink',
                'print',
+               'view',
                'edit',
                'create',
                'editthispage',
@@ -228,6 +229,7 @@ $wgMessageStructure = array(
                'delete',
                'deletethispage',
                'undelete_short',
+               'viewdeleted_short',
                'protect',
                'protect_change',
                'protectthispage',
index ec13ed0..cfcce4b 100644 (file)
@@ -107,14 +107,7 @@ class MonoBookTemplate extends BaseTemplate {
                                                echo ' class="'.htmlspecialchars($tab['class']).'"';
                                        }
                                        echo '><a href="'.htmlspecialchars($tab['href']).'"';
-                                       # We don't want to give the watch tab an accesskey if the
-                                       # page is being edited, because that conflicts with the
-                                       # accesskey on the watch checkbox.  We also don't want to
-                                       # give the edit tab an accesskey, because that's fairly su-
-                                       # perfluous and conflicts with an accesskey (Ctrl-E) often
-                                       # used for editing in Safari.
-                                       if( in_array( $action, array( 'edit', 'submit' ) )
-                                       && in_array( $key, array( 'edit', 'watch', 'unwatch' ))) {
+                                       if( $tab["tooltiponly"] ) {
                                                echo $skin->tooltip( "ca-$key" );
                                        } else {
                                                echo $skin->tooltipAndAccesskey( "ca-$key" );
index 4181e01..2d812c7 100644 (file)
@@ -50,296 +50,6 @@ class SkinVector extends SkinTemplate {
                parent::setupSkinUserCss( $out );
                $out->addModuleStyles( 'skins.vector' );
        }
-
-       /**
-        * Builds a structured array of links used for tabs and menus
-        * @return array
-        * @private
-        */
-       function buildNavigationUrls() {
-               global $wgContLang, $wgLang, $wgOut, $wgUser, $wgRequest, $wgArticle;
-               global $wgDisableLangConversion, $wgVectorUseIconWatch;
-
-               wfProfileIn( __METHOD__ );
-
-               $links = array(
-                       'namespaces' => array(),
-                       'views' => array(),
-                       'actions' => array(),
-                       'variants' => array()
-               );
-
-               // Detects parameters
-               $action = $wgRequest->getVal( 'action', 'view' );
-               $section = $wgRequest->getVal( 'section' );
-
-               $userCanRead = $this->mTitle->userCanRead();
-
-               // Checks if page is some kind of content
-               if( $this->iscontent ) {
-                       // Gets page objects for the related namespaces
-                       $subjectPage = $this->mTitle->getSubjectPage();
-                       $talkPage = $this->mTitle->getTalkPage();
-
-                       // Determines if this is a talk page
-                       $isTalk = $this->mTitle->isTalkPage();
-
-                       // Generates XML IDs from namespace names
-                       $subjectId = $this->mTitle->getNamespaceKey( '' );
-
-                       if ( $subjectId == 'main' ) {
-                               $talkId = 'talk';
-                       } else {
-                               $talkId = "{$subjectId}_talk";
-                       }
-
-                       // Adds namespace links
-                       $links['namespaces'][$subjectId] = $this->tabAction(
-                               $subjectPage, 'nstab-' . $subjectId, !$isTalk, '', $userCanRead
-                       );
-                       $links['namespaces'][$subjectId]['context'] = 'subject';
-                       $links['namespaces'][$talkId] = $this->tabAction(
-                               $talkPage, 'talk', $isTalk, '', $userCanRead
-                       );
-                       $links['namespaces'][$talkId]['context'] = 'talk';
-
-                       // Adds view view link
-                       if ( $this->mTitle->exists() && $userCanRead ) {
-                               $links['views']['view'] = $this->tabAction(
-                                       $isTalk ? $talkPage : $subjectPage,
-                                               'vector-view-view', ( $action == 'view' ), '', true
-                               );
-                       }
-
-                       wfProfileIn( __METHOD__ . '-edit' );
-
-                       // Checks if user can...
-                       if (
-                               // read and edit the current page
-                               $userCanRead && $this->mTitle->quickUserCan( 'edit' ) &&
-                               (
-                                       // if it exists
-                                       $this->mTitle->exists() ||
-                                       // or they can create one here
-                                       $this->mTitle->quickUserCan( 'create' )
-                               )
-                       ) {
-                               // Builds CSS class for talk page links
-                               $isTalkClass = $isTalk ? ' istalk' : '';
-
-                               // Determines if we're in edit mode
-                               $selected = (
-                                       ( $action == 'edit' || $action == 'submit' ) &&
-                                       ( $section != 'new' )
-                               );
-                               $links['views']['edit'] = array(
-                                       'class' => ( $selected ? 'selected' : '' ) . $isTalkClass,
-                                       'text' => $this->mTitle->exists()
-                                               ? wfMsg( 'vector-view-edit' )
-                                               : wfMsg( 'vector-view-create' ),
-                                       'href' =>
-                                               $this->mTitle->getLocalURL( $this->editUrlOptions() )
-                               );
-                               // Checks if this is a current rev of talk page and we should show a new
-                               // section link
-                               if ( ( $isTalk && $wgArticle && $wgArticle->isCurrent() ) || ( $wgOut->showNewSectionLink() ) ) {
-                                       // Checks if we should ever show a new section link
-                                       if ( !$wgOut->forceHideNewSectionLink() ) {
-                                               // Adds new section link
-                                               //$links['actions']['addsection']
-                                               $links['views']['addsection'] = array(
-                                                       'class' => 'collapsible ' . ( $section == 'new' ? 'selected' : false ),
-                                                       'text' => wfMsg( 'vector-action-addsection' ),
-                                                       'href' => $this->mTitle->getLocalURL(
-                                                               'action=edit&section=new'
-                                                       )
-                                               );
-                                       }
-                               }
-                       // Checks if the page has some kind of viewable content
-                       } elseif ( $this->mTitle->hasSourceText() && $userCanRead ) {
-                               // Adds view source view link
-                               $links['views']['viewsource'] = array(
-                                       'class' => ( $action == 'edit' ) ? 'selected' : false,
-                                       'text' => wfMsg( 'vector-view-viewsource' ),
-                                       'href' =>
-                                               $this->mTitle->getLocalURL( $this->editUrlOptions() )
-                               );
-                       }
-                       wfProfileOut( __METHOD__ . '-edit' );
-
-                       wfProfileIn( __METHOD__ . '-live' );
-
-                       // Checks if the page exists
-                       if ( $this->mTitle->exists() && $userCanRead ) {
-                               // Adds history view link
-                               $links['views']['history'] = array(
-                                       'class' => 'collapsible ' . ( ( $action == 'history' ) ? 'selected' : false ),
-                                       'text' => wfMsg( 'vector-view-history' ),
-                                       'href' => $this->mTitle->getLocalURL( 'action=history' ),
-                                       'rel' => 'archives',
-                               );
-
-                               if( $wgUser->isAllowed( 'delete' ) ) {
-                                       $links['actions']['delete'] = array(
-                                               'class' => ( $action == 'delete' ) ? 'selected' : false,
-                                               'text' => wfMsg( 'vector-action-delete' ),
-                                               'href' => $this->mTitle->getLocalURL( 'action=delete' )
-                                       );
-                               }
-                               if ( $this->mTitle->quickUserCan( 'move' ) ) {
-                                       $moveTitle = SpecialPage::getTitleFor(
-                                               'Movepage', $this->thispage
-                                       );
-                                       $links['actions']['move'] = array(
-                                               'class' => $this->mTitle->isSpecial( 'Movepage' ) ?
-                                                                               'selected' : false,
-                                               'text' => wfMsg( 'vector-action-move' ),
-                                               'href' => $moveTitle->getLocalURL()
-                                       );
-                               }
-
-                               if (
-                                       $this->mTitle->getNamespace() !== NS_MEDIAWIKI &&
-                                       $wgUser->isAllowed( 'protect' )
-                               ) {
-                                       if ( !$this->mTitle->isProtected() ) {
-                                               $links['actions']['protect'] = array(
-                                                       'class' => ( $action == 'protect' ) ?
-                                                                                       'selected' : false,
-                                                       'text' => wfMsg( 'vector-action-protect' ),
-                                                       'href' =>
-                                                               $this->mTitle->getLocalURL( 'action=protect' )
-                                               );
-
-                                       } else {
-                                               $links['actions']['unprotect'] = array(
-                                                       'class' => ( $action == 'unprotect' ) ?
-                                                                                       'selected' : false,
-                                                       'text' => wfMsg( 'vector-action-unprotect' ),
-                                                       'href' =>
-                                                               $this->mTitle->getLocalURL( 'action=unprotect' )
-                                               );
-                                       }
-                               }
-                       } else {
-                               // article doesn't exist or is deleted
-                               if (
-                                       $wgUser->isAllowed( 'deletedhistory' ) &&
-                                       $wgUser->isAllowed( 'undelete' )
-                               ) {
-                                       $n = $this->mTitle->isDeleted();
-                                       if( $n ) {
-                                               $undelTitle = SpecialPage::getTitleFor( 'Undelete' );
-                                               $links['actions']['undelete'] = array(
-                                                       'class' => false,
-                                                       'text' => wfMsgExt(
-                                                               'vector-action-undelete',
-                                                               array( 'parsemag' ),
-                                                               $wgLang->formatNum( $n )
-                                                       ),
-                                                       'href' => $undelTitle->getLocalURL(
-                                                               'target=' . urlencode( $this->thispage )
-                                                       )
-                                               );
-                                       }
-                               }
-
-                               if (
-                                       $this->mTitle->getNamespace() !== NS_MEDIAWIKI &&
-                                       $wgUser->isAllowed( 'protect' )
-                               ) {
-                                       if ( !$this->mTitle->getRestrictions( 'create' ) ) {
-                                               $links['actions']['protect'] = array(
-                                                       'class' => ( $action == 'protect' ) ?
-                                                                                       'selected' : false,
-                                                       'text' => wfMsg( 'vector-action-protect' ),
-                                                       'href' =>
-                                                               $this->mTitle->getLocalURL( 'action=protect' )
-                                               );
-
-                                       } else {
-                                               $links['actions']['unprotect'] = array(
-                                                       'class' => ( $action == 'unprotect' ) ?
-                                                                                       'selected' : false,
-                                                       'text' => wfMsg( 'vector-action-unprotect' ),
-                                                       'href' =>
-                                                               $this->mTitle->getLocalURL( 'action=unprotect' )
-                                               );
-                                       }
-                               }
-                       }
-                       wfProfileOut( __METHOD__ . '-live' );
-                       /**
-                        * The following actions use messages which, if made particular to
-                        * the Vector skin, would break the Ajax code which makes this
-                        * action happen entirely inline. Skin::makeGlobalVariablesScript
-                        * defines a set of messages in a javascript object - and these
-                        * messages are assumed to be global for all skins. Without making
-                        * a change to that procedure these messages will have to remain as
-                        * the global versions.
-                        */
-                       // Checks if the user is logged in
-                       if ( $this->loggedin ) {
-                               if ( $wgVectorUseIconWatch ) {
-                                       $class = 'icon';
-                                       $place = 'views';
-                               } else {
-                                       $class = '';
-                                       $place = 'actions';
-                               }
-                               $mode = $this->mTitle->userIsWatching() ? 'unwatch' : 'watch';
-                               $links[$place][$mode] = array(
-                                       'class' => $class . ( ( $action == 'watch' || $action == 'unwatch' ) ? ' selected' : false ),
-                                       'text' => wfMsg( $mode ), // uses 'watch' or 'unwatch' message
-                                       'href' => $this->mTitle->getLocalURL( 'action=' . $mode )
-                               );
-                       }
-                       // This is instead of SkinTemplateTabs - which uses a flat array
-                       wfRunHooks( 'SkinTemplateNavigation', array( &$this, &$links ) );
-
-               // If it's not content, it's got to be a special page
-               } else {
-                       $links['namespaces']['special'] = array(
-                               'class' => 'selected',
-                               'text' => wfMsg( 'nstab-special' ),
-                               'href' => $wgRequest->getRequestURL()
-                       );
-                       // Equiv to SkinTemplateBuildContentActionUrlsAfterSpecialPage
-                       wfRunHooks( 'SkinTemplateNavigation::SpecialPage', array( &$this, &$links ) );
-               }
-
-               // Gets list of language variants
-               $variants = $wgContLang->getVariants();
-               // Checks that language conversion is enabled and variants exist
-               if( !$wgDisableLangConversion && count( $variants ) > 1 ) {
-                       // Gets preferred variant
-                       $preferred = $wgContLang->getPreferredVariant();
-                       // Loops over each variant
-                       foreach( $variants as $code ) {
-                               // Gets variant name from language code
-                               $varname = $wgContLang->getVariantname( $code );
-                               // Checks if the variant is marked as disabled
-                               if( $varname == 'disable' ) {
-                                       // Skips this variant
-                                       continue;
-                               }
-                               // Appends variant link
-                               $links['variants'][] = array(
-                                       'class' => ( $code == $preferred ) ? 'selected' : false,
-                                       'text' => $varname,
-                                       'href' => $this->mTitle->getLocalURL( '', $code )
-                               );
-                       }
-               }
-
-               // Equiv to SkinTemplateContentActions
-               wfRunHooks( 'SkinTemplateNavigation::Universal', array( &$this,  &$links ) );
-
-               wfProfileOut( __METHOD__ );
-
-               return $links;
-       }
 }
 
 /**
@@ -361,39 +71,38 @@ class VectorTemplate extends BaseTemplate {
         * Outputs the entire contents of the XHTML page
         */
        public function execute() {
-               global $wgRequest, $wgLang;
+               global $wgRequest, $wgLang, $wgVectorUseIconWatch;
 
                $this->skin = $this->data['skin'];
                $action = $wgRequest->getText( 'action' );
 
                // Build additional attributes for navigation urls
-               $nav = $this->skin->buildNavigationUrls();
+               //$nav = $this->skin->buildNavigationUrls();
+               $nav = $this->data['content_navigation'];
+               
+               if ( $wgVectorUseIconWatch ) {
+                       $mode = $this->skin->mTitle->userIsWatching() ? 'unwatch' : 'watch';
+                       $nav['views'][$mode] = $nav['actions'][$mode];
+                       $nav['views'][$mode]['class'] = rtrim('icon ' . $nav['views'][$mode]['class'], ' ');
+                       $nav['views'][$mode]['primary'] = true;
+                       unset($nav['actions'][$mode]);
+               }
+               
                foreach ( $nav as $section => $links ) {
                        foreach ( $links as $key => $link ) {
-                               $xmlID = $key;
-                               if ( isset( $link['context'] ) && $link['context'] == 'subject' ) {
-                                       $xmlID = 'ca-nstab-' . $xmlID;
-                               } else if ( isset( $link['context'] ) && $link['context'] == 'talk' ) {
-                                       $xmlID = 'ca-talk';
-                               } else {
-                                       $xmlID = 'ca-' . $xmlID;
+                               if ( $section == "views" && !(isset($link["primary"]) && $link["primary"]) ) {
+                                       $link['class'] = rtrim('collapsible ' . $link['class'], ' ');
                                }
+                               
+                               $xmlID = isset($link["id"]) ? $link["id"] : 'ca-' . $xmlID;
                                $nav[$section][$key]['attributes'] =
                                        ' id="' . Sanitizer::escapeId( $xmlID ) . '"';
-                               if ( $nav[$section][$key]['class'] ) {
+                               if ( $link['class'] ) {
                                        $nav[$section][$key]['attributes'] .=
                                                ' class="' . htmlspecialchars( $link['class'] ) . '"';
                                        unset( $nav[$section][$key]['class'] );
                                }
-                               // We don't want to give the watch tab an accesskey if the page
-                               // is being edited, because that conflicts with the accesskey on
-                               // the watch checkbox.  We also don't want to give the edit tab
-                               // an accesskey, because that's fairly superfluous and conflicts
-                               // with an accesskey (Ctrl-E) often used for editing in Safari.
-                               if (
-                                       in_array( $action, array( 'edit', 'submit' ) ) &&
-                                       in_array( $key, array( 'edit', 'watch', 'unwatch' ) )
-                               ) {
+                               if ( isset($link['tooltiponly']) && $link['tooltiponly'] ) {
                                        $nav[$section][$key]['key'] =
                                                $this->skin->tooltip( $xmlID );
                                } else {