var $mHTMLtitle = '', $mIsarticle = true, $mPrintable = false;
var $mSubtitle = '', $mRedirect = '', $mStatusCode;
var $mLastModified = '', $mETag = false;
- var $mCategoryLinks = array(), $mLanguageLinks = array();
-
- var $mScriptLoaderClassList = array();
+ var $mCategoryLinks = array(), $mCategories = array(), $mLanguageLinks = array();
var $mScripts = '', $mLinkColours, $mPageLinkTitle = '', $mHeadItems = array();
var $mInlineMsg = array();
var $mContainsOldMagic = 0, $mContainsNewMagic = 0;
var $mIsArticleRelated = true;
protected $mParserOptions = null; // lazy initialised, use parserOptions()
-
+
var $mFeedLinks = array();
-
+
var $mEnableClientCache = true;
var $mArticleBodyOnly = false;
private $mIndexPolicy = 'index';
private $mFollowPolicy = 'follow';
+ private $mVaryHeader = array( 'Accept-Encoding' => array('list-contains=gzip'),
+ 'Cookie' => null );
/**
* Constructor
* @param string $file filename in skins/common or complete on-server path (/foo/bar.js)
*/
function addScriptFile( $file ) {
- global $wgStylePath, $wgScript, $wgUser;
- global $wgEnableScriptLoader, $wgScriptPath;
-
+ global $wgStylePath, $wgStyleVersion, $wgJsMimeType;
if( substr( $file, 0, 1 ) == '/' ) {
$path = $file;
} else {
- $path = "{$wgStylePath}/common/{$file}";
- }
-
- // If the class can be determined, use the addScriptClass method
- $js_class = $this->getJsClassFromPath( $path );
- if( $js_class ) {
- $this->addScriptClass( $js_class );
- return true;
- }
-
- //do checks for wiki-titles
- if( strpos( $path, $wgScript ) !== false ) {
- $reqPath = str_replace( $wgScript . '?', '', $path );
- $reqArgs = explode( '&', $reqPath );
- $reqSet = array();
-
- foreach( $reqArgs as $arg ) {
- list( $key, $var ) = explode( '=', $arg );
- $reqSet[$key] = $var;
- }
-
- if( isset( $reqSet['title'] ) && $reqSet != '' ) {
- $jsTitleClass = 'WT:' . $reqSet['title'];
- if( $wgEnableScriptLoader ) {
- // Extract any extra parameters (for now just skin)
- $ext_param = ( isset( $reqSet['useskin'] ) && $reqSet['useskin'] != '' )
- ? '|useskin=' . ucfirst( $reqSet['useskin'] ) : '';
- $this->mScriptLoaderClassList[] = $jsTitleClass . $ext_param ;
- return true;
- }else{
- $this->addScript( Html::linkedScript(
- wfAppendQuery( $path, $this->getURIDparam( $jsTitleClass ) )
- )
- );
- return true;
- }
- }
- }
- // If the script loader could not be used, just add the script to the header
- $this->addScript( Html::linkedScript( wfAppendQuery( $path, $this->getURIDparam() ) ) );
- }
-
- /**
- * Add the core scripts that are included on every page, for later output into the header
- *
- * this includes the conditional sitejs
- */
- function addCoreScripts2Top(){
- global $wgEnableScriptLoader, $wgJSAutoloadLocalClasses, $wgScriptPath, $wgEnableJS2system;
- global $wgUser, $wgJsMimeType;
- // @todo We should deprecate wikibits in favor of some mv_embed pieces and jQuery
-
- if( $wgEnableJS2system ){
- $core_classes = array( 'window.jQuery', 'mv_embed', 'wikibits' );
- } else {
- $core_classes = array( 'wikibits' );
+ $path = "{$wgStylePath}/common/{$file}";
}
-
- //make sure scripts are on top:
- $postScripts = $this->mScripts;
- $this->mScripts = '';
-
- if( $wgEnableScriptLoader ){
- //directly add script_loader call
- //(separate from other scriptloader calls that may include extensions with conditional js)
- $this->mScripts = $this->getScriptLoaderJs( $core_classes );
- } else {
- $so = '';
- foreach( $core_classes as $js_class ){
- $this->addScriptClass( $js_class );
- }
- }
- //now re-append any scripts that got added prior to the addCoreScripts2Top call
- $this->mScripts = $this->mScripts . $postScripts;
- }
-
- /**
- * @param string $js_class Name of the JavaScript class
- * @return boolean False if the class wasn't found, true on success
- */
- function addScriptClass( $js_class ){
- global $wgDebugJavaScript, $wgJSAutoloadLocalClasses, $wgJSAutoloadClasses,
- $wgEnableScriptLoader, $wgStyleVersion, $wgScriptPath, $wgStylePath, $wgEnableJS2system;
-
- $path = jsScriptLoader::getJsPathFromClass( $js_class );
- if( $path !== false ){
- if( $wgEnableScriptLoader ) {
- // Register it with the script loader
- if( !in_array( $js_class, $this->mScriptLoaderClassList ) ) {
- $this->mScriptLoaderClassList[] = $js_class;
- }
- } else {
- // Source the script directly
- $prefix = "skins/common/";
- if( substr( $path, 0, 1 ) == '/' ) {
- // straight path
- } elseif( substr( $path, 0, strlen( $prefix ) ) == $prefix ) {
- // Respect $wgStypePath
- $path = "{$wgStylePath}/common/" . substr( $path, strlen( $prefix ) );
- } else {
- $path = $wgScriptPath . '/' . $path;
- }
- $urlAppend = ( $wgDebugJavaScript ) ? time() : $this->getURIDparam( $js_class );
- $this->addScript( Html::linkedScript( "$path?$urlAppend" ) );
-
- //merge in language text (if js2 is on and we have loadGM function)
- if( $wgEnableJS2system ){
- $inlineMsg = jsScriptLoader::getLocalizedMsgsFromClass( $js_class );
- if( $inlineMsg != '' )
- $this->addScript( Html::inlineScript( $inlineMsg ));
- }
- }
- return true;
- }
- print "could not find: $js_class\n";
- wfDebug( __METHOD__ . ' could not find js_class: ' . $js_class );
- return false; // could not find the class
- }
-
- /**
- * Get the <script> tag which will invoke the script loader
- * @param $classAry A class array which, if given, overrides $this->mScriptLoaderClassList
- */
- function getScriptLoaderJs( $classAry = array() ) {
- global $wgRequest, $wgDebugJavaScript;
- // If no class array was provided, use mScriptLoaderClassList
- if( !count( $classAry ) ) {
- $classAry = $this->mScriptLoaderClassList;
- }
- $class_list = implode( ',', $classAry );
-
- $debug_param = ( $wgDebugJavaScript ||
- $wgRequest->getVal( 'debug' ) == 'true' ||
- $wgRequest->getVal( 'debug' ) == '1' )
- ? '&debug=true' : '';
-
- return Html::linkedScript( wfScript( 'mwScriptLoader' ) .
- "?class={$class_list}{$debug_param}&" . $this->getURIDparam( $classAry) ) . "\n";
- }
-
- /**
- * Get the unique request ID parameter for the script-loader request
- */
- function getURIDparam( $classAry = array() ) {
- global $wgDebugJavaScript, $wgStyleVersion, $IP, $wgScriptModifiedCheck;
- if( $wgDebugJavaScript ) {
- return 'urid=' . time();
- } else {
- //support single class_name attr
- if( gettype( $classAry) == 'string' ){
- $classAry = array( $classAry );
- }
- $ftime = $frev = 0;
- foreach( $classAry as $class ) {
- if( $wgScriptModifiedCheck ) {
- $js_path = jsScriptLoader::getJsPathFromClass( $class );
- if( $js_path ) {
- $cur_ftime = filemtime ( $IP ."/". $js_path );
- if( $cur_ftime > $ftime )
- $ftime = $cur_ftime;
- }
- }
- // Add the latest revision ID if the class set includes a WT (wiki title)
- if( substr($class, 0, 3) == 'WT:'){
- $title_str = substr($class, 3);
- $t = Title::newFromText( $title_str );
- if( $t && $t->exists() ) {
- if( $t->getLatestRevID() > $frev )
- $frev = $t->getLatestRevID();
- }
- }
- }
- //build the actual unique request id:
- $urid = "urid={$wgStyleVersion}";
-
- // Add the file modification time if set
- if( $ftime != 0 )
- $urid .= "_" . $ftime;
-
- //add the wiki rev id if set
- if( $frev != 0 )
- $urid.= "_" . $frev;
-
- return $urid;
- }
- }
-
- /**
- * Given a script path, get the JS class name, or false if no such path is registered.
- * @param $path string
- */
- function getJsClassFromPath( $path ) {
- global $wgJSAutoloadClasses, $wgJSAutoloadLocalClasses, $wgScriptPath;
-
- $scriptLoaderPaths = array_merge( $wgJSAutoloadClasses, $wgJSAutoloadLocalClasses );
- foreach( $scriptLoaderPaths as $js_class => $js_path ) {
- $js_path = "{$wgScriptPath}/{$js_path}";
- if( $path == $js_path )
- return $js_class;
- }
- return false;
+ $this->addScript(
+ Xml::element( 'script',
+ array(
+ 'type' => $wgJsMimeType,
+ 'src' => "$path?$wgStyleVersion",
+ ),
+ '', false
+ )
+ );
}
/**
* Get all registered JS and CSS tags for the header.
*/
function getScript() {
- global $wgEnableScriptLoader;
- if( $wgEnableScriptLoader ){
- return $this->mScripts . "\n" . $this->getScriptLoaderJs() . $this->getHeadItems();
- } else {
- return $this->mScripts . $this->getHeadItems();
- }
+ return $this->mScripts . $this->getHeadItems();
}
function getHeadItems() {
* This function allows good tags like <sup> in the <h1> tag, but not bad tags like <script>.
* This function automatically sets <title> to the same content as <h1> but with all tags removed.
* Bad tags that were escaped in <h1> will still be escaped in <title>, and good tags like <i> will be dropped entirely.
- */
+ */
public function setPageTitle( $name ) {
global $wgContLang;
$name = $wgContLang->convert( $name, true );
public function getOnloadHandler() { return $this->mOnloadHandler; }
public function disable() { $this->mDoNothing = true; }
public function isDisabled() { return $this->mDoNothing; }
-
+
public function setSyndicated( $show = true ) { $this->mShowFeedLinks = $show; }
-
+
public function setFeedAppendQuery( $val ) {
global $wgFeedClasses;
-
+
$this->mFeedLinks = array();
-
+
foreach( $wgFeedClasses as $type => $class ) {
$query = "feed=$type&".$val;
$this->mFeedLinks[$type] = $this->getTitle()->getLocalURL( $query );
}
}
-
+
public function addFeedLink( $format, $href ) {
$this->mFeedLinks[$format] = $href;
}
-
+
public function isSyndicated() { return count($this->mFeedLinks); }
public function setArticleRelated( $v ) {
return $this->mCategoryLinks;
}
+ public function getCategories() {
+ return $this->mCategories;
+ }
+
/**
* Add an array of categories, with names in the keys
*/
if ( array_key_exists( $category, $categories ) )
continue;
$text = $wgContLang->convertHtml( $title->getText() );
+ $this->mCategories[] = $title->getText();
$this->mCategoryLinks[$type][] = $sk->link( $title, $text );
}
}
return false;
}
+ public function addVaryHeader( $header, $option = null ) {
+ if ( !array_key_exists( $header, $this->mVaryHeader ) ) {
+ $this->mVaryHeader[$header] = $option;
+ }
+ elseif( is_array( $option ) ) {
+ if( is_array( $this->mVaryHeader[$header] ) ) {
+ $this->mVaryHeader[$header] = array_merge( $this->mVaryHeader[$header], $option );
+ }
+ else {
+ $this->mVaryHeader[$header] = $option;
+ }
+ }
+ $this->mVaryHeader[$header] = array_unique( $this->mVaryHeader[$header] );
+ }
+
/** Get a complete X-Vary-Options header */
public function getXVO() {
$cvCookies = $this->getCacheVaryCookies();
- $xvo = 'X-Vary-Options: Accept-Encoding;list-contains=gzip,Cookie;';
- $first = true;
+
+ $cookiesOption = array();
foreach ( $cvCookies as $cookieName ) {
- if ( $first ) {
- $first = false;
- } else {
- $xvo .= ';';
- }
- $xvo .= 'string-contains=' . $cookieName;
+ $cookiesOption[] = 'string-contains=' . $cookieName;
}
+ $this->addVaryHeader( 'Cookie', $cookiesOption );
+
+ $headers = array();
+ foreach( $this->mVaryHeader as $header => $option ) {
+ $newheader = $header;
+ if( is_array( $option ) )
+ $newheader .= ';' . implode( ';', $option );
+ $headers[] = $newheader;
+ }
+ $xvo = 'X-Vary-Options: ' . implode( ',', $headers );
+
return $xvo;
}
# don't serve compressed data to clients who can't handle it
# maintain different caches for logged-in users and non-logged in ones
- $response->header( 'Vary: Accept-Encoding, Cookie' );
+ $response->header( 'Vary: ' . join( ', ', array_keys( $this->mVaryHeader ) ) );
if ( $wgUseXVO ) {
# Add an X-Vary-Options header for Squid with Wikimedia patches
$response->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
$response->header( 'Pragma: no-cache' );
}
+ wfRunHooks('CacheHeadersAfterSet', array( $this ) );
}
/**
$sk = $wgUser->getSkin();
- // Add our core scripts to output
- $this->addCoreScripts2Top();
-
if ( $wgUseAjax ) {
$this->addScriptFile( 'ajax.js' );
$this->addScriptFile( 'rightclickedit.js' );
}
- global $wgUseAJAXCategories, $wgEnableJS2system;
- if ($wgUseAJAXCategories && $wgEnableJS2system) {
- global $wgAJAXCategoriesNamespaces;
-
- $title = $this->getTitle();
-
- if( empty( $wgAJAXCategoriesNamespaces ) || in_array( $title->getNamespace(), $wgAJAXCategoriesNamespaces ) ) {
- $this->addScriptClass( 'ajaxCategories' );
- }
- }
-
if( $wgUniversalEditButton ) {
if( isset( $wgArticle ) && $this->getTitle() && $this->getTitle()->quickUserCan( 'edit' )
&& ( $this->getTitle()->exists() || $this->getTitle()->quickUserCan( 'create' ) ) ) {
*/
public function headElement( Skin $sk, $includeStyle = true ) {
global $wgDocType, $wgDTD, $wgContLanguageCode, $wgOutputEncoding, $wgMimeType;
- global $wgXhtmlDefaultNamespace, $wgXhtmlNamespaces;
- global $wgContLang, $wgUseTrackbacks, $wgStyleVersion, $wgEnableScriptLoader, $wgHtml5;
+ global $wgXhtmlDefaultNamespace, $wgXhtmlNamespaces, $wgHtml5Version;
+ global $wgContLang, $wgUseTrackbacks, $wgStyleVersion, $wgHtml5;
$this->addMeta( "http:Content-Type", "$wgMimeType; charset={$wgOutputEncoding}" );
if ( $sk->commonPrintStylesheet() ) {
$dir = $wgContLang->getDir();
if ( $wgHtml5 ) {
- $ret .= "<!doctype html>\n";
- $ret .= "<html lang=\"$wgContLanguageCode\" dir=\"$dir\">\n";
+ $ret .= "<!DOCTYPE html>\n";
+ $ret .= "<html lang=\"$wgContLanguageCode\" dir=\"$dir\" ";
+ if ($wgHtml5Version) $ret .= " version=\"$wgHtml5Version\" ";
+ $ret .= ">\n";
} else {
$ret .= "<!DOCTYPE html PUBLIC \"$wgDocType\" \"$wgDTD\">\n";
$ret .= "<html xmlns=\"{$wgXhtmlDefaultNamespace}\" ";
$ret .= Html::inlineStyle( $sk->usercss );
}
- if( $wgEnableScriptLoader )
- $ret .= $this->getScriptLoaderJs();
-
if ($wgUseTrackbacks && $this->isArticleRelated())
$ret .= $this->getTitle()->trackbackRDF();
*/
function getHeadScripts( Skin $sk ) {
global $wgUser, $wgRequest, $wgJsMimeType, $wgUseSiteJs;
+ global $wgStylePath, $wgStyleVersion;
- $vars = Skin::makeGlobalVariablesScript( $sk->getSkinName() );
+ $scripts = Skin::makeGlobalVariablesScript( $sk->getSkinName() );
+ $scripts .= Html::linkedScript( "{$wgStylePath}/common/wikibits.js?$wgStyleVersion" );
//add site JS if enabled:
if( $wgUseSiteJs ) {
- $sk = $wgUser->getSkin();
$jsCache = $wgUser->isLoggedIn() ? '&smaxage=0' : '';
$this->addScriptFile( Skin::makeUrl( '-',
"action=raw$jsCache&gen=js&useskin=" .
//add user js if enabled:
if( $this->isUserJsAllowed() && $wgUser->isLoggedIn() ) {
$action = $wgRequest->getVal( 'action', 'view' );
- if( $this->mTitle->isJsSubpage() and $sk->userCanPreview( $action ) ) {
+ if( $this->mTitle && $this->mTitle->isJsSubpage() and $sk->userCanPreview( $action ) ) {
# XXX: additional security check/prompt?
$this->addInlineScript( $wgRequest->getText( 'wpTextbox1' ) );
} else {
}
}
- return $vars . "\n" . $this->mScripts;
+ $scripts .= "\n" . $this->mScripts;
+ return $scripts;
}
protected function addDefaultMeta() {
* Return URLs for each supported syndication format for this page.
* @return array associating format keys with URLs
*/
- public function getSyndicationLinks() {
+ public function getSyndicationLinks() {
return $this->mFeedLinks;
}