From c63ac431ff5272f308ead13ce4cab06a7e5f3c3a Mon Sep 17 00:00:00 2001 From: Trevor Parscal Date: Wed, 27 May 2009 23:27:25 +0000 Subject: [PATCH] New skin based on MonoBook with improvements inspired by research conducted by the Wikipedia Usability Initiative --- skins/Vector.deps.php | 11 + skins/Vector.php | 806 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 817 insertions(+) create mode 100644 skins/Vector.deps.php create mode 100644 skins/Vector.php diff --git a/skins/Vector.deps.php b/skins/Vector.deps.php new file mode 100644 index 0000000000..7a8c2881cd --- /dev/null +++ b/skins/Vector.deps.php @@ -0,0 +1,11 @@ +skinname = 'vector'; + $this->stylename = 'vector'; + $this->template = 'VectorTemplate'; + } + + /** + * Defines CSS files to be included + * @param object $out Output page to add styles to + */ + public function setupSkinUserCss( OutputPage $out ) { + global $wgHandheldStyle; + + parent::setupSkinUserCss( $out ); + + // Append to the default screen common & print styles... + $out->addStyle( 'vector/main.css', 'screen' ); + } + + /** + * A structured array of edit links by default used for the tabs + * @return array + * @private + */ + function buildNavigationUrls() { + global $wgContLang, $wgLang, $wgOut, $wgUser, $wgRequest; + global $wgDisableLangConversion; + + wfProfileIn( __METHOD__ ); + + $links = array( + 'namespaces' => array(), + 'views' => array(), + 'actions' => array(), + 'variants' => array() + ); + + // Detects parameters + $action = $wgRequest->getVal( 'action', 'view' ); + $section = $wgRequest->getVal( 'section' ); + + // 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 = $wgContLang->lc( $this->mTitle->getSubjectNsText() ); + if ( $subjectId == '' ) { + $subjectId = 'main'; + } + $talkId = "{$subjectId}_talk"; + $currentId = $isTalk ? $talkId : $subjectId; + + // Adds namespace links + $links['namespaces'][$subjectId] = $this->tabAction( + $subjectPage, 'nstab-' . $subjectId, !$isTalk, '', true + ); + $links['namespaces'][$talkId] = $this->tabAction( + $talkPage, 'talk', $isTalk, '', true + ); + + // Adds view view link + if ( $this->mTitle->exists() ) { + $links['views']['view'] = $this->tabAction( + $isTalk ? $talkPage : $subjectPage, + 'view', ( $action == 'view' ), '', true + ); + } + + wfProfileIn( __METHOD__ . '-edit' ); + + // Checks if user can... + if ( + // edit the current page + $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( 'edit' ) + : wfMsg( 'create' ), + 'href' => + $this->mTitle->getLocalUrl( $this->editUrlOptions() ) + ); + // Checks if this is a talk page and we should show a new + // section link + if ( $isTalk || $wgOut->showNewSectionLink() ) { + // Checks if we should ever show a new section link + if ( !$wgOut->forceHideNewSectionLink() ) { + // Adds new section link + $links['actions']['addsection'] = array( + 'class' => $section == 'new' ? 'selected' : false, + 'text' => wfMsg( 'addsection' ), + 'href' => $this->mTitle->getLocalUrl( + 'action=edit§ion=new' + ) + ); + } + } + // Checks if the page is known (some kind of viewable content) + } elseif ( $this->mTitle->isKnown() ) { + // Adds view source view link + $links['views']['viewsource'] = array( + 'class' => ( $action == 'edit') ? 'selected' : false, + 'text' => wfMsg( 'viewsource' ), + 'href' => + $this->mTitle->getLocalUrl( $this->editUrlOptions() ) + ); + } + wfProfileOut( __METHOD__ . '-edit' ); + + wfProfileIn( __METHOD__ . '-live' ); + + // Checks if the page exists + if ( $this->mTitle->exists() ) { + // Adds history view link + $links['views']['history'] = array( + 'class' => ($action == 'history') ? 'selected' : false, + 'text' => wfMsg( 'history_short' ), + 'href' => $this->mTitle->getLocalUrl( 'action=history' ), + 'rel' => 'archives', + ); + + if( $wgUser->isAllowed( 'delete' ) ) { + $links['actions']['delete'] = array( + 'class' => ($action == 'delete') ? 'selected' : false, + 'text' => wfMsg( '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( '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( 'protect' ), + 'href' => + $this->mTitle->getLocalUrl( 'action=protect' ) + ); + + } else { + $links['actions']['unprotect'] = array( + 'class' => ($action == 'unprotect') ? + 'selected' : false, + 'text' => wfMsg( 'unprotect' ), + 'href' => + $this->mTitle->getLocalUrl( 'action=unprotect' ) + ); + } + } + } else { + // article doesn't exist or is deleted + if ( + $wgUser->isAllowed( 'deletedhistory' ) && + $wgUser->isAllowed( 'undelete' ) + ) { + if( $n = $this->mTitle->isDeleted() ) { + $undelTitle = SpecialPage::getTitleFor( 'Undelete' ); + $links['actions']['undelete'] = array( + 'class' => false, + 'text' => wfMsgExt( + 'undelete_short', + 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( 'protect' ), + 'href' => + $this->mTitle->getLocalUrl( 'action=protect' ) + ); + + } else { + $links['actions']['unprotect'] = array( + 'class' => ($action == 'unprotect') ? + 'selected' : false, + 'text' => wfMsg( 'unprotect' ), + 'href' => + $this->mTitle->getLocalUrl( 'action=unprotect' ) + ); + } + } + } + wfProfileOut( __METHOD__ . '-live' ); + + // Checks if the user is logged in + if( $this->loggedin ) { + // Checks if the user is watching this page + if( !$this->mTitle->userIsWatching() ) { + // Adds watch action link + $links['actions']['watch'] = array( + 'class' => + ( $action == 'watch' or $action == 'unwatch') ? + 'selected' : false, + 'text' => wfMsg( 'watch' ), + 'href' => $this->mTitle->getLocalUrl( 'action=watch' ) + ); + } else { + // Adds unwatch action link + $links['actions']['unwatch'] = array( + 'class' => + ($action == 'unwatch' or $action == 'watch') ? + 'selected' : false, + 'text' => wfMsg( 'unwatch' ), + 'href' => $this->mTitle->getLocalUrl( 'action=unwatch' ) + ); + } + } + + // 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() + ); + } + + // 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 + $vcount = 0; + 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'][$vcount] = array( + 'class' => ( $code == $preferred )? 'selected' : false, + 'text' => $varname, + 'href' => $this->mTitle->getLocalURL( '', $code ) + ); + $vcount ++; + } + } + + wfProfileOut( __METHOD__ ); + + return $links; + } +} + +/** + * QuickTemplate class for Vector skin + * @ingroup Skins + */ +class VectorTemplate extends QuickTemplate { + + /* Members */ + + /** + * @var Cached skin object + */ + var $skin; + + /* Functions */ + + /** + * Outputs the entire contents of the XHTML page + */ + public function execute() { + global $wgRequest, $wgUseTwoButtonsSearchForm; + + $this->skin = $this->data['skin']; + $action = $wgRequest->getText( 'action' ); + + // Suppress warnings to prevent notices about missing indexes in + // $this->data (is this really the best way to handle this?) + wfSuppressWarnings(); + + // Build additional attributes for navigation urls + $nav = $this->skin->buildNavigationUrls(); + foreach ( $nav as $section => $links ) { + foreach ( $links as $key => $link ) { + $nav[$section][$key]['attributes'] = + ' id="' . Sanitizer::escapeId( "ca-$key" ) . '"'; + if ( $nav[$section][$key]['class'] ) { + $nav[$section][$key]['attributes'] .= + ' class="' . htmlspecialchars( $link['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' ) ) + ) { + $nav[$section][$key]['key'] = + $this->skin->tooltip( "ca-$key" ); + } else { + $nav[$section][$key]['key'] = + $this->skin->tooltipAndAccesskey( "ca-$key" ); + } + } + } + $this->data['namespace_urls'] = $nav['namespaces']; + $this->data['view_urls'] = $nav['views']; + $this->data['action_urls'] = $nav['actions']; + $this->data['variant_urls'] = $nav['variants']; + + // Build additional attributes for personal_urls + foreach ( $this->data['personal_urls'] as $key => $item) { + $this->data['personal_urls'][$key]['attributes'] = + ' id="' . Sanitizer::escapeId( "pt-$key" ) . '"'; + if ( $item['active'] ) { + $this->data['personal_urls'][$key]['attributes'] .= + ' class="active"'; + } + $this->data['personal_urls'][$key]['key'] = + $this->skin->tooltipAndAccesskey('pt-'.$key); + } + + // Generate additional footer links + $footerlinks = array( + 'info' => array( + 'lastmod', + 'viewcount', + 'numberofwatchingusers', + 'credits', + 'copyright', + 'tagline', + ), + 'places' => array( + 'privacy', + 'about', + 'disclaimer', + ), + ); + + // Build list of valid footer links + $validFooterLinks = array(); + foreach( $footerlinks as $category => $links ) { + $validFooterLinks[$category] = array(); + foreach( $links as $link ) { + if( isset( $this->data[$link] ) && $this->data[$link] ) { + $validFooterLinks[$category][] = $link; + } + } + } + + // Begin content output +?> +data['xhtmlnamespaces'] as $tag => $ns): ?>xmlns:xml:lang="text('lang') ?>" lang="text('lang') ?>" dir="text('dir') ?>"> + + + <?php $this->text('pagetitle') ?> + + html('headlinks') ?> + + + html('csslinks') ?> + + + + + + data ); ?> + + + + + + html('headscripts') ?> + + data['jsvarurl']): ?> + + + + + data['pagecss']): ?> + + + + + data['usercss']): ?> + + + + + data['userjs']): ?> + + + + + data['userjsprev']): ?> + + + + + data['trackbackhtml']): ?> + + data['trackbackhtml']; ?> + + + + data['body_ondblclick']): ?> ondblclick="text('body_ondblclick') ?>" data['body_onload']): ?> onload="text('body_onload') ?>" class="mediawiki text('dir') ?> text('pageclass') ?> text('skinnameclass') ?>"> +
+
+ +
+ +
+
+ + + data['sitenotice']) { ?>
html('sitenotice') ?>
+ + +

html('title') ?>

+ + +
+ +

msg('tagline') ?>

+ + +
html('subtitle') ?>
+ + data['undelete']): ?> + +
html('undelete') ?>
+ + + data['newtalk'] ): ?> + +
html('newtalk') ?>
+ + + data['showjumplinks']): ?> + + + + + + html('bodytext') ?> + + + data['catlinks']) { $this->html('catlinks'); } ?> + + + data['dataAfterContent']) { $this->html ('dataAfterContent'); } ?> + +
+
+ +
+
+ + + + + +
+
+ + + + + data['sidebar']; + $sidebar['TOOLBOX'] = ( !isset( $sidebar['TOOLBOX'] ) ); + $sidebar['LANGUAGES'] = ( !isset( $sidebar['LANGUAGES'] ) ); + foreach ( $sidebar as $name => $content ) { + switch( $name ) { + case 'SEARCH': + break; + case 'TOOLBOX': + $this->toolBox(); + break; + case 'LANGUAGES': + $this->languageBox(); + break; + default: + $this->customBox( $name, $content ); + break; + } + } + ?> + +
+
+ +
+ + + +
+ + + + + html( 'bottomscripts'); /* JS call to runBodyOnloadHook */ ?> + html( 'reporttime') ?> + data['debug'] ): ?> + + + + + +
+
langAttributes( ) ?>>msg( 'toolbox') ?>
+
+ +
+
+data['language_urls'] ) { +?> +
+
langAttributes( ) ?>>msg( 'otherlanguages') ?>
+
+
    + data['language_urls'] as $langlink ): ?> +
  • + +
+
+
+ +
skin->tooltip( 'p-'.$bar) ?>> +
langAttributes( ) ?>>
+
+ + + + + +
+
+data['userlang'] . '" xml:lang="' . $this->data['userlang'] . '"'; + } +} -- 2.20.1