[WIKI] Commit the parts we will customize of the unmodified Vector skin of MediaWiki 1.30.0 and remove our customized MediaWiki 1.23.x skin.

This commit is contained in:
Colin Finck 2018-05-14 18:32:04 +02:00
parent ff063944e3
commit 14b3d8964a
25 changed files with 688 additions and 3728 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,468 +0,0 @@
<?php
/**
* Vector - Modern version of MonoBook with fresh look and many usability
* improvements.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @todo document
* @file
* @ingroup Skins
*/
if ( !defined( 'MEDIAWIKI' ) ) {
die( -1 );
}
/**
* SkinTemplate class for Vector skin
* @ingroup Skins
*/
class SkinVector extends SkinTemplate {
protected static $bodyClasses = array( 'vector-animateLayout' );
var $skinname = 'vector', $stylename = 'vector',
$template = 'VectorTemplate', $useHeadElement = true;
/**
* Initializes output page and sets up skin-specific parameters
* @param $out OutputPage object to initialize
*/
public function initPage( OutputPage $out ) {
global $wgLocalStylePath;
parent::initPage( $out );
// Append CSS which includes IE only behavior fixes for hover support -
// this is better than including this in a CSS file since it doesn't
// wait for the CSS file to load before fetching the HTC file.
$min = $this->getRequest()->getFuzzyBool( 'debug' ) ? '' : '.min';
$out->addHeadItem( 'csshover',
'<!--[if lt IE 7]><style type="text/css">body{behavior:url("' .
htmlspecialchars( $wgLocalStylePath ) .
"/{$this->stylename}/csshover{$min}.htc\")}</style><![endif]-->"
);
$out->addModules( array( 'skins.vector.js', 'skins.vector.collapsibleNav' ) );
}
/**
* Loads skin and user CSS files.
* @param $out OutputPage object
*/
function setupSkinUserCss( OutputPage $out ) {
parent::setupSkinUserCss( $out );
$styles = array( 'mediawiki.skinning.interface', 'skins.vector.styles' );
wfRunHooks( 'SkinVectorStyleModules', array( $this, &$styles ) );
$out->addModuleStyles( $styles );
}
/**
* Adds classes to the body element.
*
* @param $out OutputPage object
* @param &$bodyAttrs Array of attributes that will be set on the body element
*/
function addToBodyAttributes( $out, &$bodyAttrs ) {
if ( isset( $bodyAttrs['class'] ) && strlen( $bodyAttrs['class'] ) > 0 ) {
$bodyAttrs['class'] .= ' ' . implode( ' ', static::$bodyClasses );
} else {
$bodyAttrs['class'] = implode( ' ', static::$bodyClasses );
}
}
}
/**
* QuickTemplate class for Vector skin
* @ingroup Skins
*/
class VectorTemplate extends BaseTemplate {
/* Functions */
/**
* Outputs the entire contents of the (X)HTML page
*/
public function execute() {
global $wgVectorUseIconWatch;
// Build additional attributes for navigation urls
$nav = $this->data['content_navigation'];
if ( $wgVectorUseIconWatch ) {
$mode = $this->getSkin()->getUser()->isWatched( $this->getSkin()->getRelevantTitle() ) ? 'unwatch' : 'watch';
if ( isset( $nav['actions'][$mode] ) ) {
$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] );
}
}
$xmlID = '';
foreach ( $nav as $section => $links ) {
foreach ( $links as $key => $link ) {
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 ( $link['class'] ) {
$nav[$section][$key]['attributes'] .=
' class="' . htmlspecialchars( $link['class'] ) . '"';
unset( $nav[$section][$key]['class'] );
}
if ( isset( $link['tooltiponly'] ) && $link['tooltiponly'] ) {
$nav[$section][$key]['key'] =
Linker::tooltip( $xmlID );
} else {
$nav[$section][$key]['key'] =
Xml::expandAttributes( Linker::tooltipAndAccesskeyAttribs( $xmlID ) );
}
}
}
$this->data['namespace_urls'] = $nav['namespaces'];
$this->data['view_urls'] = $nav['views'];
$this->data['action_urls'] = $nav['actions'];
$this->data['variant_urls'] = $nav['variants'];
// Reverse horizontally rendered navigation elements
if ( $this->data['rtl'] ) {
$this->data['view_urls'] =
array_reverse( $this->data['view_urls'] );
$this->data['namespace_urls'] =
array_reverse( $this->data['namespace_urls'] );
$this->data['personal_urls'] =
array_reverse( $this->data['personal_urls'] );
}
// Output HTML Page
$this->html( 'headelement' );
?>
<link type="text/css" rel="stylesheet" href="//fonts.googleapis.com/css?family=Open+Sans:400,400italic,700,700italic" media="all" />
<div id="mw-page-base" class="noprint"></div>
<div id="mw-head-base" class="noprint"></div>
<div id="content" class="mw-body" role="main">
<a id="top"></a>
<div id="mw-js-message" style="display:none;"<?php $this->html( 'userlangattributes' ) ?>></div>
<?php if ( $this->data['sitenotice'] ) { ?>
<div id="siteNotice"><?php $this->html( 'sitenotice' ) ?></div>
<?php } ?>
<h1 id="firstHeading" class="firstHeading" lang="<?php
$this->data['pageLanguage'] = $this->getSkin()->getTitle()->getPageViewLanguage()->getHtmlCode();
$this->text( 'pageLanguage' );
?>"><span dir="auto"><?php $this->html( 'title' ) ?></span></h1>
<?php $this->html( 'prebodyhtml' ) ?>
<div id="bodyContent">
<?php if ( $this->data['isarticle'] ) { ?>
<div id="siteSub"><?php $this->msg( 'tagline' ) ?></div>
<?php } ?>
<div id="contentSub"<?php $this->html( 'userlangattributes' ) ?>><?php $this->html( 'subtitle' ) ?></div>
<?php if ( $this->data['undelete'] ) { ?>
<div id="contentSub2"><?php $this->html( 'undelete' ) ?></div>
<?php } ?>
<?php if ( $this->data['newtalk'] ) { ?>
<div class="usermessage"><?php $this->html( 'newtalk' ) ?></div>
<?php } ?>
<div id="jump-to-nav" class="mw-jump">
<?php $this->msg( 'jumpto' ) ?>
<a href="#mw-navigation"><?php $this->msg( 'jumptonavigation' ) ?></a><?php $this->msg( 'comma-separator' ) ?>
<a href="#p-search"><?php $this->msg( 'jumptosearch' ) ?></a>
</div>
<?php $this->html( 'bodycontent' ) ?>
<?php if ( $this->data['printfooter'] ) { ?>
<div class="printfooter">
<?php $this->html( 'printfooter' ); ?>
</div>
<?php } ?>
<?php if ( $this->data['catlinks'] ) { ?>
<?php $this->html( 'catlinks' ); ?>
<?php } ?>
<?php if ( $this->data['dataAfterContent'] ) { ?>
<?php $this->html( 'dataAfterContent' ); ?>
<?php } ?>
<div class="visualClear"></div>
<?php $this->html( 'debughtml' ); ?>
</div>
</div>
<div id="mw-navigation">
<h2><?php $this->msg( 'navigation-heading' ) ?></h2>
<div id="mw-head">
<div id="reactos-head">
<a href="/"><img id="homelogo" src="/sites/default/files/ReactOS_0.png"></a>
<a id="homebutton" href="/">Back to Website</a>
</div>
<?php $this->renderNavigation( 'PERSONAL' ); ?>
<div id="left-navigation">
<?php $this->renderNavigation( array( 'NAMESPACES', 'VARIANTS' ) ); ?>
</div>
<div id="right-navigation">
<?php $this->renderNavigation( array( 'VIEWS', 'ACTIONS', 'SEARCH' ) ); ?>
</div>
</div>
<div id="mw-panel">
<?php $this->renderPortals( $this->data['sidebar'] ); ?>
</div>
</div>
<div id="footer" role="contentinfo"<?php $this->html( 'userlangattributes' ) ?>>
<?php foreach ( $this->getFooterLinks() as $category => $links ) { ?>
<ul id="footer-<?php echo $category ?>">
<?php foreach ( $links as $link ) { ?>
<li id="footer-<?php echo $category ?>-<?php echo $link ?>"><?php $this->html( $link ) ?></li>
<?php } ?>
</ul>
<?php } ?>
<?php $footericons = $this->getFooterIcons( "icononly" );
if ( count( $footericons ) > 0 ) { ?>
<ul id="footer-icons" class="noprint">
<?php foreach ( $footericons as $blockName => $footerIcons ) { ?>
<li id="footer-<?php echo htmlspecialchars( $blockName ); ?>ico">
<?php foreach ( $footerIcons as $icon ) { ?>
<?php echo $this->getSkin()->makeFooterIcon( $icon ); ?>
<?php } ?>
</li>
<?php } ?>
</ul>
<?php } ?>
<div style="clear:both"></div>
</div>
<?php $this->printTrail(); ?>
</body>
</html>
<?php
}
/**
* Render a series of portals
*
* @param $portals array
*/
protected function renderPortals( $portals ) {
// Force the rendering of the following portals
if ( !isset( $portals['SEARCH'] ) ) {
$portals['SEARCH'] = true;
}
if ( !isset( $portals['TOOLBOX'] ) ) {
$portals['TOOLBOX'] = true;
}
if ( !isset( $portals['LANGUAGES'] ) ) {
$portals['LANGUAGES'] = true;
}
// Render portals
foreach ( $portals as $name => $content ) {
if ( $content === false ) {
continue;
}
switch ( $name ) {
case 'SEARCH':
break;
case 'TOOLBOX':
$this->renderPortal( 'tb', $this->getToolbox(), 'toolbox', 'SkinTemplateToolboxEnd' );
break;
case 'LANGUAGES':
if ( $this->data['language_urls'] !== false ) {
$this->renderPortal( 'lang', $this->data['language_urls'], 'otherlanguages' );
}
break;
default:
$this->renderPortal( $name, $content );
break;
}
}
}
/**
* @param $name string
* @param $content array
* @param $msg null|string
* @param $hook null|string|array
*/
protected function renderPortal( $name, $content, $msg = null, $hook = null ) {
if ( $msg === null ) {
$msg = $name;
}
$msgObj = wfMessage( $msg );
?>
<div class="portal" role="navigation" id='<?php echo Sanitizer::escapeId( "p-$name" ) ?>'<?php echo Linker::tooltip( 'p-' . $name ) ?> aria-labelledby='<?php echo Sanitizer::escapeId( "p-$name-label" ) ?>'>
<h3<?php $this->html( 'userlangattributes' ) ?> id='<?php echo Sanitizer::escapeId( "p-$name-label" ) ?>'><?php echo htmlspecialchars( $msgObj->exists() ? $msgObj->text() : $msg ); ?></h3>
<div class="body">
<?php
if ( is_array( $content ) ) { ?>
<ul>
<?php
foreach ( $content as $key => $val ) { ?>
<?php echo $this->makeListItem( $key, $val ); ?>
<?php
}
if ( $hook !== null ) {
wfRunHooks( $hook, array( &$this, true ) );
}
?>
</ul>
<?php
} else { ?>
<?php
echo $content; /* Allow raw HTML block to be defined by extensions */
}
$this->renderAfterPortlet( $name );
?>
</div>
</div>
<?php
}
/**
* Render one or more navigations elements by name, automatically reveresed
* when UI is in RTL mode
*
* @param $elements array
*/
protected function renderNavigation( $elements ) {
global $wgVectorUseSimpleSearch;
// If only one element was given, wrap it in an array, allowing more
// flexible arguments
if ( !is_array( $elements ) ) {
$elements = array( $elements );
// If there's a series of elements, reverse them when in RTL mode
} elseif ( $this->data['rtl'] ) {
$elements = array_reverse( $elements );
}
// Render elements
foreach ( $elements as $name => $element ) {
switch ( $element ) {
case 'NAMESPACES':
?>
<div id="p-namespaces" role="navigation" class="vectorTabs<?php if ( count( $this->data['namespace_urls'] ) == 0 ) { echo ' emptyPortlet'; } ?>" aria-labelledby="p-namespaces-label">
<h3 id="p-namespaces-label"><?php $this->msg( 'namespaces' ) ?></h3>
<ul<?php $this->html( 'userlangattributes' ) ?>>
<?php foreach ( $this->data['namespace_urls'] as $link ) { ?>
<li <?php echo $link['attributes'] ?>><span><a href="<?php echo htmlspecialchars( $link['href'] ) ?>" <?php echo $link['key'] ?>><?php echo htmlspecialchars( $link['text'] ) ?></a></span></li>
<?php } ?>
</ul>
</div>
<?php
break;
case 'VARIANTS':
?>
<div id="p-variants" role="navigation" class="vectorMenu<?php if ( count( $this->data['variant_urls'] ) == 0 ) { echo ' emptyPortlet'; } ?>" aria-labelledby="p-variants-label">
<h3 id="mw-vector-current-variant">
<?php foreach ( $this->data['variant_urls'] as $link ) { ?>
<?php if ( stripos( $link['attributes'], 'selected' ) !== false ) { ?>
<?php echo htmlspecialchars( $link['text'] ) ?>
<?php } ?>
<?php } ?>
</h3>
<h3 id="p-variants-label"><span><?php $this->msg( 'variants' ) ?></span><a href="#"></a></h3>
<div class="menu">
<ul>
<?php foreach ( $this->data['variant_urls'] as $link ) { ?>
<li<?php echo $link['attributes'] ?>><a href="<?php echo htmlspecialchars( $link['href'] ) ?>" lang="<?php echo htmlspecialchars( $link['lang'] ) ?>" hreflang="<?php echo htmlspecialchars( $link['hreflang'] ) ?>" <?php echo $link['key'] ?>><?php echo htmlspecialchars( $link['text'] ) ?></a></li>
<?php } ?>
</ul>
</div>
</div>
<?php
break;
case 'VIEWS':
?>
<div id="p-views" role="navigation" class="vectorTabs<?php if ( count( $this->data['view_urls'] ) == 0 ) { echo ' emptyPortlet'; } ?>" aria-labelledby="p-views-label">
<h3 id="p-views-label"><?php $this->msg( 'views' ) ?></h3>
<ul<?php $this->html( 'userlangattributes' ) ?>>
<?php foreach ( $this->data['view_urls'] as $link ) { ?>
<li<?php echo $link['attributes'] ?>><span><a href="<?php echo htmlspecialchars( $link['href'] ) ?>" <?php echo $link['key'] ?>><?php
// $link['text'] can be undefined - bug 27764
if ( array_key_exists( 'text', $link ) ) {
echo array_key_exists( 'img', $link ) ? '<img src="' . $link['img'] . '" alt="' . $link['text'] . '" />' : htmlspecialchars( $link['text'] );
}
?></a></span></li>
<?php } ?>
</ul>
</div>
<?php
break;
case 'ACTIONS':
?>
<div id="p-cactions" role="navigation" class="vectorMenu<?php if ( count( $this->data['action_urls'] ) == 0 ) { echo ' emptyPortlet'; } ?>" aria-labelledby="p-cactions-label">
<h3 id="p-cactions-label"><span><?php $this->msg( 'actions' ) ?></span><a href="#"></a></h3>
<div class="menu">
<ul<?php $this->html( 'userlangattributes' ) ?>>
<?php foreach ( $this->data['action_urls'] as $link ) { ?>
<li<?php echo $link['attributes'] ?>><a href="<?php echo htmlspecialchars( $link['href'] ) ?>" <?php echo $link['key'] ?>><?php echo htmlspecialchars( $link['text'] ) ?></a></li>
<?php } ?>
</ul>
</div>
</div>
<?php
break;
case 'PERSONAL':
?>
<div id="p-personal" role="navigation" class="<?php if ( count( $this->data['personal_urls'] ) == 0 ) { echo ' emptyPortlet'; } ?>" aria-labelledby="p-personal-label">
<h3 id="p-personal-label"><?php $this->msg( 'personaltools' ) ?></h3>
<ul<?php $this->html( 'userlangattributes' ) ?>>
<?php
$personalTools = $this->getPersonalTools();
foreach ( $personalTools as $key => $item ) {
echo $this->makeListItem( $key, $item );
}
?>
</ul>
</div>
<?php
break;
case 'SEARCH':
?>
<div id="p-search" role="search">
<h3<?php $this->html( 'userlangattributes' ) ?>><label for="searchInput"><?php $this->msg( 'search' ) ?></label></h3>
<form action="<?php $this->text( 'wgScript' ) ?>" id="searchform">
<?php if ( $wgVectorUseSimpleSearch ) { ?>
<div id="simpleSearch">
<?php } else { ?>
<div>
<?php } ?>
<?php
echo $this->makeSearchInput( array( 'id' => 'searchInput' ) );
echo Html::hidden( 'title', $this->get( 'searchtitle' ) );
// We construct two buttons (for 'go' and 'fulltext' search modes), but only one will be
// visible and actionable at a time (they are overlaid on top of each other in CSS).
// * Browsers will use the 'fulltext' one by default (as it's the first in tree-order), which
// is desirable when they are unable to show search suggestions (either due to being broken
// or having JavaScript turned off).
// * The mediawiki.searchSuggest module, after doing tests for the broken browsers, removes
// the 'fulltext' button and handles 'fulltext' search itself; this will reveal the 'go'
// button and cause it to be used.
echo $this->makeSearchButton( 'fulltext', array( 'id' => 'mw-searchButton', 'class' => 'searchButton mw-fallbackSearchButton' ) );
echo $this->makeSearchButton( 'go', array( 'id' => 'searchButton', 'class' => 'searchButton' ) );
?>
</div>
</form>
</div>
<?php
break;
}
}
}
}

View File

@ -0,0 +1,554 @@
<?php
/**
* Vector - Modern version of MonoBook with fresh look and many usability
* improvements.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup Skins
*/
/**
* QuickTemplate class for Vector skin
* @ingroup Skins
*/
class VectorTemplate extends BaseTemplate {
/* Functions */
/**
* Outputs the entire contents of the (X)HTML page
*/
public function execute() {
$this->data['namespace_urls'] = $this->data['content_navigation']['namespaces'];
$this->data['view_urls'] = $this->data['content_navigation']['views'];
$this->data['action_urls'] = $this->data['content_navigation']['actions'];
$this->data['variant_urls'] = $this->data['content_navigation']['variants'];
// Move the watch/unwatch star outside of the collapsed "actions" menu to the main "views" menu
if ( $this->config->get( 'VectorUseIconWatch' ) ) {
$mode = $this->getSkin()->getUser()->isWatched( $this->getSkin()->getRelevantTitle() )
? 'unwatch'
: 'watch';
if ( isset( $this->data['action_urls'][$mode] ) ) {
$this->data['view_urls'][$mode] = $this->data['action_urls'][$mode];
unset( $this->data['action_urls'][$mode] );
}
}
// Reverse horizontally rendered navigation elements
if ( $this->data['rtl'] ) {
$this->data['view_urls'] =
array_reverse( $this->data['view_urls'] );
$this->data['namespace_urls'] =
array_reverse( $this->data['namespace_urls'] );
$this->data['personal_urls'] =
array_reverse( $this->data['personal_urls'] );
}
$this->data['pageLanguage'] =
$this->getSkin()->getTitle()->getPageViewLanguage()->getHtmlCode();
// Output HTML Page
$this->html( 'headelement' );
?>
<div id="mw-page-base" class="noprint"></div>
<div id="mw-head-base" class="noprint"></div>
<div id="content" class="mw-body" role="main">
<a id="top"></a>
<?php
if ( $this->data['sitenotice'] ) {
?>
<div id="siteNotice" class="mw-body-content"><?php $this->html( 'sitenotice' ) ?></div>
<?php
}
?>
<?php
if ( is_callable( [ $this, 'getIndicators' ] ) ) {
echo $this->getIndicators();
}
// Loose comparison with '!=' is intentional, to catch null and false too, but not '0'
if ( $this->data['title'] != '' ) {
?>
<h1 id="firstHeading" class="firstHeading" lang="<?php $this->text( 'pageLanguage' ); ?>"><?php
$this->html( 'title' )
?></h1>
<?php
} ?>
<?php $this->html( 'prebodyhtml' ) ?>
<div id="bodyContent" class="mw-body-content">
<?php
if ( $this->data['isarticle'] ) {
?>
<div id="siteSub" class="noprint"><?php $this->msg( 'tagline' ) ?></div>
<?php
}
?>
<div id="contentSub"<?php $this->html( 'userlangattributes' ) ?>><?php
$this->html( 'subtitle' )
?></div>
<?php
if ( $this->data['undelete'] ) {
?>
<div id="contentSub2"><?php $this->html( 'undelete' ) ?></div>
<?php
}
?>
<?php
if ( $this->data['newtalk'] ) {
?>
<div class="usermessage"><?php $this->html( 'newtalk' ) ?></div>
<?php
}
?>
<div id="jump-to-nav" class="mw-jump">
<?php $this->msg( 'jumpto' ) ?>
<a href="#mw-head"><?php
$this->msg( 'jumptonavigation' )
?></a><?php $this->msg( 'comma-separator' ) ?>
<a href="#p-search"><?php $this->msg( 'jumptosearch' ) ?></a>
</div>
<?php
$this->html( 'bodycontent' );
if ( $this->data['printfooter'] ) {
?>
<div class="printfooter">
<?php $this->html( 'printfooter' ); ?>
</div>
<?php
}
if ( $this->data['catlinks'] ) {
$this->html( 'catlinks' );
}
if ( $this->data['dataAfterContent'] ) {
$this->html( 'dataAfterContent' );
}
?>
<div class="visualClear"></div>
<?php $this->html( 'debughtml' ); ?>
</div>
</div>
<div id="mw-navigation">
<h2><?php $this->msg( 'navigation-heading' ) ?></h2>
<div id="mw-head">
<?php $this->renderNavigation( 'PERSONAL' ); ?>
<div id="left-navigation">
<?php $this->renderNavigation( [ 'NAMESPACES', 'VARIANTS' ] ); ?>
</div>
<div id="right-navigation">
<?php $this->renderNavigation( [ 'VIEWS', 'ACTIONS', 'SEARCH' ] ); ?>
</div>
</div>
<div id="mw-panel">
<div id="p-logo" role="banner"><a class="mw-wiki-logo" href="<?php
echo htmlspecialchars( $this->data['nav_urls']['mainpage']['href'] )
?>" <?php
echo Xml::expandAttributes( Linker::tooltipAndAccesskeyAttribs( 'p-logo' ) )
?>></a></div>
<?php $this->renderPortals( $this->data['sidebar'] ); ?>
</div>
</div>
<div id="footer" role="contentinfo"<?php $this->html( 'userlangattributes' ) ?>>
<?php
foreach ( $this->getFooterLinks() as $category => $links ) {
?>
<ul id="footer-<?php echo $category ?>">
<?php
foreach ( $links as $link ) {
?>
<li id="footer-<?php echo $category ?>-<?php echo $link ?>"><?php $this->html( $link ) ?></li>
<?php
}
?>
</ul>
<?php
}
?>
<?php $footericons = $this->getFooterIcons( 'icononly' );
if ( count( $footericons ) > 0 ) {
?>
<ul id="footer-icons" class="noprint">
<?php
foreach ( $footericons as $blockName => $footerIcons ) {
?>
<li id="footer-<?php echo htmlspecialchars( $blockName ); ?>ico">
<?php
foreach ( $footerIcons as $icon ) {
echo $this->getSkin()->makeFooterIcon( $icon );
}
?>
</li>
<?php
}
?>
</ul>
<?php
}
?>
<div style="clear:both"></div>
</div>
<?php $this->printTrail(); ?>
</body>
</html>
<?php
}
/**
* Render a series of portals
*
* @param array $portals
*/
protected function renderPortals( $portals ) {
// Force the rendering of the following portals
if ( !isset( $portals['SEARCH'] ) ) {
$portals['SEARCH'] = true;
}
if ( !isset( $portals['TOOLBOX'] ) ) {
$portals['TOOLBOX'] = true;
}
if ( !isset( $portals['LANGUAGES'] ) ) {
$portals['LANGUAGES'] = true;
}
// Render portals
foreach ( $portals as $name => $content ) {
if ( $content === false ) {
continue;
}
// Numeric strings gets an integer when set as key, cast back - T73639
$name = (string)$name;
switch ( $name ) {
case 'SEARCH':
break;
case 'TOOLBOX':
$this->renderPortal( 'tb', $this->getToolbox(), 'toolbox', 'SkinTemplateToolboxEnd' );
break;
case 'LANGUAGES':
if ( $this->data['language_urls'] !== false ) {
$this->renderPortal( 'lang', $this->data['language_urls'], 'otherlanguages' );
}
break;
default:
$this->renderPortal( $name, $content );
break;
}
}
}
/**
* @param string $name
* @param array $content
* @param null|string $msg
* @param null|string|array $hook
*/
protected function renderPortal( $name, $content, $msg = null, $hook = null ) {
if ( $msg === null ) {
$msg = $name;
}
$msgObj = wfMessage( $msg );
$labelId = Sanitizer::escapeId( "p-$name-label" );
?>
<div class="portal" role="navigation" id='<?php
echo Sanitizer::escapeId( "p-$name" )
?>'<?php
echo Linker::tooltip( 'p-' . $name )
?> aria-labelledby='<?php echo $labelId ?>'>
<h3<?php $this->html( 'userlangattributes' ) ?> id='<?php echo $labelId ?>'><?php
echo htmlspecialchars( $msgObj->exists() ? $msgObj->text() : $msg );
?></h3>
<div class="body">
<?php
if ( is_array( $content ) ) {
?>
<ul>
<?php
foreach ( $content as $key => $val ) {
echo $this->makeListItem( $key, $val );
}
if ( $hook !== null ) {
// Avoid PHP 7.1 warning
$skin = $this;
Hooks::run( $hook, [ &$skin, true ] );
}
?>
</ul>
<?php
} else {
// Allow raw HTML block to be defined by extensions
echo $content;
}
$this->renderAfterPortlet( $name );
?>
</div>
</div>
<?php
}
/**
* Render one or more navigations elements by name, automatically reveresed
* when UI is in RTL mode
*
* @param array $elements
*/
protected function renderNavigation( $elements ) {
// If only one element was given, wrap it in an array, allowing more
// flexible arguments
if ( !is_array( $elements ) ) {
$elements = [ $elements ];
// If there's a series of elements, reverse them when in RTL mode
} elseif ( $this->data['rtl'] ) {
$elements = array_reverse( $elements );
}
// Render elements
foreach ( $elements as $name => $element ) {
switch ( $element ) {
case 'NAMESPACES':
?>
<div id="p-namespaces" role="navigation" class="vectorTabs<?php
if ( count( $this->data['namespace_urls'] ) == 0 ) {
echo ' emptyPortlet';
}
?>" aria-labelledby="p-namespaces-label">
<h3 id="p-namespaces-label"><?php $this->msg( 'namespaces' ) ?></h3>
<ul<?php $this->html( 'userlangattributes' ) ?>>
<?php
foreach ( $this->data['namespace_urls'] as $key => $item ) {
echo "\t\t\t\t\t\t\t" . $this->makeListItem( $key, $item, [
'vector-wrap' => true,
] ) . "\n";
}
?>
</ul>
</div>
<?php
break;
case 'VARIANTS':
?>
<div id="p-variants" role="navigation" class="vectorMenu<?php
if ( count( $this->data['variant_urls'] ) == 0 ) {
echo ' emptyPortlet';
}
?>" aria-labelledby="p-variants-label">
<?php
// Replace the label with the name of currently chosen variant, if any
$variantLabel = $this->getMsg( 'variants' )->text();
foreach ( $this->data['variant_urls'] as $item ) {
if ( isset( $item['class'] ) && stripos( $item['class'], 'selected' ) !== false ) {
$variantLabel = $item['text'];
break;
}
}
?>
<h3 id="p-variants-label">
<span><?php echo htmlspecialchars( $variantLabel ) ?></span>
</h3>
<div class="menu">
<ul>
<?php
foreach ( $this->data['variant_urls'] as $key => $item ) {
echo "\t\t\t\t\t\t\t\t" . $this->makeListItem( $key, $item ) . "\n";
}
?>
</ul>
</div>
</div>
<?php
break;
case 'VIEWS':
?>
<div id="p-views" role="navigation" class="vectorTabs<?php
if ( count( $this->data['view_urls'] ) == 0 ) {
echo ' emptyPortlet';
}
?>" aria-labelledby="p-views-label">
<h3 id="p-views-label"><?php $this->msg( 'views' ) ?></h3>
<ul<?php $this->html( 'userlangattributes' ) ?>>
<?php
foreach ( $this->data['view_urls'] as $key => $item ) {
echo "\t\t\t\t\t\t\t" . $this->makeListItem( $key, $item, [
'vector-wrap' => true,
'vector-collapsible' => true,
] ) . "\n";
}
?>
</ul>
</div>
<?php
break;
case 'ACTIONS':
?>
<div id="p-cactions" role="navigation" class="vectorMenu<?php
if ( count( $this->data['action_urls'] ) == 0 ) {
echo ' emptyPortlet';
}
?>" aria-labelledby="p-cactions-label">
<h3 id="p-cactions-label"><span><?php
$this->msg( 'vector-more-actions' )
?></span></h3>
<div class="menu">
<ul<?php $this->html( 'userlangattributes' ) ?>>
<?php
foreach ( $this->data['action_urls'] as $key => $item ) {
echo "\t\t\t\t\t\t\t\t" . $this->makeListItem( $key, $item ) . "\n";
}
?>
</ul>
</div>
</div>
<?php
break;
case 'PERSONAL':
?>
<div id="p-personal" role="navigation" class="<?php
if ( count( $this->data['personal_urls'] ) == 0 ) {
echo ' emptyPortlet';
}
?>" aria-labelledby="p-personal-label">
<h3 id="p-personal-label"><?php $this->msg( 'personaltools' ) ?></h3>
<ul<?php $this->html( 'userlangattributes' ) ?>>
<?php
$notLoggedIn = '';
if ( !$this->getSkin()->getUser()->isLoggedIn() &&
User::groupHasPermission( '*', 'edit' )
) {
$notLoggedIn =
Html::rawElement( 'li',
[ 'id' => 'pt-anonuserpage' ],
$this->getMsg( 'notloggedin' )->escaped()
);
}
$personalTools = $this->getPersonalTools();
$langSelector = '';
if ( array_key_exists( 'uls', $personalTools ) ) {
$langSelector = $this->makeListItem( 'uls', $personalTools[ 'uls' ] );
unset( $personalTools[ 'uls' ] );
}
if ( !$this->data[ 'rtl' ] ) {
echo $langSelector;
echo $notLoggedIn;
}
foreach ( $personalTools as $key => $item ) {
echo $this->makeListItem( $key, $item );
}
if ( $this->data[ 'rtl' ] ) {
echo $notLoggedIn;
echo $langSelector;
}
?>
</ul>
</div>
<?php
break;
case 'SEARCH':
?>
<div id="p-search" role="search">
<h3<?php $this->html( 'userlangattributes' ) ?>>
<label for="searchInput"><?php $this->msg( 'search' ) ?></label>
</h3>
<form action="<?php $this->text( 'wgScript' ) ?>" id="searchform">
<div<?php echo $this->config->get( 'VectorUseSimpleSearch' ) ? ' id="simpleSearch"' : '' ?>>
<?php
echo $this->makeSearchInput( [ 'id' => 'searchInput' ] );
echo Html::hidden( 'title', $this->get( 'searchtitle' ) );
/* We construct two buttons (for 'go' and 'fulltext' search modes),
* but only one will be visible and actionable at a time (they are
* overlaid on top of each other in CSS).
* * Browsers will use the 'fulltext' one by default (as it's the
* first in tree-order), which is desirable when they are unable
* to show search suggestions (either due to being broken or
* having JavaScript turned off).
* * The mediawiki.searchSuggest module, after doing tests for the
* broken browsers, removes the 'fulltext' button and handles
* 'fulltext' search itself; this will reveal the 'go' button and
* cause it to be used.
*/
echo $this->makeSearchButton(
'fulltext',
[ 'id' => 'mw-searchButton', 'class' => 'searchButton mw-fallbackSearchButton' ]
);
echo $this->makeSearchButton(
'go',
[ 'id' => 'searchButton', 'class' => 'searchButton' ]
);
?>
</div>
</form>
</div>
<?php
break;
}
}
}
/**
* @inheritDoc
*/
public function makeLink( $key, $item, $options = [] ) {
$html = parent::makeLink( $key, $item, $options );
// Add an extra wrapper because our CSS is weird
if ( isset( $options['vector-wrap'] ) && $options['vector-wrap'] ) {
$html = Html::rawElement( 'span', [], $html );
}
return $html;
}
/**
* @inheritDoc
*/
public function makeListItem( $key, $item, $options = [] ) {
// For fancy styling of watch/unwatch star
if (
$this->config->get( 'VectorUseIconWatch' )
&& ( $key === 'watch' || $key === 'unwatch' )
) {
$item['class'] = rtrim( 'icon ' . $item['class'], ' ' );
$item['primary'] = true;
}
// Add CSS class 'collapsible' to links which are not marked as "primary"
if (
isset( $options['vector-collapsible'] ) && $options['vector-collapsible']
&& !( isset( $item['primary'] ) && $item['primary'] )
) {
$item['class'] = rtrim( 'collapsible ' . $item['class'], ' ' );
}
// We don't use this, prevent it from popping up in HTML output
unset( $item['redundant'] );
return parent::makeListItem( $key, $item, $options );
}
}

View File

@ -0,0 +1,119 @@
{
"name": "Vector",
"author": [
"Trevor Parscal",
"Roan Kattouw",
"..."
],
"url": "https://www.mediawiki.org/wiki/Skin:Vector",
"descriptionmsg": "vector-skin-desc",
"namemsg": "skinname-vector",
"license-name": "GPL-2.0+",
"type": "skin",
"requires": {
"MediaWiki": ">= 1.29.0"
},
"ConfigRegistry": {
"vector": "GlobalVarConfig::newInstance"
},
"ValidSkinNames": {
"vector": "Vector"
},
"MessagesDirs": {
"Vector": [
"i18n"
]
},
"AutoloadClasses": {
"VectorHooks": "Hooks.php",
"SkinVector": "SkinVector.php",
"VectorTemplate": "VectorTemplate.php",
"Vector\\ResourceLoaderLessModule": "ResourceLoaderLessModule.php"
},
"Hooks": {
"BeforePageDisplayMobile": [
"VectorHooks::onBeforePageDisplayMobile"
]
},
"@note": "When modifying skins.vector.styles definition, make sure the installer still works",
"ResourceModules": {
"skins.vector.styles": {
"targets": [ "desktop", "mobile" ],
"position": "top",
"styles": {
"screen.less": {
"media": "screen"
},
"screen-hd.less": {
"media": "screen and (min-width: 982px)"
}
}
},
"skins.vector.styles.experimental.print": {
"class": "Vector\\ResourceLoaderLessModule",
"targets": [ "desktop", "mobile" ],
"position": "top",
"styles": [
"print.less"
]
},
"skins.vector.styles.responsive": {
"targets": [ "desktop", "mobile" ],
"position": "top",
"styles": [
"responsive.less"
]
},
"skins.vector.js": {
"scripts": [
"collapsibleTabs.js",
"vector.js"
],
"position": "top",
"dependencies": [
"jquery.throttle-debounce",
"jquery.tabIndex"
]
}
},
"ResourceFileModulePaths": {
"localBasePath": "",
"remoteSkinPath": "Vector"
},
"ResourceModuleSkinStyles": {
"vector": {
"jquery.tipsy": "skinStyles/jquery.tipsy.less",
"jquery.ui.core": [
"skinStyles/jquery.ui/jquery.ui.core.css",
"skinStyles/jquery.ui/jquery.ui.theme.css"
],
"jquery.ui.accordion": "skinStyles/jquery.ui/jquery.ui.accordion.css",
"jquery.ui.autocomplete": "skinStyles/jquery.ui/jquery.ui.autocomplete.css",
"jquery.ui.button": "skinStyles/jquery.ui/jquery.ui.button.css",
"jquery.ui.datepicker": "skinStyles/jquery.ui/jquery.ui.datepicker.css",
"jquery.ui.dialog": "skinStyles/jquery.ui/jquery.ui.dialog.css",
"jquery.ui.menu": "skinStyles/jquery.ui/jquery.ui.menu.css",
"jquery.ui.progressbar": "skinStyles/jquery.ui/jquery.ui.progressbar.css",
"jquery.ui.resizable": "skinStyles/jquery.ui/jquery.ui.resizable.css",
"jquery.ui.selectable": "skinStyles/jquery.ui/jquery.ui.selectable.css",
"jquery.ui.slider": "skinStyles/jquery.ui/jquery.ui.slider.css",
"jquery.ui.spinner": "skinStyles/jquery.ui/jquery.ui.spinner.css",
"jquery.ui.tabs": "skinStyles/jquery.ui/jquery.ui.tabs.css",
"jquery.ui.tooltips": "skinStyles/jquery.ui/jquery.ui.tooltips.css",
"+mediawiki.action.view.redirectPage": "skinStyles/mediawiki.action.view.redirectPage.less",
"+mediawiki.notification": "skinStyles/mediawiki.notification.less",
"+oojs-ui-core.styles": "skinStyles/ooui.less",
"mediawiki.special": "skinStyles/mediawiki.special.less",
"+mediawiki.special.preferences.styles": "skinStyles/mediawiki.special.preferences.styles.less"
}
},
"config": {
"VectorUseSimpleSearch": true,
"VectorUseIconWatch": true,
"@VectorExperimentalPrintStyles": "Temporary config variable to feature flag new print styles (T154965)",
"VectorExperimentalPrintStyles": false,
"VectorResponsive": false,
"VectorPrintLogo": false
},
"manifest_version": 1
}

View File

@ -1,16 +1,23 @@
@html-font-size: 1em;
@import 'mediawiki.ui/variables';
@html-font-size: 100%;
@font-family-serif: 'Linux Libertine', 'Georgia', 'Times', serif;
@font-family-sans-serif: sans-serif;
// Page content
// FIXME: Use global variable since Echo and CentralNotice use this variable
@content-border-color: #a7d7f9;
// FIXME: Find an open font that works with this stack and is readable by Windows users
@content-font-family: "Open Sans", sans-serif;
@content-font-color: #252525;
@content-font-family: @font-family-sans-serif;
@content-font-color: #222;
@content-font-size: 0.875em;
@pureBlack: #000;
@content-line-height: 1.6;
@content-padding: 1em;
@content-heading-font-size: 1.8em;
@content-heading-font-family: "Open Sans", sans-serif;
@content-heading-font-family: @font-family-serif;
@content-heading-font-family-generic: sans-serif;
@body-background-color: #fff;
@heading-line-height: 1.3;
@ -22,22 +29,15 @@
// Main menu
@menu-main-font-size: inherit;
@menu-main-heading-font-size: 0.75em;
@menu-main-heading-padding: 0 1.75em 0.25em 0.25em;
@menu-main-heading-color: #444;
@menu-main-body-font-size: 0.75em;
@menu-main-body-link-color: #0645ad;
@menu-main-body-link-visited-color: #0b0080;
@menu-main-body-margin: 0 0 0 1.25em;
@menu-main-body-padding: 0;
@menu-main-logo-left: 0.5em;
@menu-main-body-margin-left: 0.5em;
@menu-main-body-padding: 0.3em 0 0 0;
// Personal menu
@menu-personal-font-size: 0.75em;
// Collapsible nav
@collapsible-nav-heading-color: #4d4d4d;
@collapsible-nav-heading-collapsed-color: #0645ad;
@collapsible-nav-heading-padding: 4px 0 3px 1.5em;
@collapsible-nav-body-margin: 0 0 0 1.25em;

View File

@ -1,152 +0,0 @@
/**
* Collapsible navigation for Vector
*/
( function ( mw, $ ) {
'use strict';
var map;
// Use the same function for all navigation headings - don't repeat
function toggle( $element ) {
var isCollapsed = $element.parent().is( '.collapsed' );
$.cookie(
'vector-nav-' + $element.parent().attr( 'id' ),
isCollapsed,
{ 'expires': 30, 'path': '/' }
);
$element
.parent()
.toggleClass( 'expanded' )
.toggleClass( 'collapsed' )
.find( '.body' )
.slideToggle( 'fast' );
isCollapsed = !isCollapsed;
$element
.find( '> a' )
.attr( {
'aria-pressed': isCollapsed ? 'false' : 'true',
'aria-expanded': isCollapsed ? 'false' : 'true'
} );
}
/* Browser Support */
map = {
// Left-to-right languages
ltr: {
// Collapsible Nav is broken in Opera < 9.6 and Konqueror < 4
opera: [['>=', 9.6]],
konqueror: [['>=', 4.0]],
blackberry: false,
ipod: false,
iphone: false,
ps3: false
},
// Right-to-left languages
rtl: {
opera: [['>=', 9.6]],
konqueror: [['>=', 4.0]],
blackberry: false,
ipod: false,
iphone: false,
ps3: false
}
};
if ( !$.client.test( map ) ) {
return true;
}
$( function ( $ ) {
var $headings, tabIndex;
/* General Portal Modification */
// Always show the first portal
$( '#mw-panel > .portal:first' ).addClass( 'first persistent' );
// Apply a class to the entire panel to activate styles
$( '#mw-panel' ).addClass( 'collapsible-nav' );
// Use cookie data to restore preferences of what to show and hide
$( '#mw-panel > .portal:not(.persistent)' )
.each( function ( i ) {
var id = $(this).attr( 'id' ),
state = $.cookie( 'vector-nav-' + id );
$(this).find( 'ul:first' ).attr( 'id', id + '-list' );
// Add anchor tag to heading for better accessibility
$( this ).find( 'h3' ).wrapInner(
$( '<a>' )
.attr( {
href: '#',
'aria-haspopup': 'true',
'aria-controls': id + '-list',
role: 'button'
} )
.click( false )
);
// In the case that we are not showing the new version, let's show the languages by default
if (
state === 'true' ||
( state === null && i < 1 ) ||
( state === null && id === 'p-lang' )
) {
$(this)
.addClass( 'expanded' )
.removeClass( 'collapsed' )
.find( '.body' )
.hide() // bug 34450
.show();
$(this).find( 'h3 > a' )
.attr( {
'aria-pressed': 'true',
'aria-expanded': 'true'
} );
} else {
$(this)
.addClass( 'collapsed' )
.removeClass( 'expanded' );
$(this).find( 'h3 > a' )
.attr( {
'aria-pressed': 'false',
'aria-expanded': 'false'
} );
}
// Re-save cookie
if ( state !== null ) {
$.cookie( 'vector-nav-' + $(this).attr( 'id' ), state, { 'expires': 30, 'path': '/' } );
}
} );
/* Tab Indexing */
$headings = $( '#mw-panel > .portal:not(.persistent) > h3' );
// Get the highest tab index
tabIndex = $( document ).lastTabIndex() + 1;
// Fix the search not having a tabindex
$( '#searchInput' ).attr( 'tabindex', tabIndex++ );
// Make it keyboard accessible
$headings.attr( 'tabindex', function () {
return tabIndex++;
});
// Toggle the selected menu's class and expand or collapse the menu
$( '#mw-panel' )
.delegate( '.portal:not(.persistent) > h3', 'keydown', function ( e ) {
// Make the space and enter keys act as a click
if ( e.which === 13 /* Enter */ || e.which === 32 /* Space */ ) {
toggle( $(this) );
}
} )
.delegate( '.portal:not(.persistent) > h3', 'mousedown', function ( e ) {
if ( e.which !== 3 ) { // Right mouse click
toggle( $(this) );
$(this).blur();
}
return false;
} );
});
}( mediaWiki, jQuery ) );

View File

@ -1,208 +0,0 @@
/**
* Collapsible tabs jQuery Plugin
*/
( function ( $ ) {
var rtl = $( 'html' ).attr( 'dir' ) === 'rtl';
$.fn.collapsibleTabs = function ( options ) {
// return if the function is called on an empty jquery object
if ( !this.length ) {
return this;
}
// Merge options into the defaults
var $settings = $.extend( {}, $.collapsibleTabs.defaults, options );
this.each( function () {
var $el = $( this );
// add the element to our array of collapsible managers
$.collapsibleTabs.instances = ( $.collapsibleTabs.instances.length === 0 ?
$el : $.collapsibleTabs.instances.add( $el ) );
// attach the settings to the elements
$el.data( 'collapsibleTabsSettings', $settings );
// attach data to our collapsible elements
$el.children( $settings.collapsible ).each( function () {
$.collapsibleTabs.addData( $( this ) );
} );
} );
// if we haven't already bound our resize handler, bind it now
if ( !$.collapsibleTabs.boundEvent ) {
$( window ).on( 'resize', $.debounce( 500, function () {
$.collapsibleTabs.handleResize();
} ) );
$.collapsibleTabs.boundEvent = true;
}
// call our resize handler to setup the page
$.collapsibleTabs.handleResize();
return this;
};
/**
* Returns the amount of horizontal distance between the two tabs groups
* (#left-navigation and #right-navigation), in pixels. If negative, this
* means that the tabs overlap, and the value is the width of overlapping
* parts.
*
* Used in default expandCondition and collapseCondition.
*
* @return {Numeric} distance/overlap in pixels
*/
function calculateTabDistance() {
var $leftTab, $rightTab, leftEnd, rightStart;
// In RTL, #right-navigation is actually on the left and vice versa.
// Hooray for descriptive naming.
if ( !rtl ) {
$leftTab = $( '#left-navigation' );
$rightTab = $( '#right-navigation' );
} else {
$leftTab = $( '#right-navigation' );
$rightTab = $( '#left-navigation' );
}
leftEnd = $leftTab.offset().left + $leftTab.width();
rightStart = $rightTab.offset().left;
return rightStart - leftEnd;
}
$.collapsibleTabs = {
instances: [],
boundEvent: null,
defaults: {
expandedContainer: '#p-views ul',
collapsedContainer: '#p-cactions ul',
collapsible: 'li.collapsible',
shifting: false,
expandCondition: function ( eleWidth ) {
// If there are at least eleWidth + 1 pixels of free space, expand.
// We add 1 because .width() will truncate fractional values
// but .offset() will not.
return calculateTabDistance() >= (eleWidth + 1);
},
collapseCondition: function () {
// If there's an overlap, collapse.
return calculateTabDistance() < 0;
}
},
addData: function ( $collapsible ) {
var $settings = $collapsible.parent().data( 'collapsibleTabsSettings' );
if ( $settings ) {
$collapsible.data( 'collapsibleTabsSettings', {
expandedContainer: $settings.expandedContainer,
collapsedContainer: $settings.collapsedContainer,
expandedWidth: $collapsible.width(),
prevElement: $collapsible.prev()
} );
}
},
getSettings: function ( $collapsible ) {
var $settings = $collapsible.data( 'collapsibleTabsSettings' );
if ( !$settings ) {
$.collapsibleTabs.addData( $collapsible );
$settings = $collapsible.data( 'collapsibleTabsSettings' );
}
return $settings;
},
handleResize: function () {
$.collapsibleTabs.instances.each( function () {
var $el = $( this ),
data = $.collapsibleTabs.getSettings( $el );
if ( data.shifting ) {
return;
}
// if the two navigations are colliding
if ( $el.children( data.collapsible ).length > 0 && data.collapseCondition() ) {
$el.trigger( 'beforeTabCollapse' );
// move the element to the dropdown menu
$.collapsibleTabs.moveToCollapsed( $el.children( data.collapsible + ':last' ) );
}
// if there are still moveable items in the dropdown menu,
// and there is sufficient space to place them in the tab container
if ( $( data.collapsedContainer + ' ' + data.collapsible ).length > 0 &&
data.expandCondition( $.collapsibleTabs.getSettings( $( data.collapsedContainer ).children(
data.collapsible + ':first' ) ).expandedWidth ) ) {
//move the element from the dropdown to the tab
$el.trigger( 'beforeTabExpand' );
$.collapsibleTabs
.moveToExpanded( data.collapsedContainer + ' ' + data.collapsible + ':first' );
}
} );
},
moveToCollapsed: function ( ele ) {
var outerData, expContainerSettings, target,
$moving = $( ele );
outerData = $.collapsibleTabs.getSettings( $moving );
if ( !outerData ) {
return;
}
expContainerSettings = $.collapsibleTabs.getSettings( $( outerData.expandedContainer ) );
if ( !expContainerSettings ) {
return;
}
expContainerSettings.shifting = true;
// Remove the element from where it's at and put it in the dropdown menu
target = outerData.collapsedContainer;
$moving.css( 'position', 'relative' )
.css( ( rtl ? 'left' : 'right' ), 0 )
.animate( { width: '1px' }, 'normal', function () {
var data, expContainerSettings;
$( this ).hide();
// add the placeholder
$( '<span class="placeholder" style="display: none;"></span>' ).insertAfter( this );
$( this ).detach().prependTo( target ).data( 'collapsibleTabsSettings', outerData );
$( this ).attr( 'style', 'display: list-item;' );
data = $.collapsibleTabs.getSettings( $( ele ) );
if ( data ) {
expContainerSettings = $.collapsibleTabs.getSettings( $( data.expandedContainer ) );
if ( expContainerSettings ) {
expContainerSettings.shifting = false;
$.collapsibleTabs.handleResize();
}
}
} );
},
moveToExpanded: function ( ele ) {
var data, expContainerSettings, $target, expandedWidth,
$moving = $( ele );
data = $.collapsibleTabs.getSettings( $moving );
if ( !data ) {
return;
}
expContainerSettings = $.collapsibleTabs.getSettings( $( data.expandedContainer ) );
if ( !expContainerSettings ) {
return;
}
expContainerSettings.shifting = true;
// grab the next appearing placeholder so we can use it for replacing
$target = $( data.expandedContainer ).find( 'span.placeholder:first' );
expandedWidth = data.expandedWidth;
$moving.css( 'position', 'relative' ).css( ( rtl ? 'right' : 'left' ), 0 ).css( 'width', '1px' );
$target.replaceWith(
$moving
.detach()
.css( 'width', '1px' )
.data( 'collapsibleTabsSettings', data )
.animate( { width: expandedWidth + 'px' }, 'normal', function () {
$( this ).attr( 'style', 'display: block;' );
var data, expContainerSettings;
data = $.collapsibleTabs.getSettings( $( this ) );
if ( data ) {
expContainerSettings = $.collapsibleTabs.getSettings( $( data.expandedContainer ) );
if ( expContainerSettings ) {
expContainerSettings.shifting = false;
$.collapsibleTabs.handleResize();
}
}
} )
);
}
};
}( jQuery ) );

View File

@ -1,28 +0,0 @@
/* Animate between standard and high definition layouts */
body.vector-animateLayout {
div#content,
div#footer,
#left-navigation {
.transition(margin-left 250ms, padding 250ms;);
}
#p-logo {
.transition(left 250ms);
}
#mw-panel {
.transition(padding-right 250ms);
}
#p-search {
.transition(margin-right 250ms);
}
#p-personal {
.transition(right 250ms);
}
#mw-head-base {
.transition(margin-left 250ms);
}
}

View File

@ -1,91 +0,0 @@
/**
* LESS Stylesheet for collapsible nav
*/
@import "mediawiki.mixins.less";
#mw-panel.collapsible-nav {
.portal {
background-position: left top;
background-repeat: no-repeat;
.background-image('images/portal-break.png');
padding: 0.25em 0 !important;
margin: -11px 9px 10px 11px;
h3 {
font-size: @menu-main-heading-font-size;
color: @collapsible-nav-heading-color;
font-weight: normal;
background-position: left center;
background-repeat: no-repeat;
.background-image-svg('images/arrow-expanded.svg', 'images/arrow-expanded.png');
padding: @collapsible-nav-heading-padding;
margin-bottom: 0;
&:hover {
cursor: pointer;
text-decoration: none;
}
a {
color: @collapsible-nav-heading-color;
text-decoration: none;
}
}
.body {
margin: @collapsible-nav-body-margin;
background-image: none !important;
padding-top: 0;
display: none;
ul {
li {
padding: 0.25em 0;
}
}
}
/* First */
&.first {
background-image: none;
margin-top: 0;
h3 {
display: none;
}
}
/* Persistent */
&.persistent {
.body {
display: block;
margin-left: 0.5em;
}
h3 {
background-image: none !important;
padding-left: 0.7em;
cursor: default;
}
}
/* Collapsed */
&.collapsed {
h3 {
color: @collapsible-nav-heading-collapsed-color;
background-position: left center;
background-repeat: no-repeat;
.background-image-svg('images/arrow-collapsed-ltr.svg', 'images/arrow-collapsed-ltr.png');
margin-bottom: 0;
&:hover {
text-decoration: underline;
}
a {
color: @collapsible-nav-heading-collapsed-color;
}
}
}
}
}

View File

@ -1,141 +0,0 @@
/*
* Any rules which should not be flipped automatically in right-to-left situations should be
* prepended with @noflip in a comment block.
*
* This stylesheet employs a few CSS trick to accomplish compatibility with a wide range of web
* browsers. The most common trick is to use some styles in IE6 only. This is accomplished by using
* a rule that makes things work in IE6, and then following it with a rule that begins with
* "html > body" or use a child selector ">", which is ignored by IE6 because it does not support
* the child selector. You can spot this by looking for the "OVERRIDDEN BY COMPLIANT BROWSERS" and
* "IGNORED BY IE6" comments.
*/
@import "mediawiki.mixins";
/* Framework */
html {
font-size: @html-font-size;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
font-family: @content-font-family;
}
body {
background-color: @menu-background-color;
}
/* Content */
div#content {
margin-left: 10em;
padding: @content-padding;
/* Border on top, left, and bottom side */
border: 1px solid @content-border-color;
border-right-width: 0;
/* Merge the border with tabs' one (in their background image) */
margin-top: -1px;
background-color: @body-background-color;
color: @content-font-color;
direction: ltr;
.mw-editsection,
.mw-editsection-like {
font-family: @content-font-family;
}
p {
line-height: inherit;
margin: 0.5em 0;
}
h1,
h2,
#firstHeading {
font-family: @content-heading-font-family;
line-height: @heading-line-height;
margin-bottom: 0.25em;
padding: 0;
}
h1,
#firstHeading {
font-size: @content-heading-font-size;
}
h2 {
font-size: 1.5em;
margin-top: 1em;
}
h3,
h4,
h5,
h6 {
line-height: @content-line-height;
margin-top: 0.3em;
margin-bottom: 0;
padding-bottom: 0;
}
h3 {
font-size: 1.17em;
}
h3,
h4 {
font-weight: bold;
}
h4,
h5,
h6 {
font-size: 100%; /* (reset) */
}
#toc h2,
.toc h2 {
font-size: 100%; /* (reset) */
font-family: @content-font-family;
}
}
/* Hide empty portlets */
div.emptyPortlet {
display: none;
}
ul {
list-style-type: disc;
.list-style-image('images/bullet-icon.png');
}
pre, .mw-code {
line-height: 1.3em;
}
/* Site Notice (includes notices from CentralNotice extension) */
#siteNotice {
font-size: 0.8em;
}
.redirectText {
font-size: 140%;
}
.redirectMsg img {
vertical-align: text-bottom;
}
#bodyContent {
position: relative;
width: 100%;
line-height: @content-line-height;
font-size: @content-font-size;
}
/* Tooltips are outside of the normal body code, so this helps make the size of the text sensible */
// FIXME: Should be part of jquery.tipsy.css
.tipsy {
font-size: 0.8em;
}

View File

@ -1,10 +0,0 @@
@import "mediawiki.mixins.less";
// External links
#content {
.external {
background-position: center right;
background-repeat: no-repeat;
.background-image-svg('images/external-link-ltr-icon.svg', 'images/external-link-ltr-icon.png');
padding-right: 13px;
}
}

View File

@ -1,57 +0,0 @@
/* Footer */
div#footer {
margin-left: 10em;
margin-top: 0;
padding: 0.75em;
direction: ltr;
ul {
list-style-type: none;
list-style-image: none;
margin: 0;
padding: 0;
li {
margin: 0;
padding: 0;
padding-top: 0.5em;
padding-bottom: 0.5em;
color: #333;
font-size: 0.7em;
}
}
#footer-icons {
float: right;
li {
float: left;
margin-left: 0.5em;
line-height: 2em;
text-align: right;
}
}
#footer-info {
li {
line-height: 1.4em;
}
}
#footer-places {
li {
float: left;
margin-right: 1em;
line-height: 2em;
}
}
}
body.ltr {
div#footer {
#footer-places {
/* @noflip */
float: left;
}
}
}

View File

@ -1,134 +0,0 @@
@import "mediawiki.mixins";
@import "personalMenu";
@import "collapsibleNav";
@import "search";
@import "tabs";
/* Hide, but keep accessible for screen-readers */
#mw-navigation h2 {
position: absolute;
top: -9999px;
}
/* Head */
#mw-page-base {
height: 5em;
background-position: bottom left;
background-repeat: repeat-x;
/* This image is only a fallback (for IE 6-9), so we do not @embed it. */
background-image: url('images/page-fade.png');
.vertical-gradient(@body-background-color, @menu-background-color, 50%, 100%);
background-color: @body-background-color;
}
#mw-head-base {
margin-top: -5em;
margin-left: 10em;
height: 5em;
}
div#mw-head {
position: absolute;
top: 0;
right: 0;
width: 100%;
h3 {
margin: 0;
padding: 0;
}
}
/* Navigation Containers */
#left-navigation {
float: left;
margin-left: 10em;
margin-top: 2.5em;
/* When right nav would overlap left nav, it's placed below it
(normal CSS floats behavior). This rule ensures that no empty space
is shown between them due to right nav's margin-top. Page layout
is still broken, but at least the nav overlaps only the page title
instead of half the content. */
margin-bottom: -2.5em;
/* IE 6 double-margin bug fix */
display: inline;
}
#right-navigation {
float: right;
margin-top: 2.5em;
}
/* Logo */
#p-logo {
position: absolute;
top: -160px;
left: 0;
width: 10em;
height: 160px;
a {
display: block;
width: 10em;
height: 160px;
background-repeat: no-repeat;
background-position: center center;
text-decoration: none;
}
}
/* Panel */
div#mw-panel {
font-size: @menu-main-font-size;
position: absolute;
top: 160px;
padding-top: 1em;
width: 10em;
left: 0;
div.portal {
padding-bottom: 1.5em;
direction: ltr;
h3 {
font-weight: normal;
color: #444;
padding: @menu-main-heading-padding;
cursor: default;
border: none;
font-size: @menu-main-heading-font-size;
}
div.body {
padding-top: 0.5em;
margin: @menu-main-body-margin;
.background-image('images/portal-break.png');
background-repeat: no-repeat;
background-position: top left;
ul {
list-style-type: none;
list-style-image: none;
padding: @menu-main-body-padding;
margin: 0;
li {
line-height: 1.125em;
padding: 0;
padding-bottom: 0.5em;
margin: 0;
font-size: @menu-main-body-font-size;
word-wrap: break-word;
a {
color: @menu-main-body-link-color;
&:visited {
color: @menu-main-body-link-visited-color;
}
}
}
}
}
}
}

View File

@ -1,20 +0,0 @@
/* mediawiki.notification */
.skin-vector {
.mw-notification-area {
font-size: 0.8em;
}
.mw-notification-area-layout {
top: 7em;
}
.mw-notification {
background-color: #fff;
background-color: rgba(255, 255, 255, 0.93);
padding: 0.75em 1.5em;
border: solid 1px @content-border-color;
border-radius: 0.75em;
-webkit-box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.125);
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.125);
}
}

View File

@ -1,41 +0,0 @@
/* Personal */
#p-personal {
position: absolute;
top: 0.33em;
right: 0.75em;
/* Display on top of page tabs - bugs 37158, 48078 */
z-index: 100;
h3 {
display: none;
}
ul {
list-style-type: none;
list-style-image: none;
margin: 0;
padding-left: 10em; /* Keep from overlapping logo */
}
li {
line-height: 1.125em;
/* @noflip */
float: left;
margin-left: 0.75em;
margin-top: 0.5em;
font-size: @menu-personal-font-size;
white-space: nowrap;
}
}
/* Icon for Usernames */
#pt-userpage,
#pt-anonuserpage,
#pt-login {
background-position: left top;
background-repeat: no-repeat;
/* SVG support using a transparent gradient to guarantee cross-browser
* compatibility (browsers able to understand gradient syntax support also SVG) */
.background-image-svg('images/user-icon.svg', 'images/user-icon.png');
padding-left: 15px !important;
}

View File

@ -1,113 +0,0 @@
/* Search */
#p-search {
/* @noflip */
float: left;
margin-right: 0.5em;
margin-left: 0.5em;
h3 {
display: none;
}
form,
input {
margin: 0;
margin-top: 0.4em;
}
}
div#simpleSearch {
display: block;
width: 14em;
height: 1.4em;
margin-top: 0.65em;
position: relative;
min-height: 1px; /* Gotta trigger hasLayout for IE7 */
border: solid 1px #aaa;
color: black;
background-color: white;
.background-image('images/search-fade.png');
background-position: top left;
background-repeat: repeat-x;
// Styles for both the search input and the button
input {
position: absolute;
margin: 0;
padding: 0;
border: 0;
background-color: transparent;
color: black;
}
// The search input
#searchInput {
top: 0;
left: 0;
width: 90%;
padding: 0.2em 0 0.2em 0.2em;
font-size: 13px;
direction: ltr;
&:focus {
outline: none;
}
// These rules MAY NOT be merged because of how CSS requires browsers
// to parse unrecognized selectors!
// Note these rules ensure that placeholder text can be distinguished from
// standard text. In browsers which make this distinction clear these rules
// are not necessary.
// For inputs that use jquery.placeholder.js e.g. IE9-
&.placeholder {
color: #999;
}
// Distinguish placeholder text in IE10+
&:-ms-input-placeholder {
color: #999;
}
// Distinguish placeholder text in Firefox 18-
&:-moz-placeholder {
color: #999;
}
// Undo the styles Webkit browsers apply to type=search fields,
// we provide our own
-webkit-appearance: textfield;
&::-webkit-search-decoration,
&::-webkit-search-cancel-button,
&::-webkit-search-results-button,
&::-webkit-search-results-decoration {
-webkit-appearance: textfield;
}
}
// The buttons. They are displayed in the same position, and if both are
// present the fulltext search one obscures the 'Go' one.
#searchButton,
#mw-searchButton {
top: 0;
right: 0;
width: 10%;
height: 100%;
cursor: pointer;
/* Hide button text and replace it with the image. */
/* This would be 100% if not for Firefox shenanigans (bug 60900). */
text-indent: 200%;
/* Needed to make IE6 respect the text-indent. */
line-height: 1;
/* Opera 12 on RTL flips the text in a funny way without this. */
/* @noflip */
direction: ltr;
white-space: nowrap;
overflow: hidden;
.background-image-svg('images/search-ltr.svg', 'images/search-ltr.png');
background-position: center center;
background-repeat: no-repeat;
}
#mw-searchButton {
z-index: 1;
}
}

View File

@ -1,274 +0,0 @@
/*
Styling for namespace tabs (page, discussion) and views (read, edit, view history, watch and other actions)
*/
/* Navigation Labels */
div.vectorTabs h3,
div.vectorMenu h3 span {
display: none;
}
/* Namespaces and Views */
div.vectorTabs {
/* @noflip */
float: left;
height: 2.5em;
.background-image('images/tab-break.png');
background-position: bottom left;
background-repeat: no-repeat;
padding-left: 1px;
ul {
/* @noflip */
float: left;
height: 100%;
list-style-type: none;
list-style-image: none;
margin: 0;
padding: 0;
.background-image('images/tab-break.png');
background-position: right bottom;
background-repeat: no-repeat;
li {
/* @noflip */
float: left;
line-height: 1.125em;
/* For IE6, overridden later to display:block by modern browsers */
display: inline-block;
height: 100%;
margin: 0;
padding: 0;
background-color: #f3f3f3;
.background-image('images/tab-normal-fade.png');
background-position: bottom left;
background-repeat: repeat-x;
white-space: nowrap;
}
/* IGNORED BY IE6 which doesn't support child selector */
> li {
display: block;
}
}
li {
&.new {
a,
a:visited{
color: #a55858;
}
}
&.selected {
.background-image('images/tab-current-fade.png');
a,
a:visited{
color: #333;
text-decoration: none;
}
}
&.icon {
a {
background-position: bottom right;
background-repeat: no-repeat;
}
}
a {
/* For IE6, overridden later to display:block by modern browsers */
display: inline-block;
height: 1.9em;
padding-left: 0.5em;
padding-right: 0.5em;
color: @menu-link-color;
cursor: pointer;
font-size: 0.8em;
}
/* Ignored by IE6 which doesn't support child selector */
> a {
display: block;
}
}
span {
display: inline-block;
.background-image('images/tab-break.png');
background-position: bottom right;
background-repeat: no-repeat;
a {
/* For IE6, overridden later to display:block by modern browsers */
display: inline-block;
padding-top: 1.25em;
}
/* Ignored by IE6 which doesn't support child selector */
> a {
/* @noflip */
float: left;
display: block;
}
}
}
/* Variants and Actions */
div.vectorMenu {
/* @noflip */
direction: ltr;
/* @noflip */
float: left;
.background-image-svg('images/arrow-down-icon.svg', 'images/arrow-down-icon.png');
/* @noflip */
background-position: 100% 60%;
background-repeat: no-repeat;
cursor: pointer;
.transition(background-position 250ms);
}
div.vectorMenu.menuForceShow {
background-position: 100% 100%;
}
div.vectorMenuFocus {
.background-image-svg('images/arrow-down-focus-icon.svg', 'images/arrow-down-focus-icon.png');
background-position: 100% 60%;
}
body.rtl div.vectorMenu {
/* @noflip */
direction: rtl;
}
/* OVERRIDDEN BY COMPLIANT BROWSERS */
div#mw-head div.vectorMenu h3 {
/* @noflip */
float: left;
.background-image('images/tab-break.png');
background-repeat: no-repeat;
background-position: bottom left;
margin-left: -1px;
}
/* IGNORED BY IE6 */
div#mw-head div.vectorMenu > h3 {
background-image: none;
}
div#mw-head div.vectorMenu h4,
div.vectorMenu#p-variants #mw-vector-current-variant {
display: inline-block;
float: left;
font-size: 0.8em;
padding-left: 0.5em;
padding-top: 1.375em;
font-weight: normal;
border: none;
}
/* OVERRIDDEN BY COMPLIANT BROWSERS */
div.vectorMenu h3 a {
display: inline-block;
width: 24px;
height: 1.9em;
text-decoration: none;
.background-image('images/tab-break.png');
background-repeat: no-repeat;
background-position: bottom right;
}
/* IGNORED BY IE6 */
div.vectorMenu h3 > a {
display: block;
}
div.vectorMenu div.menu {
position: relative;
display: none;
clear: both;
text-align: left;
}
/* OVERRIDDEN BY COMPLIANT BROWSERS */
body.rtl div.vectorMenu div.menu {
/* @noflip */
margin-left: 24px;
}
/* IGNORED BY IE6 */
body.rtl div.vectorMenu > div.menu {
/* @noflip */
margin-left: auto;
}
/* IGNORED BY IE6 */
/* Also fixes old versions of FireFox */
body.rtl div.vectorMenu > div.menu,
x:-moz-any-link {
/* @noflip */
margin-left: 23px;
}
/* Enable forcing showing of the menu for accessibility */
div.vectorMenu:hover div.menu,
div.vectorMenu.menuForceShow div.menu {
display: block;
}
div.vectorMenu ul {
position: absolute;
background-color: white;
border: solid 1px silver;
border-top-width: 0;
list-style-type: none;
list-style-image: none;
padding: 0;
margin: 0;
margin-left: -1px;
text-align: left;
}
/* Fixes old versions of FireFox */
div.vectorMenu ul,
x:-moz-any-link {
min-width: 5em;
}
/* Returns things back to normal in modern versions of FireFox */
div.vectorMenu ul,
x:-moz-any-link,
x:default {
min-width: 0;
}
div.vectorMenu li {
padding: 0;
margin: 0;
text-align: left;
line-height: 1em;
}
/* OVERRIDDEN BY COMPLIANT BROWSERS */
div.vectorMenu li a {
display: inline-block;
padding: 0.5em;
white-space: nowrap;
color: @menu-link-color;
cursor: pointer;
font-size: 0.8em;
}
/* IGNORED BY IE6 */
div.vectorMenu li > a {
display: block;
}
div.vectorMenu li.selected a,
div.vectorMenu li.selected a:visited {
color: #333;
text-decoration: none;
}
@import 'watchstar.less';

View File

@ -1,46 +0,0 @@
@import "mediawiki.mixins.rotation"
/* Watch/Unwatch Icon Styling */
#ca-unwatch.icon a,
#ca-watch.icon a {
margin: 0;
padding: 0;
display: block;
width: 26px;
/* This hides the text but shows the background image */
padding-top: 3.1em;
margin-top: 0;
/* Only applied in IE6 */
margin-top: -0.8em !ie;
height: 0;
overflow: hidden;
background-position: 5px 60%;
}
#ca-unwatch.icon a {
.background-image-svg('images/unwatch-icon.svg', 'images/unwatch-icon.png');
}
#ca-watch.icon a {
.background-image-svg('images/watch-icon.svg', 'images/watch-icon.png');
}
#ca-unwatch.icon a:hover,
#ca-unwatch.icon a:focus {
.background-image-svg('images/unwatch-icon-hl.svg', 'images/unwatch-icon-hl.png');
}
#ca-watch.icon a:hover,
#ca-watch.icon a:focus {
.background-image-svg('images/watch-icon-hl.svg', 'images/watch-icon-hl.png');
}
#ca-unwatch.icon a.loading,
#ca-watch.icon a.loading {
.background-image-svg('images/watch-icon-loading.svg', 'images/watch-icon-loading.png');
.rotation(700ms);
/* Suppress the hilarious rotating focus outline on Firefox */
outline: none;
background-position: 50% 60%;
-webkit-transform-origin: 50% 57%;
transform-origin: 50% 57%;
}
#ca-unwatch.icon a span,
#ca-watch.icon a span {
display: none;
}

View File

@ -1,284 +0,0 @@
<public:attach event="ondocumentready" onevent="CSSHover()" />
<script>
/**
* Whatever:hover - V3.11
* ------------------------------------------------------------
* Author - Peter Nederlof, http://www.xs4all.nl/~peterned
* License - http://creativecommons.org/licenses/LGPL/2.1
*
* Special thanks to Sergiu Dumitriu, http://purl.org/net/sergiu,
* for fixing the expression loop.
*
* Whatever:hover is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Whatever:hover is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* howto: body { behavior:url("csshover3.htc"); }
* ------------------------------------------------------------
*/
window.CSSHover = (function(){
// regular expressions, used and explained later on.
var REG_INTERACTIVE = /(^|\s)((([^a]([^ ]+)?)|(a([^#.][^ ]+)+)):(hover|active|focus))/i;
var REG_AFFECTED = /(.*?)\:(hover|active|focus)/i;
var REG_PSEUDO = /[^:]+:([a-z\-]+).*/i;
var REG_SELECT = /(\.([a-z0-9_\-]+):[a-z]+)|(:[a-z]+)/gi;
var REG_CLASS = /\.([a-z0-9_\-]*on(hover|active|focus))/i;
var REG_MSIE = /msie (5|6|7)/i;
var REG_COMPAT = /backcompat/i;
// property mapping, real css properties must be used in order to clear expressions later on...
// Uses obscure css properties that no-one is likely to use. The properties are borrowed to
// set an expression, and are then restored to the most likely correct value.
var Properties = {
index: 0,
list: ['text-kashida', 'text-kashida-space', 'text-justify'],
get: function() {
return this.list[(this.index++)%this.list.length];
}
};
// camelize is used to convert css properties from (eg) text-kashida to textKashida
var camelize = function(str) {
return str.replace(/-(.)/mg, function(result, match){
return match.toUpperCase();
});
};
/**
* Local CSSHover object
* --------------------------
*/
var CSSHover = {
// array of CSSHoverElements, used to unload created events
elements: [],
// buffer used for checking on duplicate expressions
callbacks: {},
// init, called once ondomcontentready via the exposed window.CSSHover function
init:function() {
// don't run in IE8 standards; expressions don't work in standards mode anyway,
// and the stuff we're trying to fix should already work properly
if(!REG_MSIE.test(navigator.userAgent) && !REG_COMPAT.test(window.document.compatMode)) {
return;
}
// start parsing the existing stylesheets
var sheets = window.document.styleSheets, l = sheets.length;
for(var i=0; i<l; i++) {
this.parseStylesheet(sheets[i]);
}
},
// called from init, parses individual stylesheets
parseStylesheet:function(sheet) {
// check sheet imports and parse those recursively
if(sheet.imports) {
try {
var imports = sheet.imports;
var l = imports.length;
for(var i=0; i<l; i++) {
this.parseStylesheet(sheet.imports[i]);
}
} catch(securityException){
// trycatch for various possible errors
}
}
// interate the sheet's rules and send them to the parser
try {
var rules = sheet.rules;
var r = rules.length;
for(var j=0; j<r; j++) {
this.parseCSSRule(rules[j], sheet);
}
} catch(someException){
// trycatch for various errors, most likely accessing the sheet's rules.
}
},
// magic starts here ...
parseCSSRule:function(rule, sheet) {
// The sheet is used to insert new rules into, this must be the same sheet the rule
// came from, to ensure that relative paths keep pointing to the right location.
// only parse a rule if it contains an interactive pseudo.
var select = rule.selectorText;
if(REG_INTERACTIVE.test(select)) {
var style = rule.style.cssText;
// affected elements are found by truncating the selector after the interactive pseudo,
// eg: "div li:hover" >> "div li"
var affected = REG_AFFECTED.exec(select)[1];
// that pseudo is needed for a classname, and defines the type of interaction (focus, hover, active)
// eg: "li:hover" >> "onhover"
var pseudo = select.replace(REG_PSEUDO, 'on$1');
// the new selector is going to use that classname in a new css rule,
// since IE6 doesn't support multiple classnames, this is merged into one classname
// eg: "li:hover" >> "li.onhover", "li.folder:hover" >> "li.folderonhover"
var newSelect = select.replace(REG_SELECT, '.$2' + pseudo);
// the classname is needed for the events that are going to be set on affected nodes
// eg: "li.folder:hover" >> "folderonhover"
var className = REG_CLASS.exec(newSelect)[1];
// no need to set the same callback more than once when the same selector uses the same classname
var hash = affected + className;
if(!this.callbacks[hash]) {
// affected elements are given an expression under a borrowed css property, because fake properties
// can't have their expressions cleared. Different properties are used per pseudo, to avoid
// expressions from overwriting eachother. The expression does a callback to CSSHover.patch,
// rerouted via the exposed window.CSSHover function.
var property = Properties.get();
var atRuntime = camelize(property);
// because the expression is added to the stylesheet, and styles are always applied to html that is
// dynamically added to the dom, the expression will also trigger for those new elements (provided
// they are selected by the affected selector).
sheet.addRule(affected, property + ':expression(CSSHover(this, "'+pseudo+'", "'+className+'", "'+atRuntime+'"))');
// hash it, so an identical selector/class combo does not duplicate the expression
this.callbacks[hash] = true;
}
// duplicate expressions need not be set, but the style could differ
sheet.addRule(newSelect, style);
}
},
// called via the expression, patches individual nodes
patch:function(node, type, className, property) {
// restores the borrowed css property to the value of its immediate parent, clearing
// the expression so that it's not repeatedly called.
try {
var value = node.parentNode.currentStyle[property];
node.style[property] = value;
} catch(e) {
// the above reset should never fail, but just in case, clear the runtimeStyle if it does.
// this will also stop the expression.
node.runtimeStyle[property] = '';
}
// just to make sure, also keep track of patched classnames locally on the node
if(!node.csshover) {
node.csshover = [];
}
// and check for it to prevent duplicate events with the same classname from being set
if(!node.csshover[className]) {
node.csshover[className] = true;
// create an instance for the given type and class
var element = new CSSHoverElement(node, type, className);
// and store that instance for unloading later on
this.elements.push(element);
}
// returns a dummy value to the expression
return type;
},
// unload stuff onbeforeunload
unload:function() {
try {
// remove events
var l = this.elements.length;
for(var i=0; i<l; i++) {
this.elements[i].unload();
}
// and set properties to null
this.elements = [];
this.callbacks = {};
} catch (e) {
}
}
};
/**
* CSSHoverElement
* --------------------------
*/
// the event types associated with the interactive pseudos
var CSSEvents = {
onhover: { activator: 'onmouseenter', deactivator: 'onmouseleave' },
onactive: { activator: 'onmousedown', deactivator: 'onmouseup' },
onfocus: { activator: 'onfocus', deactivator: 'onblur' }
};
// CSSHoverElement constructor, called via CSSHover.patch
function CSSHoverElement(node, type, className) {
// the CSSHoverElement patches individual nodes by manually applying the events that should
// have fired by the css pseudoclasses, eg mouseenter and mouseleave for :hover.
this.node = node;
this.type = type;
var replacer = new RegExp('(^|\\s)'+className+'(\\s|$)', 'g');
// store event handlers for removal onunload
this.activator = function(){ node.className += ' ' + className; };
this.deactivator = function(){ node.className = node.className.replace(replacer, ' '); };
// add the events
node.attachEvent(CSSEvents[type].activator, this.activator);
node.attachEvent(CSSEvents[type].deactivator, this.deactivator);
}
CSSHoverElement.prototype = {
// onbeforeunload, called via CSSHover.unload
unload:function() {
// remove events
this.node.detachEvent(CSSEvents[this.type].activator, this.activator);
this.node.detachEvent(CSSEvents[this.type].deactivator, this.deactivator);
// and set properties to null
this.activator = null;
this.deactivator = null;
this.node = null;
this.type = null;
}
};
// add the unload to the onbeforeunload event
window.attachEvent('onbeforeunload', function(){
CSSHover.unload();
});
/**
* Public hook
* --------------------------
*/
return function(node, type, className, property) {
if(node) {
// called via the css expression; patches individual nodes
return CSSHover.patch(node, type, className, property);
} else {
// called ondomcontentready via the public:attach node
CSSHover.init();
}
};
})();
</script>

View File

@ -1,12 +0,0 @@
<public:attach event="ondocumentready" onevent="CSSHover()" />
<script>
/**
* Whatever:hover - V3.11
* http://www.xs4all.nl/~peterned/
*
* Copyright (c) 2009 Peter Nederlof
* Licensed under the LGPL license
* http://creativecommons.org/licenses/LGPL/2.1
*/
window.CSSHover=(function(){var m=/(^|\s)((([^a]([^ ]+)?)|(a([^#.][^ ]+)+)):(hover|active|focus))/i;var n=/(.*?)\:(hover|active|focus)/i;var o=/[^:]+:([a-z\-]+).*/i;var p=/(\.([a-z0-9_\-]+):[a-z]+)|(:[a-z]+)/gi;var q=/\.([a-z0-9_\-]*on(hover|active|focus))/i;var s=/msie (5|6|7)/i;var t=/backcompat/i;var u={index:0,list:['text-kashida','text-kashida-space','text-justify'],get:function(){return this.list[(this.index++)%this.list.length]}};var v=function(c){return c.replace(/-(.)/mg,function(a,b){return b.toUpperCase()})};var w={elements:[],callbacks:{},init:function(){if(!s.test(navigator.userAgent)&&!t.test(window.document.compatMode)){return}var a=window.document.styleSheets,l=a.length;for(var i=0;i<l;i++){this.parseStylesheet(a[i])}},parseStylesheet:function(a){if(a.imports){try{var b=a.imports;var l=b.length;for(var i=0;i<l;i++){this.parseStylesheet(a.imports[i])}}catch(securityException){}}try{var c=a.rules;var r=c.length;for(var j=0;j<r;j++){this.parseCSSRule(c[j],a)}}catch(someException){}},parseCSSRule:function(a,b){var c=a.selectorText;if(m.test(c)){var d=a.style.cssText;var e=n.exec(c)[1];var f=c.replace(o,'on$1');var g=c.replace(p,'.$2'+f);var h=q.exec(g)[1];var i=e+h;if(!this.callbacks[i]){var j=u.get();var k=v(j);b.addRule(e,j+':expression(CSSHover(this, "'+f+'", "'+h+'", "'+k+'"))');this.callbacks[i]=true}b.addRule(g,d)}},patch:function(a,b,c,d){try{var f=a.parentNode.currentStyle[d];a.style[d]=f}catch(e){a.runtimeStyle[d]=''}if(!a.csshover){a.csshover=[]}if(!a.csshover[c]){a.csshover[c]=true;var g=new CSSHoverElement(a,b,c);this.elements.push(g)}return b},unload:function(){try{var l=this.elements.length;for(var i=0;i<l;i++){this.elements[i].unload()}this.elements=[];this.callbacks={}}catch(e){}}};var x={onhover:{activator:'onmouseenter',deactivator:'onmouseleave'},onactive:{activator:'onmousedown',deactivator:'onmouseup'},onfocus:{activator:'onfocus',deactivator:'onblur'}};function CSSHoverElement(a,b,c){this.node=a;this.type=b;var d=new RegExp('(^|\\s)'+c+'(\\s|$)','g');this.activator=function(){a.className+=' '+c};this.deactivator=function(){a.className=a.className.replace(d,' ')};a.attachEvent(x[b].activator,this.activator);a.attachEvent(x[b].deactivator,this.deactivator)}CSSHoverElement.prototype={unload:function(){this.node.detachEvent(x[this.type].activator,this.activator);this.node.detachEvent(x[this.type].deactivator,this.deactivator);this.activator=null;this.deactivator=null;this.node=null;this.type=null}};window.attachEvent('onbeforeunload',function(){w.unload()});return function(a,b,c,d){if(a){return w.patch(a,b,c,d)}else{w.init()}}})();
</script>

View File

@ -1,30 +0,0 @@
/* Vector screen styles for high definition displays */
@import "variables.less";
div#content {
margin-left: 11em;
padding: 1.25em 1.5em 1.5em 1.5em;
}
#p-logo {
left: @menu-main-logo-left;
}
div#footer {
margin-left: 11em;
padding: 1.25em;
}
#mw-panel {
padding-left: 0.5em;
}
#p-search {
margin-right: 1em;
}
#left-navigation {
margin-left: 11em;
}
#p-personal {
right: 1em;
}
#mw-head-base {
margin-left: 11em;
}

View File

@ -1,10 +0,0 @@
/* Vector screen styles */
@import "variables.less";
@import "components/common.less";
@import "components/animations.less";
@import "components/navigation.less";
@import "components/footer.less";
@import 'components/notifications.less';
@import "components/externalLinks.less";

View File

@ -1,7 +0,0 @@
/**
* Adjusts for decreased margin-bottom for h2 elements inside #content div
* introduced in March / April 2014 typography update.
*/
table.mw-specialpages-table {
margin-top: 0;
}

View File

@ -1,114 +0,0 @@
@import "mediawiki.mixins";
@import "variables";
/**
* The following code is highly modified from monobook. It would be nice if the
* preftoc id was more human readable like preferences-toc for instance,
* howerver this would require backporting the other skins.
*/
#preftoc {
/* Tabs */
width: 100%;
float: left;
clear: both;
margin: 0 !important;
padding: 0 !important;
.background-image('images/preferences/break.png');
background-position: bottom left;
background-repeat: no-repeat;
li {
/* Tab */
float: left;
margin: 0;
padding: 0;
padding-right: 1px;
height: 2.25em;
white-space: nowrap;
list-style-type: none;
list-style-image: none;
.background-image('images/preferences/break.png');
background-position: bottom right;
background-repeat: no-repeat;
/* Sadly, IE6 won't understand this */
&:first-child {
margin-left: 1px;
}
&.selected {
a {
.background-image('images/preferences/fade.png');
background-position: bottom;
background-repeat: repeat-x;
color: #333;
text-decoration: none;
}
}
}
a,
a:active {
display: inline-block;
position: relative;
color: @menu-link-color;
padding: 0.5em;
text-decoration: none;
background-image: none;
font-size: 0.9em;
}
a:hover,
a:focus {
text-decoration: underline;
}
}
#preferences {
float: left;
width: 100%;
margin: 0;
margin-top: -2px;
clear: both;
border: solid 1px #ccc;
background-color: #fafafa;
fieldset {
border: none;
border-top: solid 1px #ccc;
&.prefsection {
border: none;
padding: 0;
margin: 1em;
legend.mainLegend {
display: none;
}
}
}
legend {
color: #666;
}
td {
padding-left: 0.5em;
padding-right: 0.5em;
}
div.mw-prefs-buttons {
padding: 1em;
input {
margin-right: 0.25em;
}
}
}
.htmlform-tip {
font-size: x-small;
padding: .2em 2em;
color: #666;
}

View File

@ -1,55 +0,0 @@
/**
* Vector-specific scripts
*/
jQuery( function ( $ ) {
$( 'div.vectorMenu' ).each( function () {
var $el = $( this );
$el.find( '> h3 > a' ).parent()
.attr( 'tabindex', '0' )
// For accessibility, show the menu when the h3 is clicked (bug 24298/46486)
.on( 'click keypress', function ( e ) {
if ( e.type === 'click' || e.which === 13 ) {
$el.toggleClass( 'menuForceShow' );
e.preventDefault();
}
} )
// When the heading has focus, also set a class that will change the arrow icon
.focus( function () {
$el.find( '> a' ).addClass( 'vectorMenuFocus' );
} )
.blur( function () {
$el.find( '> a' ).removeClass( 'vectorMenuFocus' );
} )
.find( '> a:first' )
// As the h3 can already be focused there's no need for the link to be focusable
.attr( 'tabindex', '-1' );
} );
/**
* Collapsible tabs for Vector
*/
var $cactions = $( '#p-cactions' );
// Bind callback functions to animate our drop down menu in and out
// and then call the collapsibleTabs function on the menu
$( '#p-views ul' )
.bind( 'beforeTabCollapse', function () {
// If the dropdown was hidden, show it
if ( $cactions.hasClass( 'emptyPortlet' ) ) {
$cactions
.removeClass( 'emptyPortlet' )
.find( 'h3' )
.css( 'width', '1px' ).animate( { 'width': '24px' }, 390 );
}
} )
.bind( 'beforeTabExpand', function () {
// If we're removing the last child node right now, hide the dropdown
if ( $cactions.find( 'li' ).length === 1 ) {
$cactions.find( 'h3' ).animate( { 'width': '1px' }, 390, function () {
$( this ).attr( 'style', '' )
.parent().addClass( 'emptyPortlet' );
});
}
} )
.collapsibleTabs();
} );