diff options
author | Luke Shumaker <LukeShu@sbcglobal.net> | 2014-01-28 09:50:25 -0500 |
---|---|---|
committer | Luke Shumaker <LukeShu@sbcglobal.net> | 2014-01-28 09:50:25 -0500 |
commit | 5744df39e15f85c6cc8a9faf8924d77e76d2b216 (patch) | |
tree | a8c8dd40a94d1fa0d5377566aa5548ae55a163da /includes/OutputPage.php | |
parent | 4bb2aeca1d198391ca856aa16c40b8559c68daec (diff) | |
parent | 224b22a051051f6c2e494c3a2fb4adb42898e2d1 (diff) |
Merge branch 'archwiki'
Conflicts:
extensions/FluxBBAuthPlugin.php
extensions/SyntaxHighlight_GeSHi/README
extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.class.php
extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.i18n.php
extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.php
extensions/SyntaxHighlight_GeSHi/geshi/docs/CHANGES
extensions/SyntaxHighlight_GeSHi/geshi/docs/THANKS
extensions/SyntaxHighlight_GeSHi/geshi/docs/TODO
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractClass.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractClass_logo.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractMethod.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractPrivateClass.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractPrivateClass_logo.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractPrivateMethod.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Class.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Class_logo.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Constant.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Constructor.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Destructor.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Function.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Global.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/I.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Index.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Interface.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Interface_logo.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/L.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Lminus.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Lplus.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Method.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Page.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Page_logo.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateClass.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateClass_logo.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateMethod.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateVariable.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/StaticMethod.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/StaticVariable.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/T.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Tminus.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Tplus.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Variable.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/blank.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/class_folder.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/file.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/folder.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/function_folder.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/next_button.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/next_button_disabled.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/package.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/package_folder.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/previous_button.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/previous_button_disabled.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/private_class_logo.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/tutorial.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/tutorial_folder.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/up_button.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/geshi-doc.html
extensions/SyntaxHighlight_GeSHi/geshi/docs/geshi-doc.txt
extensions/SyntaxHighlight_GeSHi/geshi/geshi.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/4cs.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/6502acme.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/6502kickass.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/6502tasm.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/68000devpac.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/abap.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/actionscript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/actionscript3.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/ada.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/algol68.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/apache.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/applescript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/apt_sources.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/asm.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/asp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/autoconf.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/autohotkey.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/autoit.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/avisynth.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/awk.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/bascomavr.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/bash.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/basic4gl.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/bf.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/bibtex.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/blitzbasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/bnf.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/boo.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/c.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/c_loadrunner.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/c_mac.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/caddcl.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cadlisp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cfdg.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cfm.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/chaiscript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cil.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/clojure.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cmake.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cobol.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/coffeescript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cpp-qt.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cpp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/csharp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/css.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cuesheet.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/d.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/dcs.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/delphi.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/diff.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/div.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/dos.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/dot.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/e.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/ecmascript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/eiffel.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/email.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/epc.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/erlang.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/euphoria.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/f1.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/falcon.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/fo.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/fortran.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/freebasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/fsharp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/gambas.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/gdb.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/genero.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/genie.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/gettext.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/glsl.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/gml.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/gnuplot.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/go.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/groovy.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/gwbasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/haskell.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/hicest.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/hq9plus.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/html4strict.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/html5.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/icon.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/idl.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/ini.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/inno.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/intercal.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/io.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/j.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/java.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/java5.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/javascript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/jquery.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/kixtart.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/klonec.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/klonecpp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/latex.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lb.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lisp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/llvm.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/locobasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/logtalk.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lolcode.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lotusformulas.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lotusscript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lscript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lsl2.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lua.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/m68k.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/magiksf.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/make.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/mapbasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/matlab.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/mirc.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/mmix.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/modula2.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/modula3.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/mpasm.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/mxml.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/mysql.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/newlisp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/nsis.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/oberon2.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/objc.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/objeck.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/ocaml-brief.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/ocaml.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/oobas.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/oracle11.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/oracle8.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/oxygene.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/oz.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pascal.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pcre.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/per.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/perl.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/perl6.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pf.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/php-brief.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/php.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pic16.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pike.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pixelbender.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pli.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/plsql.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/postgresql.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/povray.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/powerbuilder.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/powershell.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/proftpd.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/progress.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/prolog.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/properties.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/providex.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/purebasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pycon.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/python.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/q.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/qbasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/rails.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/rebol.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/reg.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/robots.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/rpmspec.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/rsplus.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/ruby.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/sas.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/scala.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/scheme.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/scilab.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/sdlbasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/smalltalk.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/smarty.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/sql.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/systemverilog.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/tcl.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/teraterm.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/text.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/thinbasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/tsql.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/typoscript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/unicon.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/uscript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/vala.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/vb.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/vbnet.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/verilog.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/vhdl.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/vim.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/visualfoxpro.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/visualprolog.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/whitespace.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/whois.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/winbatch.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/xbasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/xml.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/xorg_conf.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/xpp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/yaml.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/z80.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/zxbasic.php
Diffstat (limited to 'includes/OutputPage.php')
-rw-r--r-- | includes/OutputPage.php | 804 |
1 files changed, 442 insertions, 362 deletions
diff --git a/includes/OutputPage.php b/includes/OutputPage.php index b4a81bb1..7f0454f6 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -39,10 +39,8 @@ class OutputPage extends ContextSource { /// Should be private. Used with addMeta() which adds "<meta>" var $mMetatags = array(); - /// "<meta keywords='stuff'>" most of the time the first 10 links to an article - var $mKeywords = array(); - var $mLinktags = array(); + var $mCanonicalUrl = false; /// Additional stylesheets. Looks like this is for extensions. Might be replaced by resource loader. var $mExtStyles = array(); @@ -122,7 +120,7 @@ class OutputPage extends ContextSource { var $mScripts = ''; /** - * Inline CSS styles. Use addInlineStyle() sparsingly + * Inline CSS styles. Use addInlineStyle() sparingly */ var $mInlineStyles = ''; @@ -248,6 +246,21 @@ class OutputPage extends ContextSource { private $mRedirectedFrom = null; /** + * Additional key => value data + */ + private $mProperties = array(); + + /** + * @var string|null: ResourceLoader target for load.php links. If null, will be omitted + */ + private $mTarget = null; + + /** + * @var bool: Whether output should contain table of contents + */ + private $mEnableTOC = true; + + /** * Constructor for OutputPage. This should not be called directly. * Instead a new RequestContext should be created and it will implicitly create * a OutputPage tied to that context. @@ -255,7 +268,7 @@ class OutputPage extends ContextSource { function __construct( IContextSource $context = null ) { if ( $context === null ) { # Extensions should use `new RequestContext` instead of `new OutputPage` now. - wfDeprecated( __METHOD__ ); + wfDeprecated( __METHOD__, '1.18' ); } else { $this->setContext( $context ); } @@ -264,8 +277,8 @@ class OutputPage extends ContextSource { /** * Redirect to $url rather than displaying the normal page * - * @param $url String: URL - * @param $responsecode String: HTTP status code + * @param string $url URL + * @param string $responsecode HTTP status code */ public function redirect( $url, $responsecode = '302' ) { # Strip newlines as a paranoia check for header injection in PHP<5.1.2 @@ -295,30 +308,19 @@ class OutputPage extends ContextSource { * Add a new "<meta>" tag * To add an http-equiv meta tag, precede the name with "http:" * - * @param $name String tag name - * @param $val String tag value + * @param string $name tag name + * @param string $val tag value */ function addMeta( $name, $val ) { array_push( $this->mMetatags, array( $name, $val ) ); } /** - * Add a keyword or a list of keywords in the page header + * Add a new \<link\> tag to the page header. * - * @param $text String or array of strings - */ - function addKeyword( $text ) { - if( is_array( $text ) ) { - $this->mKeywords = array_merge( $this->mKeywords, $text ); - } else { - array_push( $this->mKeywords, $text ); - } - } - - /** - * Add a new \<link\> tag to the page header + * Note: use setCanonicalUrl() for rel=canonical. * - * @param $linkarr Array: associative array of attributes. + * @param array $linkarr associative array of attributes. */ function addLink( $linkarr ) { array_push( $this->mLinktags, $linkarr ); @@ -327,7 +329,7 @@ class OutputPage extends ContextSource { /** * Add a new \<link\> with "rel" attribute set to "meta" * - * @param $linkarr Array: associative array mapping attribute names to their + * @param array $linkarr associative array mapping attribute names to their * values, both keys and values will be escaped, and the * "rel" attribute will be automatically added */ @@ -337,6 +339,14 @@ class OutputPage extends ContextSource { } /** + * Set the URL to be used for the <link rel=canonical>. This should be used + * in preference to addLink(), to avoid duplicate link tags. + */ + function setCanonicalUrl( $url ) { + $this->mCanonicalUrl = $url; + } + + /** * Get the value of the "rel" attribute for metadata links * * @return String @@ -355,7 +365,7 @@ class OutputPage extends ContextSource { /** * Add raw HTML to the list of scripts (including \<script\> tag, etc.) * - * @param $script String: raw HTML + * @param string $script raw HTML */ function addScript( $script ) { $this->mScripts .= $script . "\n"; @@ -364,7 +374,7 @@ class OutputPage extends ContextSource { /** * Register and add a stylesheet from an extension directory. * - * @param $url String path to sheet. Provide either a full url (beginning + * @param string $url path to sheet. Provide either a full url (beginning * with 'http', etc) or a relative path from the document root * (beginning with '/'). Otherwise it behaves identically to * addStyle() and draws from the /skins folder. @@ -385,27 +395,28 @@ class OutputPage extends ContextSource { /** * Add a JavaScript file out of skins/common, or a given relative path. * - * @param $file String: filename in skins/common or complete on-server path + * @param string $file filename in skins/common or complete on-server path * (/foo/bar.js) - * @param $version String: style version of the file. Defaults to $wgStyleVersion + * @param string $version style version of the file. Defaults to $wgStyleVersion */ public function addScriptFile( $file, $version = null ) { global $wgStylePath, $wgStyleVersion; // See if $file parameter is an absolute URL or begins with a slash - if( substr( $file, 0, 1 ) == '/' || preg_match( '#^[a-z]*://#i', $file ) ) { + if ( substr( $file, 0, 1 ) == '/' || preg_match( '#^[a-z]*://#i', $file ) ) { $path = $file; } else { $path = "{$wgStylePath}/common/{$file}"; } - if ( is_null( $version ) ) + if ( is_null( $version ) ) { $version = $wgStyleVersion; + } $this->addScript( Html::linkedScript( wfAppendQuery( $path, $version ) ) ); } /** * Add a self-contained script tag with the given contents * - * @param $script String: JavaScript text, no "<script>" tags + * @param string $script JavaScript text, no "<script>" tags */ public function addInlineScript( $script ) { $this->mScripts .= Html::inlineScript( "\n$script\n" ) . "\n"; @@ -424,18 +435,19 @@ class OutputPage extends ContextSource { * Filter an array of modules to remove insufficiently trustworthy members, and modules * which are no longer registered (eg a page is cached before an extension is disabled) * @param $modules Array - * @param $position String if not null, only return modules with this position + * @param string $position if not null, only return modules with this position * @param $type string * @return Array */ - protected function filterModules( $modules, $position = null, $type = ResourceLoaderModule::TYPE_COMBINED ){ + protected function filterModules( $modules, $position = null, $type = ResourceLoaderModule::TYPE_COMBINED ) { $resourceLoader = $this->getResourceLoader(); $filteredModules = array(); - foreach( $modules as $val ){ + foreach ( $modules as $val ) { $module = $resourceLoader->getModule( $val ); - if( $module instanceof ResourceLoaderModule + if ( $module instanceof ResourceLoaderModule && $module->getOrigin() <= $this->getAllowedModules( $type ) - && ( is_null( $position ) || $module->getPosition() == $position ) ) + && ( is_null( $position ) || $module->getPosition() == $position ) + && ( !$this->mTarget || in_array( $this->mTarget, $module->getTargets() ) ) ) { $filteredModules[] = $val; } @@ -446,8 +458,8 @@ class OutputPage extends ContextSource { /** * Get the list of modules to include on this page * - * @param $filter Bool whether to filter out insufficiently trustworthy modules - * @param $position String if not null, only return modules with this position + * @param bool $filter whether to filter out insufficiently trustworthy modules + * @param string $position if not null, only return modules with this position * @param $param string * @return Array of module names */ @@ -501,13 +513,15 @@ class OutputPage extends ContextSource { * @return Array of module names */ public function getModuleStyles( $filter = false, $position = null ) { - return $this->getModules( $filter, $position, 'mModuleStyles' ); + return $this->getModules( $filter, $position, 'mModuleStyles' ); } /** - * Add only CSS of one or more modules recognized by the resource loader. Module - * styles added through this function will be loaded by the resource loader when - * the page loads. + * Add only CSS of one or more modules recognized by the resource loader. + * + * Module styles added through this function will be added using standard link CSS + * tags, rather than as a combined Javascript and CSS package. Thus, they will + * load when JavaScript is disabled (unless CSS also happens to be disabled). * * @param $modules Mixed: module name (string) or array of module names */ @@ -539,6 +553,22 @@ class OutputPage extends ContextSource { } /** + * @return null|string: ResourceLoader target + */ + public function getTarget() { + return $this->mTarget; + } + + /** + * Sets ResourceLoader target for load.php links. If null, will be omitted + * + * @param $target string|null + */ + public function setTarget( $target ) { + $this->mTarget = $target; + } + + /** * Get an array of head items * * @return Array @@ -563,8 +593,8 @@ class OutputPage extends ContextSource { /** * Add or replace an header item to the output * - * @param $name String: item name - * @param $value String: raw HTML + * @param string $name item name + * @param string $value raw HTML */ public function addHeadItem( $name, $value ) { $this->mHeadItems[$name] = $value; @@ -573,7 +603,7 @@ class OutputPage extends ContextSource { /** * Check if the header item $name is already set * - * @param $name String: item name + * @param string $name item name * @return Boolean */ public function hasHeadItem( $name ) { @@ -583,7 +613,7 @@ class OutputPage extends ContextSource { /** * Set the value of the ETag HTTP header, only used if $wgUseETag is true * - * @param $tag String: value of "ETag" header + * @param string $tag value of "ETag" header */ function setETag( $tag ) { $this->mETag = $tag; @@ -610,28 +640,54 @@ class OutputPage extends ContextSource { } /** + * Set an additional output property + * @since 1.21 + * + * @param string $name + * @param mixed $value + */ + public function setProperty( $name, $value ) { + $this->mProperties[$name] = $value; + } + + /** + * Get an additional output property + * @since 1.21 + * + * @param $name + * @return mixed: Property value or null if not found + */ + public function getProperty( $name ) { + if ( isset( $this->mProperties[$name] ) ) { + return $this->mProperties[$name]; + } else { + return null; + } + } + + /** * checkLastModified tells the client to use the client-cached page if - * possible. If sucessful, the OutputPage is disabled so that + * possible. If successful, the OutputPage is disabled so that * any future call to OutputPage->output() have no effect. * * Side effect: sets mLastModified for Last-Modified header * * @param $timestamp string * - * @return Boolean: true iff cache-ok headers was sent. + * @return Boolean: true if cache-ok headers was sent. */ public function checkLastModified( $timestamp ) { - global $wgCachePages, $wgCacheEpoch; + global $wgCachePages, $wgCacheEpoch, $wgUseSquid, $wgSquidMaxage; if ( !$timestamp || $timestamp == '19700101000000' ) { wfDebug( __METHOD__ . ": CACHE DISABLED, NO TIMESTAMP\n" ); return false; } - if( !$wgCachePages ) { + if ( !$wgCachePages ) { wfDebug( __METHOD__ . ": CACHE DISABLED\n", false ); return false; } - if( $this->getUser()->getOption( 'nocache' ) ) { + if ( $this->getUser()->getOption( 'nocache' ) ) { wfDebug( __METHOD__ . ": USER DISABLED CACHE\n", false ); return false; } @@ -642,6 +698,10 @@ class OutputPage extends ContextSource { 'user' => $this->getUser()->getTouched(), 'epoch' => $wgCacheEpoch ); + if ( $wgUseSquid ) { + // bug 44570: the core page itself may not change, but resources might + $modifiedTimes['sepoch'] = wfTimestamp( TS_MW, time() - $wgSquidMaxage ); + } wfRunHooks( 'OutputPageCheckLastModified', array( &$modifiedTimes ) ); $maxModified = max( $modifiedTimes ); @@ -680,7 +740,7 @@ class OutputPage extends ContextSource { wfTimestamp( TS_ISO_8601, $clientHeaderTime ) . "\n", false ); wfDebug( __METHOD__ . ": effective Last-Modified: " . wfTimestamp( TS_ISO_8601, $maxModified ) . "\n", false ); - if( $clientHeaderTime < $maxModified ) { + if ( $clientHeaderTime < $maxModified ) { wfDebug( __METHOD__ . ": STALE, $info\n", false ); return false; } @@ -704,7 +764,7 @@ class OutputPage extends ContextSource { /** * Override the last modified timestamp * - * @param $timestamp String: new timestamp, in a format readable by + * @param string $timestamp new timestamp, in a format readable by * wfTimestamp() */ public function setLastModified( $timestamp ) { @@ -714,7 +774,7 @@ class OutputPage extends ContextSource { /** * Set the robot policy for the page: <http://www.robotstxt.org/meta.html> * - * @param $policy String: the literal string to output as the contents of + * @param string $policy the literal string to output as the contents of * the meta tag. Will be parsed according to the spec and output in * standardized form. * @return null @@ -722,10 +782,10 @@ class OutputPage extends ContextSource { public function setRobotPolicy( $policy ) { $policy = Article::formatRobotPolicy( $policy ); - if( isset( $policy['index'] ) ) { + if ( isset( $policy['index'] ) ) { $this->setIndexPolicy( $policy['index'] ); } - if( isset( $policy['follow'] ) ) { + if ( isset( $policy['follow'] ) ) { $this->setFollowPolicy( $policy['follow'] ); } } @@ -734,12 +794,12 @@ class OutputPage extends ContextSource { * Set the index policy for the page, but leave the follow policy un- * touched. * - * @param $policy string Either 'index' or 'noindex'. + * @param string $policy Either 'index' or 'noindex'. * @return null */ public function setIndexPolicy( $policy ) { $policy = trim( $policy ); - if( in_array( $policy, array( 'index', 'noindex' ) ) ) { + if ( in_array( $policy, array( 'index', 'noindex' ) ) ) { $this->mIndexPolicy = $policy; } } @@ -748,12 +808,12 @@ class OutputPage extends ContextSource { * Set the follow policy for the page, but leave the index policy un- * touched. * - * @param $policy String: either 'follow' or 'nofollow'. + * @param string $policy either 'follow' or 'nofollow'. * @return null */ public function setFollowPolicy( $policy ) { $policy = trim( $policy ); - if( in_array( $policy, array( 'follow', 'nofollow' ) ) ) { + if ( in_array( $policy, array( 'follow', 'nofollow' ) ) ) { $this->mFollowPolicy = $policy; } } @@ -762,7 +822,7 @@ class OutputPage extends ContextSource { * Set the new value of the "action text", this will be added to the * "HTML title", separated from it with " - ". * - * @param $text String: new value of the "action text" + * @param string $text new value of the "action text" */ public function setPageTitleActionText( $text ) { $this->mPageTitleActionText = $text; @@ -777,6 +837,7 @@ class OutputPage extends ContextSource { if ( isset( $this->mPageTitleActionText ) ) { return $this->mPageTitleActionText; } + return ''; } /** @@ -851,11 +912,10 @@ class OutputPage extends ContextSource { $this->getContext()->setTitle( $t ); } - /** - * Replace the subtile with $str + * Replace the subtitle with $str * - * @param $str String|Message: new value of the subtitle + * @param string|Message $str new value of the subtitle. String should be safe HTML. */ public function setSubtitle( $str ) { $this->clearSubtitle(); @@ -866,7 +926,7 @@ class OutputPage extends ContextSource { * Add $str to the subtitle * * @deprecated in 1.19; use addSubtitle() instead - * @param $str String|Message to add to the subtitle + * @param string|Message $str to add to the subtitle */ public function appendSubtitle( $str ) { $this->addSubtitle( $str ); @@ -875,7 +935,7 @@ class OutputPage extends ContextSource { /** * Add $str to the subtitle * - * @param $str String|Message to add to the subtitle + * @param string|Message $str to add to the subtitle. String should be safe HTML. */ public function addSubtitle( $str ) { if ( $str instanceof Message ) { @@ -987,7 +1047,7 @@ class OutputPage extends ContextSource { * for the new version * @see addFeedLink() * - * @param $val String: query to append to feed links or false to output + * @param string $val query to append to feed links or false to output * default links */ public function setFeedAppendQuery( $val ) { @@ -1007,8 +1067,8 @@ class OutputPage extends ContextSource { /** * Add a feed link to the page header * - * @param $format String: feed type, should be a key of $wgFeedClasses - * @param $href String: URL + * @param string $format feed type, should be a key of $wgFeedClasses + * @param string $href URL */ public function addFeedLink( $format, $href ) { global $wgAdvertisedFeedTypes; @@ -1092,7 +1152,7 @@ class OutputPage extends ContextSource { /** * Add new language links * - * @param $newLinkArray array Associative array mapping language code to the page + * @param array $newLinkArray Associative array mapping language code to the page * name */ public function addLanguageLinks( $newLinkArray ) { @@ -1102,7 +1162,7 @@ class OutputPage extends ContextSource { /** * Reset the language links and add new language links * - * @param $newLinkArray array Associative array mapping language code to the page + * @param array $newLinkArray Associative array mapping language code to the page * name */ public function setLanguageLinks( $newLinkArray ) { @@ -1121,7 +1181,7 @@ class OutputPage extends ContextSource { /** * Add an array of categories, with names in the keys * - * @param $categories Array mapping category name => sort key + * @param array $categories mapping category name => sort key */ public function addCategoryLinks( $categories ) { global $wgContLang; @@ -1182,7 +1242,7 @@ class OutputPage extends ContextSource { /** * Reset the category links (but not the category list) and add $categories * - * @param $categories Array mapping category name => sort key + * @param array $categories mapping category name => sort key */ public function setCategoryLinks( $categories ) { $this->mCategoryLinks = array(); @@ -1225,7 +1285,6 @@ class OutputPage extends ContextSource { * Return whether user JavaScript is allowed for this page * @deprecated since 1.18 Load modules with ResourceLoader, and origin and * trustworthiness is identified and enforced automagically. - * Will be removed in 1.20. * @return Boolean */ public function isUserJsAllowed() { @@ -1236,11 +1295,11 @@ class OutputPage extends ContextSource { /** * Show what level of JavaScript / CSS untrustworthiness is allowed on this page * @see ResourceLoaderModule::$origin - * @param $type String ResourceLoaderModule TYPE_ constant + * @param string $type ResourceLoaderModule TYPE_ constant * @return Int ResourceLoaderModule ORIGIN_ class constant */ - public function getAllowedModules( $type ){ - if( $type == ResourceLoaderModule::TYPE_COMBINED ){ + public function getAllowedModules( $type ) { + if ( $type == ResourceLoaderModule::TYPE_COMBINED ) { return min( array_values( $this->mAllowedModules ) ); } else { return isset( $this->mAllowedModules[$type] ) @@ -1254,23 +1313,23 @@ class OutputPage extends ContextSource { * @param $type String ResourceLoaderModule TYPE_ constant * @param $level Int ResourceLoaderModule class constant */ - public function setAllowedModules( $type, $level ){ + public function setAllowedModules( $type, $level ) { $this->mAllowedModules[$type] = $level; } /** - * As for setAllowedModules(), but don't inadvertantly make the page more accessible + * As for setAllowedModules(), but don't inadvertently make the page more accessible * @param $type String * @param $level Int ResourceLoaderModule class constant */ - public function reduceAllowedModules( $type, $level ){ - $this->mAllowedModules[$type] = min( $this->getAllowedModules($type), $level ); + public function reduceAllowedModules( $type, $level ) { + $this->mAllowedModules[$type] = min( $this->getAllowedModules( $type ), $level ); } /** * Prepend $text to the body HTML * - * @param $text String: HTML + * @param string $text HTML */ public function prependHTML( $text ) { $this->mBodytext = $text . $this->mBodytext; @@ -1279,7 +1338,7 @@ class OutputPage extends ContextSource { /** * Append $text to the body HTML * - * @param $text String: HTML + * @param string $text HTML */ public function addHTML( $text ) { $this->mBodytext .= $text; @@ -1357,7 +1416,7 @@ class OutputPage extends ContextSource { * @param $timestamp Mixed: string, or null * @return Mixed: previous value */ - public function setRevisionTimestamp( $timestamp) { + public function setRevisionTimestamp( $timestamp ) { return wfSetVar( $this->mRevisionTimestamp, $timestamp ); } @@ -1423,14 +1482,17 @@ class OutputPage extends ContextSource { * @param $interface Boolean: is this text in the user interface language? */ public function addWikiText( $text, $linestart = true, $interface = true ) { - $title = $this->getTitle(); // Work arround E_STRICT + $title = $this->getTitle(); // Work around E_STRICT + if ( !$title ) { + throw new MWException( 'Title is null' ); + } $this->addWikiTextTitle( $text, $title, $linestart, /*tidy*/false, $interface ); } /** * Add wikitext with a custom Title object * - * @param $text String: wikitext + * @param string $text wikitext * @param $title Title object * @param $linestart Boolean: is this the start of a line? */ @@ -1441,7 +1503,7 @@ class OutputPage extends ContextSource { /** * Add wikitext with a custom Title object and tidy enabled. * - * @param $text String: wikitext + * @param string $text wikitext * @param $title Title object * @param $linestart Boolean: is this the start of a line? */ @@ -1452,7 +1514,7 @@ class OutputPage extends ContextSource { /** * Add wikitext with tidy enabled * - * @param $text String: wikitext + * @param string $text wikitext * @param $linestart Boolean: is this the start of a line? */ public function addWikiTextTidy( $text, $linestart = true ) { @@ -1463,21 +1525,21 @@ class OutputPage extends ContextSource { /** * Add wikitext with a custom Title object * - * @param $text String: wikitext + * @param string $text wikitext * @param $title Title object * @param $linestart Boolean: is this the start of a line? * @param $tidy Boolean: whether to use tidy * @param $interface Boolean: whether it is an interface message * (for example disables conversion) */ - public function addWikiTextTitle( $text, &$title, $linestart, $tidy = false, $interface = false ) { + public function addWikiTextTitle( $text, Title $title, $linestart, $tidy = false, $interface = false ) { global $wgParser; wfProfileIn( __METHOD__ ); $popts = $this->parserOptions(); $oldTidy = $popts->setTidy( $tidy ); - $popts->setInterfaceMessage( (bool) $interface ); + $popts->setInterfaceMessage( (bool)$interface ); $parserOutput = $wgParser->parse( $text, $title, $popts, @@ -1535,6 +1597,10 @@ class OutputPage extends ContextSource { } } + // Link flags are ignored for now, but may in the future be + // used to mark individual language links. + $linkFlags = array(); + wfRunHooks( 'LanguageLinks', array( $this->getTitle(), &$this->mLanguageLinks, &$linkFlags ) ); wfRunHooks( 'OutputPageParserOutput', array( &$this, $parserOutput ) ); } @@ -1545,12 +1611,12 @@ class OutputPage extends ContextSource { */ function addParserOutput( &$parserOutput ) { $this->addParserOutputNoText( $parserOutput ); + $parserOutput->setTOCEnabled( $this->mEnableTOC ); $text = $parserOutput->getText(); wfRunHooks( 'OutputPageBeforeHTML', array( &$this, &$text ) ); $this->addHTML( $text ); } - /** * Add the output of a QuickTemplate to the output buffer * @@ -1571,15 +1637,16 @@ class OutputPage extends ContextSource { * @param $interface Boolean: use interface language ($wgLang instead of * $wgContLang) while parsing language sensitive magic * words like GRAMMAR and PLURAL. This also disables - * LanguageConverter. + * LanguageConverter. * @param $language Language object: target language object, will override * $interface + * @throws MWException * @return String: HTML */ public function parse( $text, $linestart = true, $interface = false, $language = null ) { global $wgParser; - if( is_null( $this->getTitle() ) ) { + if ( is_null( $this->getTitle() ) ) { throw new MWException( 'Empty $mTitle in ' . __METHOD__ ); } @@ -1660,6 +1727,7 @@ class OutputPage extends ContextSource { array( "{$wgCookiePrefix}Token", "{$wgCookiePrefix}LoggedOut", + "forceHTTPS", session_name() ), $wgCacheVaryCookies @@ -1695,7 +1763,7 @@ class OutputPage extends ContextSource { /** * Add an HTTP header that will influence on the cache * - * @param $header String: header name + * @param string $header header name * @param $option Array|null * @todo FIXME: Document the $option parameter; it appears to be for * X-Vary-Options but what format is acceptable? @@ -1703,8 +1771,8 @@ class OutputPage extends ContextSource { public function addVaryHeader( $header, $option = null ) { if ( !array_key_exists( $header, $this->mVaryHeader ) ) { $this->mVaryHeader[$header] = (array)$option; - } elseif( is_array( $option ) ) { - if( is_array( $this->mVaryHeader[$header] ) ) { + } elseif ( is_array( $option ) ) { + if ( is_array( $this->mVaryHeader[$header] ) ) { $this->mVaryHeader[$header] = array_merge( $this->mVaryHeader[$header], $option ); } else { $this->mVaryHeader[$header] = $option; @@ -1738,7 +1806,7 @@ class OutputPage extends ContextSource { $this->addVaryHeader( 'Cookie', $cookiesOption ); $headers = array(); - foreach( $this->mVaryHeader as $header => $option ) { + foreach ( $this->mVaryHeader as $header => $option ) { $newheader = $header; if ( is_array( $option ) && count( $option ) > 0 ) { $newheader .= ';' . implode( ';', $option ); @@ -1760,23 +1828,21 @@ class OutputPage extends ContextSource { */ function addAcceptLanguage() { $lang = $this->getTitle()->getPageLanguage(); - if( !$this->getRequest()->getCheck( 'variant' ) && $lang->hasVariants() ) { + if ( !$this->getRequest()->getCheck( 'variant' ) && $lang->hasVariants() ) { $variants = $lang->getVariants(); $aloption = array(); foreach ( $variants as $variant ) { - if( $variant === $lang->getCode() ) { + if ( $variant === $lang->getCode() ) { continue; } else { $aloption[] = 'string-contains=' . $variant; - // IE and some other browsers use another form of language code - // in their Accept-Language header, like "zh-CN" or "zh-TW". + // IE and some other browsers use BCP 47 standards in + // their Accept-Language header, like "zh-CN" or "zh-Hant". // We should handle these too. - $ievariant = explode( '-', $variant ); - if ( count( $ievariant ) == 2 ) { - $ievariant[1] = strtoupper( $ievariant[1] ); - $ievariant = implode( '-', $ievariant ); - $aloption[] = 'string-contains=' . $ievariant; + $variantBCP47 = wfBCP47( $variant ); + if ( $variantBCP47 !== $variant ) { + $aloption[] = 'string-contains=' . $variantBCP47; } } } @@ -1847,12 +1913,11 @@ class OutputPage extends ContextSource { $response->header( $this->getXVO() ); } - if( $this->mEnableClientCache ) { - if( + if ( $this->mEnableClientCache ) { + if ( $wgUseSquid && session_id() == '' && !$this->isPrintable() && $this->mSquidMaxage != 0 && !$this->haveCacheVaryCookies() - ) - { + ) { if ( $wgUseESI ) { # We'll purge the proxy cache explicitly, but require end user agents # to revalidate against the proxy on each visit. @@ -1860,7 +1925,7 @@ class OutputPage extends ContextSource { wfDebug( __METHOD__ . ": proxy caching with ESI; {$this->mLastModified} **\n", false ); # start with a shorter timeout for initial testing # header( 'Surrogate-Control: max-age=2678400+2678400, content="ESI/1.0"'); - $response->header( 'Surrogate-Control: max-age='.$wgSquidMaxage.'+'.$this->mSquidMaxage.', content="ESI/1.0"'); + $response->header( 'Surrogate-Control: max-age=' . $wgSquidMaxage . '+' . $this->mSquidMaxage . ', content="ESI/1.0"' ); $response->header( 'Cache-Control: s-maxage=0, must-revalidate, max-age=0' ); } else { # We'll purge the proxy cache for anons explicitly, but require end user agents @@ -1870,7 +1935,7 @@ class OutputPage extends ContextSource { wfDebug( __METHOD__ . ": local proxy caching; {$this->mLastModified} **\n", false ); # start with a shorter timeout for initial testing # header( "Cache-Control: s-maxage=2678400, must-revalidate, max-age=0" ); - $response->header( 'Cache-Control: s-maxage='.$this->mSquidMaxage.', must-revalidate, max-age=0' ); + $response->header( 'Cache-Control: s-maxage=' . $this->mSquidMaxage . ', must-revalidate, max-age=0' ); } } else { # We do want clients to cache if they can, but they *must* check for updates @@ -1879,7 +1944,7 @@ class OutputPage extends ContextSource { $response->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' ); $response->header( "Cache-Control: private, must-revalidate, max-age=0" ); } - if($this->mLastModified) { + if ( $this->mLastModified ) { $response->header( "Last-Modified: {$this->mLastModified}" ); } } else { @@ -1894,7 +1959,7 @@ class OutputPage extends ContextSource { } /** - * Get the message associed with the HTTP response code $code + * Get the message associated with the HTTP response code $code * * @param $code Integer: status code * @return String or null: message or null if $code is not in the list of @@ -1903,7 +1968,7 @@ class OutputPage extends ContextSource { * @deprecated since 1.18 Use HttpStatus::getMessage() instead. */ public static function getStatusMessage( $code ) { - wfDeprecated( __METHOD__ ); + wfDeprecated( __METHOD__, '1.18' ); return HttpStatus::getMessage( $code ); } @@ -1912,9 +1977,10 @@ class OutputPage extends ContextSource { * the object, let's actually output it: */ public function output() { - global $wgLanguageCode, $wgDebugRedirects, $wgMimeType, $wgVaryOnXFP; + global $wgLanguageCode, $wgDebugRedirects, $wgMimeType, $wgVaryOnXFP, + $wgUseAjax, $wgResponsiveImages; - if( $this->mDoNothing ) { + if ( $this->mDoNothing ) { return; } @@ -1929,9 +1995,9 @@ class OutputPage extends ContextSource { $redirect = $this->mRedirect; $code = $this->mRedirectCode; - if( wfRunHooks( "BeforePageRedirect", array( $this, &$redirect, &$code ) ) ) { - if( $code == '301' || $code == '303' ) { - if( !$wgDebugRedirects ) { + if ( wfRunHooks( "BeforePageRedirect", array( $this, &$redirect, &$code ) ) ) { + if ( $code == '301' || $code == '303' ) { + if ( !$wgDebugRedirects ) { $message = HttpStatus::getMessage( $code ); $response->header( "HTTP/1.1 $code $message" ); } @@ -1943,7 +2009,7 @@ class OutputPage extends ContextSource { $this->sendCacheControl(); $response->header( "Content-Type: text/html; charset=utf-8" ); - if( $wgDebugRedirects ) { + if ( $wgDebugRedirects ) { $url = htmlspecialchars( $redirect ); print "<html>\n<head>\n<title>Redirect</title>\n</head>\n<body>\n"; print "<p>Location: <a href=\"$url\">$url</a></p>\n"; @@ -1975,11 +2041,34 @@ class OutputPage extends ContextSource { } if ( $this->mArticleBodyOnly ) { - $this->out( $this->mBodytext ); + echo $this->mBodytext; } else { - $this->addDefaultModules(); $sk = $this->getSkin(); + // add skin specific modules + $modules = $sk->getDefaultModules(); + + // enforce various default modules for all skins + $coreModules = array( + // keep this list as small as possible + 'mediawiki.page.startup', + 'mediawiki.user', + ); + + // Support for high-density display images if enabled + if ( $wgResponsiveImages ) { + $coreModules[] = 'mediawiki.hidpi'; + } + + $this->addModules( $coreModules ); + foreach ( $modules as $group ) { + $this->addModules( $group ); + } + MWDebug::addModules( $this ); + if ( $wgUseAjax ) { + // FIXME: deprecate? - not clear why this is useful + wfRunHooks( 'AjaxAddScript', array( &$this ) ); + } // Hook that allows last minute changes to the output page, e.g. // adding of CSS or Javascript by extensions. @@ -1994,16 +2083,20 @@ class OutputPage extends ContextSource { wfRunHooks( 'AfterFinalPageOutput', array( $this ) ); $this->sendCacheControl(); + ob_end_flush(); + wfProfileOut( __METHOD__ ); } /** - * Actually output something with print(). + * Actually output something with print. * - * @param $ins String: the string to output + * @param string $ins the string to output + * @deprecated since 1.22 Use echo yourself. */ public function out( $ins ) { + wfDeprecated( __METHOD__, '1.22' ); print $ins; } @@ -2020,8 +2113,8 @@ class OutputPage extends ContextSource { * indexing, clear the current text and redirect, set the page's title * and optionally an custom HTML title (content of the "<title>" tag). * - * @param $pageTitle String|Message will be passed directly to setPageTitle() - * @param $htmlTitle String|Message will be passed directly to setHTMLTitle(); + * @param string|Message $pageTitle will be passed directly to setPageTitle() + * @param string|Message $htmlTitle will be passed directly to setHTMLTitle(); * optional, if not passed the "<title>" attribute will be * based on $pageTitle */ @@ -2047,17 +2140,17 @@ class OutputPage extends ContextSource { * * @param $title Mixed: message key (string) for page title, or a Message object * @param $msg Mixed: message key (string) for page text, or a Message object - * @param $params Array: message parameters; ignored if $msg is a Message object + * @param array $params message parameters; ignored if $msg is a Message object */ public function showErrorPage( $title, $msg, $params = array() ) { - if( !$title instanceof Message ) { + if ( !$title instanceof Message ) { $title = $this->msg( $title ); } $this->prepareErrorPage( $title ); - if ( $msg instanceof Message ){ - $this->addHTML( $msg->parse() ); + if ( $msg instanceof Message ) { + $this->addHTML( $msg->parseAsBlock() ); } else { $this->addWikiMsgArray( $msg, $params ); } @@ -2068,12 +2161,10 @@ class OutputPage extends ContextSource { /** * Output a standard permission error page * - * @param $errors Array: error message keys - * @param $action String: action that was denied or null if unknown + * @param array $errors error message keys + * @param string $action action that was denied or null if unknown */ public function showPermissionsErrorPage( $errors, $action = null ) { - global $wgGroupPermissions; - // For some action (read, edit, create and upload), display a "login to do this action" // error if all of the following conditions are met: // 1. the user is not logged in @@ -2082,8 +2173,8 @@ class OutputPage extends ContextSource { if ( in_array( $action, array( 'read', 'edit', 'createpage', 'createtalk', 'upload' ) ) && $this->getUser()->isAnon() && count( $errors ) == 1 && isset( $errors[0][0] ) && ( $errors[0][0] == 'badaccess-groups' || $errors[0][0] == 'badaccess-group0' ) - && ( ( isset( $wgGroupPermissions['user'][$action] ) && $wgGroupPermissions['user'][$action] ) - || ( isset( $wgGroupPermissions['autoconfirmed'][$action] ) && $wgGroupPermissions['autoconfirmed'][$action] ) ) + && ( User::groupHasPermission( 'user', $action ) + || User::groupHasPermission( 'autoconfirmed', $action ) ) ) { $displayReturnto = null; @@ -2115,7 +2206,7 @@ class OutputPage extends ContextSource { unset( $returntoquery['title'] ); unset( $returntoquery['returnto'] ); unset( $returntoquery['returntoquery'] ); - $query['returntoquery'] = wfArrayToCGI( $returntoquery ); + $query['returntoquery'] = wfArrayToCgi( $returntoquery ); } } $loginLink = Linker::linkKnown( @@ -2155,7 +2246,8 @@ class OutputPage extends ContextSource { /** * Display an error page noting that a given permission bit is required. * @deprecated since 1.18, just throw the exception directly - * @param $permission String: key required + * @param string $permission key required + * @throws PermissionsError */ public function permissionRequired( $permission ) { throw new PermissionsError( $permission ); @@ -2173,8 +2265,8 @@ class OutputPage extends ContextSource { /** * Format a list of error messages * - * @param $errors Array of arrays returned by Title::getUserPermissionsErrors - * @param $action String: action that was denied or null if unknown + * @param array $errors of arrays returned by Title::getUserPermissionsErrors + * @param string $action action that was denied or null if unknown * @return String: the wikitext error-messages, formatted into a list. */ public function formatPermissionsErrorMessage( $errors, $action = null ) { @@ -2192,7 +2284,7 @@ class OutputPage extends ContextSource { if ( count( $errors ) > 1 ) { $text .= '<ul class="permissions-errors">' . "\n"; - foreach( $errors as $error ) { + foreach ( $errors as $error ) { $text .= '<li>'; $text .= call_user_func_array( array( $this, 'msg' ), $error )->plain(); $text .= "</li>\n"; @@ -2226,6 +2318,7 @@ class OutputPage extends ContextSource { * @param $protected Boolean: is this a permissions error? * @param $reasons Array: list of reasons for this error, as returned by Title::getUserPermissionsErrors(). * @param $action String: action that was denied or null if unknown + * @throws ReadOnlyError */ public function readOnlyPage( $source = null, $protected = false, $reasons = array(), $action = null ) { $this->setRobotPolicy( 'noindex,nofollow' ); @@ -2239,7 +2332,7 @@ class OutputPage extends ContextSource { if ( !empty( $reasons ) ) { // Permissions error - if( $source ) { + if ( $source ) { $this->setPageTitle( $this->msg( 'viewsource-title', $this->getTitle()->getPrefixedText() ) ); $this->addBacklinkSubtitle( $this->getTitle() ); } else { @@ -2252,12 +2345,12 @@ class OutputPage extends ContextSource { } // Show source, if supplied - if( is_string( $source ) ) { + if ( is_string( $source ) ) { $this->addWikiMsg( 'viewsourcetext' ); $pageLang = $this->getTitle()->getPageLanguage(); $params = array( - 'id' => 'wpTextbox1', + 'id' => 'wpTextbox1', 'name' => 'wpTextbox1', 'cols' => $this->getUser()->getOption( 'cols' ), 'rows' => $this->getUser()->getOption( 'rows' ), @@ -2278,13 +2371,13 @@ $templates # If the title doesn't exist, it's fairly pointless to print a return # link to it. After all, you just tried editing it and couldn't, so # what's there to do there? - if( $this->getTitle()->exists() ) { + if ( $this->getTitle()->exists() ) { $this->returnToMain( null, $this->getTitle() ); } } /** - * Turn off regular page output and return an error reponse + * Turn off regular page output and return an error response * for when rate limiting has triggered. */ public function rateLimited() { @@ -2302,7 +2395,7 @@ $templates */ public function showLagWarning( $lag ) { global $wgSlaveLagWarning, $wgSlaveLagCritical; - if( $lag >= $wgSlaveLagWarning ) { + if ( $lag >= $wgSlaveLagWarning ) { $message = $lag < $wgSlaveLagCritical ? 'lag-warn-normal' : 'lag-warn-high'; @@ -2341,13 +2434,13 @@ $templates * Add a "return to" link pointing to a specified title * * @param $title Title to link - * @param $query Array query string parameters - * @param $text String text of the link (input is not escaped) + * @param array $query query string parameters + * @param string $text text of the link (input is not escaped) + * @param $options Options array to pass to Linker */ - public function addReturnTo( $title, $query = array(), $text = null ) { - $this->addLink( array( 'rel' => 'next', 'href' => $title->getFullURL() ) ); + public function addReturnTo( $title, $query = array(), $text = null, $options = array() ) { $link = $this->msg( 'returnto' )->rawParams( - Linker::link( $title, $text, array(), $query ) )->escaped(); + Linker::link( $title, $text, array(), $query, $options ) )->escaped(); $this->addHTML( "<p id=\"mw-returnto\">{$link}</p>\n" ); } @@ -2357,7 +2450,7 @@ $templates * * @param $unused * @param $returnto Title or String to return to - * @param $returntoquery String: query string for the return to link + * @param string $returntoquery query string for the return to link */ public function returnToMain( $unused = null, $returnto = null, $returntoquery = null ) { if ( $returnto == null ) { @@ -2390,15 +2483,11 @@ $templates * @return String: The doctype, opening "<html>", and head element. */ public function headElement( Skin $sk, $includeStyle = true ) { - global $wgContLang; + global $wgContLang, $wgMimeType; $userdir = $this->getLanguage()->getDir(); $sitedir = $wgContLang->getDir(); - if ( $sk->commonPrintStylesheet() ) { - $this->addModuleStyles( 'mediawiki.legacy.wikiprintable' ); - } - $ret = Html::htmlHeader( array( 'lang' => $this->getLanguage()->getHtmlCode(), 'dir' => $userdir, 'class' => 'client-nojs' ) ); if ( $this->getHTMLTitle() == '' ) { @@ -2411,10 +2500,22 @@ $templates $ret .= "$openHead\n"; } + if ( !Html::isXmlMimeType( $wgMimeType ) ) { + // Add <meta charset="UTF-8"> + // This should be before <title> since it defines the charset used by + // text including the text inside <title>. + // The spec recommends defining XHTML5's charset using the XML declaration + // instead of meta. + // Our XML declaration is output by Html::htmlHeader. + // http://www.whatwg.org/html/semantics.html#attr-meta-http-equiv-content-type + // http://www.whatwg.org/html/semantics.html#charset + $ret .= Html::element( 'meta', array( 'charset' => 'UTF-8' ) ); + } + $ret .= Html::element( 'title', null, $this->getHTMLTitle() ) . "\n"; $ret .= implode( "\n", array( - $this->getHeadLinks( null, true ), + $this->getHeadLinks(), $this->buildCssLinks(), $this->getHeadScripts(), $this->getHeadItems() @@ -2425,20 +2526,29 @@ $templates $ret .= "$closeHead\n"; } - $bodyAttrs = array(); + $bodyClasses = array(); + $bodyClasses[] = 'mediawiki'; # Classes for LTR/RTL directionality support - $bodyAttrs['class'] = "mediawiki $userdir sitedir-$sitedir"; + $bodyClasses[] = $userdir; + $bodyClasses[] = "sitedir-$sitedir"; if ( $this->getLanguage()->capitalizeAllNouns() ) { # A <body> class is probably not the best way to do this . . . - $bodyAttrs['class'] .= ' capitalize-all-nouns'; + $bodyClasses[] = 'capitalize-all-nouns'; } - $bodyAttrs['class'] .= ' ' . $sk->getPageClasses( $this->getTitle() ); - $bodyAttrs['class'] .= ' skin-' . Sanitizer::escapeClass( $sk->getSkinName() ); - $bodyAttrs['class'] .= ' action-' . Sanitizer::escapeClass( Action::getActionName( $this->getContext() ) ); - $sk->addToBodyAttributes( $this, $bodyAttrs ); // Allow skins to add body attributes they need + $bodyClasses[] = $sk->getPageClasses( $this->getTitle() ); + $bodyClasses[] = 'skin-' . Sanitizer::escapeClass( $sk->getSkinName() ); + $bodyClasses[] = 'action-' . Sanitizer::escapeClass( Action::getActionName( $this->getContext() ) ); + + $bodyAttrs = array(); + // While the implode() is not strictly needed, it's used for backwards compatibility + // (this used to be built as a string and hooks likely still expect that). + $bodyAttrs['class'] = implode( ' ', $bodyClasses ); + + // Allow skins and extensions to add body attributes they need + $sk->addToBodyAttributes( $this, $bodyAttrs ); wfRunHooks( 'OutputPageBodyAttributes', array( $this, $sk, &$bodyAttrs ) ); $ret .= Html::openElement( 'body', $bodyAttrs ) . "\n"; @@ -2447,54 +2557,6 @@ $templates } /** - * Add the default ResourceLoader modules to this object - */ - private function addDefaultModules() { - global $wgIncludeLegacyJavaScript, $wgPreloadJavaScriptMwUtil, $wgUseAjax, - $wgAjaxWatch; - - // Add base resources - $this->addModules( array( - 'mediawiki.user', - 'mediawiki.page.startup', - 'mediawiki.page.ready', - ) ); - if ( $wgIncludeLegacyJavaScript ){ - $this->addModules( 'mediawiki.legacy.wikibits' ); - } - - if ( $wgPreloadJavaScriptMwUtil ) { - $this->addModules( 'mediawiki.util' ); - } - - MWDebug::addModules( $this ); - - // Add various resources if required - if ( $wgUseAjax ) { - $this->addModules( 'mediawiki.legacy.ajax' ); - - wfRunHooks( 'AjaxAddScript', array( &$this ) ); - - if( $wgAjaxWatch && $this->getUser()->isLoggedIn() ) { - $this->addModules( 'mediawiki.page.watch.ajax' ); - } - - if ( !$this->getUser()->getOption( 'disablesuggest', false ) ) { - $this->addModules( 'mediawiki.searchSuggest' ); - } - } - - if ( $this->getUser()->getBoolOption( 'editsectiononrightclick' ) ) { - $this->addModules( 'mediawiki.action.view.rightClickEdit' ); - } - - # Crazy edit-on-double-click stuff - if ( $this->isArticle() && $this->getUser()->getOption( 'editondblclick' ) ) { - $this->addModules( 'mediawiki.action.view.dblClickEdit' ); - } - } - - /** * Get a ResourceLoader object associated with this OutputPage * * @return ResourceLoader @@ -2509,16 +2571,16 @@ $templates /** * TODO: Document * @param $modules Array/string with the module name(s) - * @param $only String ResourceLoaderModule TYPE_ class constant + * @param string $only ResourceLoaderModule TYPE_ class constant * @param $useESI boolean - * @param $extraQuery Array with extra query parameters to add to each request. array( param => value ) + * @param array $extraQuery with extra query parameters to add to each request. array( param => value ) * @param $loadCall boolean If true, output an (asynchronous) mw.loader.load() call rather than a "<script src='...'>" tag * @return string html "<script>" and "<style>" tags */ protected function makeResourceLoaderLink( $modules, $only, $useESI = false, array $extraQuery = array(), $loadCall = false ) { global $wgResourceLoaderUseESI; - $modules = (array) $modules; + $modules = (array)$modules; if ( !count( $modules ) ) { return ''; @@ -2539,6 +2601,9 @@ $templates return $links; } } + if ( !is_null( $this->mTarget ) ) { + $extraQuery['target'] = $this->mTarget; + } // Create keyed-by-group list of module objects from modules list $groups = array(); @@ -2551,8 +2616,8 @@ $templates && $only == ResourceLoaderModule::TYPE_SCRIPTS ) || ( $module->getOrigin() > $this->getAllowedModules( ResourceLoaderModule::TYPE_STYLES ) && $only == ResourceLoaderModule::TYPE_STYLES ) - ) - { + || ( $this->mTarget && !in_array( $this->mTarget, $module->getTargets() ) ) + ) { continue; } @@ -2587,7 +2652,7 @@ $templates ); $context = new ResourceLoaderContext( $resourceLoader, new FauxRequest( $query ) ); // Extract modules that know they're empty - $emptyModules = array (); + $emptyModules = array(); foreach ( $grpModules as $key => $module ) { if ( $module->isKnownEmpty( $context ) ) { $emptyModules[$key] = 'ready'; @@ -2598,13 +2663,9 @@ $templates if ( count( $emptyModules ) > 0 && $only !== ResourceLoaderModule::TYPE_STYLES ) { // If we're only getting the styles, we don't need to do anything for empty modules. $links .= Html::inlineScript( - ResourceLoader::makeLoaderConditionalScript( - ResourceLoader::makeLoaderStateScript( $emptyModules ) - ) - ) . "\n"; } @@ -2634,7 +2695,7 @@ $templates } // Special handling for the user group; because users might change their stuff // on-wiki like user pages, or user preferences; we need to find the highest - // timestamp of these user-changable modules so we can ensure cache misses on change + // timestamp of these user-changeable modules so we can ensure cache misses on change // This should NOT be done for the site group (bug 27564) because anons get that too // and we shouldn't be putting timestamps in Squid-cached HTML $version = null; @@ -2671,7 +2732,7 @@ $templates // Automatically select style/script elements if ( $only === ResourceLoaderModule::TYPE_STYLES ) { $link = Html::linkedStyle( $url ); - } else if ( $loadCall ) { + } elseif ( $loadCall ) { $link = Html::inlineScript( ResourceLoader::makeLoaderConditionalScript( Xml::encodeJsCall( 'mw.loader.load', array( $url, 'text/javascript', true ) ) @@ -2682,7 +2743,7 @@ $templates } } - if( $group == 'noscript' ){ + if ( $group == 'noscript' ) { $links .= Html::rawElement( 'noscript', array(), $link ) . "\n"; } else { $links .= $link . "\n"; @@ -2786,14 +2847,14 @@ $templates ); $defaultModules['site'] = 'loading'; } else { - // The wiki is configured to not allow a site module. - $defaultModules['site'] = 'missing'; + // Site module is empty, save request by marking ready in advance (bug 46857) + $defaultModules['site'] = 'ready'; } // Add user JS if enabled if ( $wgAllowUserJs ) { if ( $this->getUser()->isLoggedIn() ) { - if( $this->getTitle() && $this->getTitle()->isJsSubpage() && $this->userCanPreview() ) { + if ( $this->getTitle() && $this->getTitle()->isJsSubpage() && $this->userCanPreview() ) { # XXX: additional security check/prompt? // We're on a preview of a JS subpage // Exclude this page from the user module in case it's in there (bug 26283) @@ -2813,15 +2874,14 @@ $templates } $defaultModules['user'] = 'loading'; } else { - // Non-logged-in users have no user module. Treat it as empty and 'ready' to avoid - // blocking default gadgets that might depend on it. Although arguably default-enabled - // gadgets should not depend on the user module, it's harmless and less error-prone to - // handle this case. + // Non-logged-in users have an empty user module. + // Save request by marking ready in advance (bug 46857) $defaultModules['user'] = 'ready'; } } else { - // User JS disabled - $defaultModules['user'] = 'missing'; + // User modules are disabled on this wiki. + // Save request by marking ready in advance (bug 46857) + $defaultModules['user'] = 'ready'; } // Group JS is only enabled if site JS is enabled. @@ -2832,13 +2892,13 @@ $templates ); $defaultModules['user.groups'] = 'loading'; } else { - // Non-logged-in users have no user.groups module. Treat it as empty and 'ready' to - // avoid blocking gadgets that might depend upon the module. + // Non-logged-in users have no user.groups module. + // Save request by marking ready in advance (bug 46857) $defaultModules['user.groups'] = 'ready'; } } else { // Site (and group JS) disabled - $defaultModules['user.groups'] = 'missing'; + $defaultModules['user.groups'] = 'ready'; } $loaderInit = ''; @@ -2866,11 +2926,18 @@ $templates */ function getBottomScripts() { global $wgResourceLoaderExperimentalAsyncLoading; + + // Optimise jQuery ready event cross-browser. + // This also enforces $.isReady to be true at </body> which fixes the + // mw.loader bug in Firefox with using document.write between </body> + // and the DOMContentReady event (bug 47457). + $html = Html::inlineScript( 'window.jQuery && jQuery.ready();' ); + if ( !$wgResourceLoaderExperimentalAsyncLoading ) { - return $this->getScriptsForBottomQueue( false ); - } else { - return ''; + $html .= $this->getScriptsForBottomQueue( false ); } + + return $html; } /** @@ -2890,40 +2957,39 @@ $templates $this->mJsConfigVars[$keys] = $value; } - /** * Get an array containing the variables to be set in mw.config in JavaScript. * * DO NOT CALL THIS FROM OUTSIDE OF THIS CLASS OR Skin::makeGlobalVariablesScript(). * This is only public until that function is removed. You have been warned. * - * Do not add things here which can be evaluated in ResourceLoaderStartupScript + * Do not add things here which can be evaluated in ResourceLoaderStartUpModule * - in other words, page-independent/site-wide variables (without state). * You will only be adding bloat to the html page and causing page caches to * have to be purged on configuration changes. * @return array */ public function getJSVars() { - global $wgUseAjax, $wgContLang; + global $wgContLang; - $latestRevID = 0; - $pageID = 0; - $canonicalName = false; # bug 21115 + $curRevisionId = 0; + $articleId = 0; + $canonicalSpecialPageName = false; # bug 21115 $title = $this->getTitle(); $ns = $title->getNamespace(); - $nsname = MWNamespace::exists( $ns ) ? MWNamespace::getCanonicalName( $ns ) : $title->getNsText(); + $canonicalNamespace = MWNamespace::exists( $ns ) ? MWNamespace::getCanonicalName( $ns ) : $title->getNsText(); // Get the relevant title so that AJAX features can use the correct page name // when making API requests from certain special pages (bug 34972). $relevantTitle = $this->getSkin()->getRelevantTitle(); if ( $ns == NS_SPECIAL ) { - list( $canonicalName, /*...*/ ) = SpecialPageFactory::resolveAlias( $title->getDBkey() ); + list( $canonicalSpecialPageName, /*...*/ ) = SpecialPageFactory::resolveAlias( $title->getDBkey() ); } elseif ( $this->canUseWikiPage() ) { $wikiPage = $this->getWikiPage(); - $latestRevID = $wikiPage->getLatest(); - $pageID = $wikiPage->getId(); + $curRevisionId = $wikiPage->getLatest(); + $articleId = $wikiPage->getId(); } $lang = $title->getPageLanguage(); @@ -2942,31 +3008,48 @@ $templates implode( "\t", $digitTransTable ), ); + $user = $this->getUser(); + $vars = array( - 'wgCanonicalNamespace' => $nsname, - 'wgCanonicalSpecialPageName' => $canonicalName, + 'wgCanonicalNamespace' => $canonicalNamespace, + 'wgCanonicalSpecialPageName' => $canonicalSpecialPageName, 'wgNamespaceNumber' => $title->getNamespace(), - 'wgPageName' => $title->getPrefixedDBKey(), + 'wgPageName' => $title->getPrefixedDBkey(), 'wgTitle' => $title->getText(), - 'wgCurRevisionId' => $latestRevID, - 'wgArticleId' => $pageID, + 'wgCurRevisionId' => $curRevisionId, + 'wgRevisionId' => (int)$this->getRevisionId(), + 'wgArticleId' => $articleId, 'wgIsArticle' => $this->isArticle(), + 'wgIsRedirect' => $title->isRedirect(), 'wgAction' => Action::getActionName( $this->getContext() ), - 'wgUserName' => $this->getUser()->isAnon() ? null : $this->getUser()->getName(), - 'wgUserGroups' => $this->getUser()->getEffectiveGroups(), + 'wgUserName' => $user->isAnon() ? null : $user->getName(), + 'wgUserGroups' => $user->getEffectiveGroups(), 'wgCategories' => $this->getCategories(), 'wgBreakFrames' => $this->getFrameOptions() == 'DENY', 'wgPageContentLanguage' => $lang->getCode(), + 'wgPageContentModel' => $title->getContentModel(), 'wgSeparatorTransformTable' => $compactSeparatorTransTable, 'wgDigitTransformTable' => $compactDigitTransTable, 'wgDefaultDateFormat' => $lang->getDefaultDateFormat(), 'wgMonthNames' => $lang->getMonthNamesArray(), 'wgMonthNamesShort' => $lang->getMonthAbbreviationsArray(), - 'wgRelevantPageName' => $relevantTitle->getPrefixedDBKey(), + 'wgRelevantPageName' => $relevantTitle->getPrefixedDBkey(), ); + if ( $user->isLoggedIn() ) { + $vars['wgUserId'] = $user->getId(); + $vars['wgUserEditCount'] = $user->getEditCount(); + $userReg = wfTimestampOrNull( TS_UNIX, $user->getRegistration() ); + $vars['wgUserRegistration'] = $userReg !== null ? ( $userReg * 1000 ) : null; + // Get the revision ID of the oldest new message on the user's talk + // page. This can be used for constructing new message alerts on + // the client side. + $vars['wgUserNewMsgRevisionId'] = $user->getNewMessageRevisionId(); + } if ( $wgContLang->hasVariants() ) { $vars['wgUserVariant'] = $wgContLang->getPreferredVariant(); - } + } + // Same test as SkinTemplate + $vars['wgIsProbablyEditable'] = $title->quickUserCan( 'edit', $user ) && ( $title->exists() || $title->quickUserCan( 'create', $user ) ); foreach ( $title->getRestrictionTypes() as $type ) { $vars['wgRestriction' . ucfirst( $type )] = $title->getRestrictions( $type ); } @@ -2974,7 +3057,7 @@ $templates $vars['wgIsMainPage'] = true; } if ( $this->mRedirectedFrom ) { - $vars['wgRedirectedFrom'] = $this->mRedirectedFrom->getPrefixedDBKey(); + $vars['wgRedirectedFrom'] = $this->mRedirectedFrom->getPrefixedDBkey(); } // Allow extensions to add their custom variables to the mw.config map. @@ -3012,35 +3095,18 @@ $templates } /** - * @param $addContentType bool: Whether "<meta>" specifying content type should be returned - * * @return array in format "link name or number => 'link html'". */ - public function getHeadLinksArray( $addContentType = false ) { + public function getHeadLinksArray() { global $wgUniversalEditButton, $wgFavicon, $wgAppleTouchIcon, $wgEnableAPI, - $wgSitename, $wgVersion, $wgHtml5, $wgMimeType, + $wgSitename, $wgVersion, $wgFeed, $wgOverrideSiteFeed, $wgAdvertisedFeedTypes, $wgDisableLangConversion, $wgCanonicalLanguageLinks, $wgRightsPage, $wgRightsUrl; $tags = array(); - if ( $addContentType ) { - if ( $wgHtml5 ) { - # More succinct than <meta http-equiv=Content-Type>, has the - # same effect - $tags['meta-charset'] = Html::element( 'meta', array( 'charset' => 'UTF-8' ) ); - } else { - $tags['meta-content-type'] = Html::element( 'meta', array( - 'http-equiv' => 'Content-Type', - 'content' => "$wgMimeType; charset=UTF-8" - ) ); - $tags['meta-content-style-type'] = Html::element( 'meta', array( // bug 15835 - 'http-equiv' => 'Content-Style-Type', - 'content' => 'text/css' - ) ); - } - } + $canonicalUrl = $this->mCanonicalUrl; $tags['meta-generator'] = Html::element( 'meta', array( 'name' => 'generator', @@ -3048,7 +3114,7 @@ $templates ) ); $p = "{$this->mIndexPolicy},{$this->mFollowPolicy}"; - if( $p !== 'index,follow' ) { + if ( $p !== 'index,follow' ) { // http://www.robotstxt.org/wc/meta-user.html // Only show if it's different from the default robots policy $tags['meta-robots'] = Html::element( 'meta', array( @@ -3057,21 +3123,6 @@ $templates ) ); } - if ( count( $this->mKeywords ) > 0 ) { - $strip = array( - "/<.*?" . ">/" => '', - "/_/" => ' ' - ); - $tags['meta-keywords'] = Html::element( 'meta', array( - 'name' => 'keywords', - 'content' => preg_replace( - array_keys( $strip ), - array_values( $strip ), - implode( ',', $this->mKeywords ) - ) - ) ); - } - foreach ( $this->mMetatags as $tag ) { if ( 0 == strcasecmp( 'http:', substr( $tag[0], 0, 5 ) ) ) { $a = 'http-equiv'; @@ -3151,7 +3202,6 @@ $templates ) ); } - # Language variants if ( !$wgDisableLangConversion && $wgCanonicalLanguageLinks ) { $lang = $this->getTitle()->getPageLanguage(); @@ -3164,15 +3214,12 @@ $templates foreach ( $variants as $_v ) { $tags["variant-$_v"] = Html::element( 'link', array( 'rel' => 'alternate', - 'hreflang' => $_v, + 'hreflang' => wfBCP47( $_v ), 'href' => $this->getTitle()->getLocalURL( array( 'variant' => $_v ) ) ) ); } } else { - $tags['canonical'] = Html::element( 'link', array( - 'rel' => 'canonical', - 'href' => $this->getTitle()->getCanonicalUrl() - ) ); + $canonicalUrl = $this->getTitle()->getLocalURL(); } } } @@ -3200,7 +3247,7 @@ $templates # Feeds if ( $wgFeed ) { - foreach( $this->getSyndicationLinks() as $format => $link ) { + foreach ( $this->getSyndicationLinks() as $format => $link ) { # Use the page name for the title. In principle, this could # lead to issues with having the same name for different feeds # corresponding to the same page, but we can't avoid that at @@ -3235,31 +3282,46 @@ $templates foreach ( $wgAdvertisedFeedTypes as $format ) { $tags[] = $this->feedLink( $format, - $rctitle->getLocalURL( "feed={$format}" ), + $rctitle->getLocalURL( array( 'feed' => $format ) ), $this->msg( "site-{$format}-feed", $wgSitename )->text() # For grep: 'site-rss-feed', 'site-atom-feed'. ); } } } + + # Canonical URL + global $wgEnableCanonicalServerLink; + if ( $wgEnableCanonicalServerLink ) { + if ( $canonicalUrl !== false ) { + $canonicalUrl = wfExpandUrl( $canonicalUrl, PROTO_CANONICAL ); + } else { + $reqUrl = $this->getRequest()->getRequestURL(); + $canonicalUrl = wfExpandUrl( $reqUrl, PROTO_CANONICAL ); + } + } + if ( $canonicalUrl !== false ) { + $tags[] = Html::element( 'link', array( + 'rel' => 'canonical', + 'href' => $canonicalUrl + ) ); + } + return $tags; } /** - * @param $unused - * @param $addContentType bool: Whether "<meta>" specifying content type should be returned - * * @return string HTML tag links to be put in the header. */ - public function getHeadLinks( $unused = null, $addContentType = false ) { - return implode( "\n", $this->getHeadLinksArray( $addContentType ) ); + public function getHeadLinks() { + return implode( "\n", $this->getHeadLinksArray() ); } /** * Generate a "<link rel/>" for a feed. * - * @param $type String: feed type - * @param $url String: URL to the feed - * @param $text String: value of the "title" attribute + * @param string $type feed type + * @param string $url URL to the feed + * @param string $text value of the "title" attribute * @return String: HTML fragment */ private function feedLink( $type, $url, $text ) { @@ -3275,22 +3337,22 @@ $templates * Add a local or specified stylesheet, with the given media options. * Meant primarily for internal use... * - * @param $style String: URL to the file - * @param $media String: to specify a media type, 'screen', 'printable', 'handheld' or any. - * @param $condition String: for IE conditional comments, specifying an IE version - * @param $dir String: set to 'rtl' or 'ltr' for direction-specific sheets + * @param string $style URL to the file + * @param string $media to specify a media type, 'screen', 'printable', 'handheld' or any. + * @param string $condition for IE conditional comments, specifying an IE version + * @param string $dir set to 'rtl' or 'ltr' for direction-specific sheets */ public function addStyle( $style, $media = '', $condition = '', $dir = '' ) { $options = array(); // Even though we expect the media type to be lowercase, but here we // force it to lowercase to be safe. - if( $media ) { + if ( $media ) { $options['media'] = $media; } - if( $condition ) { + if ( $condition ) { $options['condition'] = $condition; } - if( $dir ) { + if ( $dir ) { $options['dir'] = $dir; } $this->styles[$style] = $options; @@ -3299,10 +3361,10 @@ $templates /** * Adds inline CSS styles * @param $style_css Mixed: inline CSS - * @param $flip String: Set to 'flip' to flip the CSS if needed + * @param string $flip Set to 'flip' to flip the CSS if needed */ public function addInlineStyle( $style_css, $flip = 'noflip' ) { - if( $flip === 'flip' && $this->getLanguage()->isRTL() ) { + if ( $flip === 'flip' && $this->getLanguage()->isRTL() ) { # If wanted, and the interface is right-to-left, flip the CSS $style_css = CSSJanus::transform( $style_css, true, false ); } @@ -3316,8 +3378,7 @@ $templates * @return string */ public function buildCssLinks() { - global $wgUseSiteCss, $wgAllowUserCss, $wgAllowUserCssPrefs, - $wgLang, $wgContLang; + global $wgUseSiteCss, $wgAllowUserCss, $wgAllowUserCssPrefs, $wgContLang; $this->getSkin()->setupSkinUserCss( $this ); @@ -3333,7 +3394,7 @@ $templates if ( $wgUseSiteCss ) { $moduleStyles[] = 'site'; $moduleStyles[] = 'noscript'; - if( $this->getUser()->isLoggedIn() ){ + if ( $this->getUser()->isLoggedIn() ) { $moduleStyles[] = 'user.groups'; } } @@ -3351,7 +3412,7 @@ $templates // If needed, Janus it first. This is user-supplied CSS, so it's // assumed to be right for the content language directionality. $previewedCSS = $this->getRequest()->getText( 'wpTextbox1' ); - if ( $wgLang->getDir() !== $wgContLang->getDir() ) { + if ( $this->getLanguage()->getDir() !== $wgContLang->getDir() ) { $previewedCSS = CSSJanus::transform( $previewedCSS, true, false ); } $otherTags .= Html::inlineStyle( $previewedCSS ); @@ -3414,9 +3475,9 @@ $templates } $this->mExtStyles = array(); - foreach( $this->styles as $file => $options ) { + foreach ( $this->styles as $file => $options ) { $link = $this->styleLink( $file, $options ); - if( $link ) { + if ( $link ) { $links[$file] = $link; } } @@ -3426,28 +3487,28 @@ $templates /** * Generate \<link\> tags for stylesheets * - * @param $style String: URL to the file - * @param $options Array: option, can contain 'condition', 'dir', 'media' + * @param string $style URL to the file + * @param array $options option, can contain 'condition', 'dir', 'media' * keys * @return String: HTML fragment */ protected function styleLink( $style, $options ) { - if( isset( $options['dir'] ) ) { - if( $this->getLanguage()->getDir() != $options['dir'] ) { + if ( isset( $options['dir'] ) ) { + if ( $this->getLanguage()->getDir() != $options['dir'] ) { return ''; } } - if( isset( $options['media'] ) ) { + if ( isset( $options['media'] ) ) { $media = self::transformCssMedia( $options['media'] ); - if( is_null( $media ) ) { + if ( is_null( $media ) ) { return ''; } } else { $media = 'all'; } - if( substr( $style, 0, 1 ) == '/' || + if ( substr( $style, 0, 1 ) == '/' || substr( $style, 0, 5 ) == 'http:' || substr( $style, 0, 6 ) == 'https:' ) { $url = $style; @@ -3458,7 +3519,7 @@ $templates $link = Html::linkedStyle( $url, $media ); - if( isset( $options['condition'] ) ) { + if ( isset( $options['condition'] ) ) { $condition = htmlspecialchars( $options['condition'] ); $link = "<!--[if $condition]>$link<![endif]-->"; } @@ -3468,39 +3529,43 @@ $templates /** * Transform "media" attribute based on request parameters * - * @param $media String: current value of the "media" attribute - * @return String: modified value of the "media" attribute + * @param string $media current value of the "media" attribute + * @return String: modified value of the "media" attribute, or null to skip + * this stylesheet */ public static function transformCssMedia( $media ) { - global $wgRequest, $wgHandheldForIPhone; + global $wgRequest; + + // http://www.w3.org/TR/css3-mediaqueries/#syntax + $screenMediaQueryRegex = '/^(?:only\s+)?screen\b/i'; // Switch in on-screen display for media testing $switches = array( 'printable' => 'print', 'handheld' => 'handheld', ); - foreach( $switches as $switch => $targetMedia ) { - if( $wgRequest->getBool( $switch ) ) { - if( $media == $targetMedia ) { + foreach ( $switches as $switch => $targetMedia ) { + if ( $wgRequest->getBool( $switch ) ) { + if ( $media == $targetMedia ) { $media = ''; - } elseif( $media == 'screen' ) { - return null; + } elseif ( preg_match( $screenMediaQueryRegex, $media ) === 1 ) { + // This regex will not attempt to understand a comma-separated media_query_list + // + // Example supported values for $media: 'screen', 'only screen', 'screen and (min-width: 982px)' ), + // Example NOT supported value for $media: '3d-glasses, screen, print and resolution > 90dpi' + // + // If it's a print request, we never want any kind of screen stylesheets + // If it's a handheld request (currently the only other choice with a switch), + // we don't want simple 'screen' but we might want screen queries that + // have a max-width or something, so we'll pass all others on and let the + // client do the query. + if ( $targetMedia == 'print' || $media == 'screen' ) { + return null; + } } } } - // Expand longer media queries as iPhone doesn't grok 'handheld' - if( $wgHandheldForIPhone ) { - $mediaAliases = array( - 'screen' => 'screen and (min-device-width: 481px)', - 'handheld' => 'handheld, only screen and (max-device-width: 480px)', - ); - - if( isset( $mediaAliases[$media] ) ) { - $media = $mediaAliases[$media]; - } - } - return $media; } @@ -3557,7 +3622,6 @@ $templates $msgSpecs = array_values( $msgSpecs ); $s = $wrap; foreach ( $msgSpecs as $n => $spec ) { - $options = array(); if ( is_array( $spec ) ) { $args = $spec; $name = array_shift( $args ); @@ -3568,7 +3632,7 @@ $templates '1.20' ); } - } else { + } else { $args = array(); $name = $spec; } @@ -3581,7 +3645,7 @@ $templates * Include jQuery core. Use this to avoid loading it multiple times * before we get a usable script loader. * - * @param $modules Array: list of jQuery modules which should be loaded + * @param array $modules list of jQuery modules which should be loaded * @return Array: the list of modules which were not loaded. * @since 1.16 * @deprecated since 1.17 @@ -3590,4 +3654,20 @@ $templates return array(); } + /** + * Enables/disables TOC, doesn't override __NOTOC__ + * @param bool $flag + * @since 1.22 + */ + public function enableTOC( $flag = true ) { + $this->mEnableTOC = $flag; + } + + /** + * @return bool + * @since 1.22 + */ + public function isTOCEnabled() { + return $this->mEnableTOC; + } } |