ApiParse: Add 'useskin' param for general OutputPage/Skin support
authorTimo Tijhof <krinklemail@gmail.com>
Tue, 25 Apr 2017 03:53:50 +0000 (20:53 -0700)
committerTimo Tijhof <krinklemail@gmail.com>
Sun, 21 May 2017 17:06:42 +0000 (19:06 +0200)
Required for Idc41934eb89.

* If 'useskin' is set, run ParserOutput through OutputPage (with proper
  Skin set up). Specifically call addParserOutputMetadata().

  Then use OutputPage isntead of ParserOutput to retrieve that subset
  of meta data. Such as modules, lang links and config vars.

* Deprecate 'effectivelanglinks' in favour of 'useskin'.

* Simplify 'headhtml' support and re-use this new code.

Change-Id: Iaa85ac49f6e0cbdf7f1bb0f50a8f7730d119f0a2

includes/api/ApiParse.php
includes/api/i18n/en.json
includes/api/i18n/qqq.json

index 7d22d9c..b36127d 100644 (file)
@@ -22,6 +22,8 @@
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * @ingroup API
  */
@@ -278,6 +280,40 @@ class ApiParse extends ApiBase {
                $result_array['title'] = $titleObj->getPrefixedText();
                $result_array['pageid'] = $pageid ?: $pageObj->getId();
 
+               if ( $params['disabletoc'] ) {
+                       $p_result->setTOCEnabled( false );
+               }
+
+               if ( isset( $params['useskin'] ) ) {
+                       $factory = MediaWikiServices::getInstance()->getSkinFactory();
+                       $skin = $factory->makeSkin( Skin::normalizeKey( $params['useskin'] ) );
+               } else {
+                       $skin = null;
+               }
+
+               $outputPage = null;
+               if ( $skin || isset( $prop['headhtml'] ) ) {
+                       // Enabling the skin via 'useskin' or 'headhtml' gets OutputPage and
+                       // Skin involved, which (among others) applies these hooks:
+                       // - ParserOutputHooks
+                       // - Hook: LanguageLinks
+                       // - Hook: OutputPageParserOutput
+                       $context = new DerivativeContext( $this->getContext() );
+                       $context->setTitle( $titleObj );
+                       $context->setWikiPage( $pageObj );
+
+                       if ( $skin ) {
+                               // Use the skin specified by 'useskin'
+                               $context->setSkin( $skin );
+                               // Context clones the skin, refetch to stay in sync. (T166022)
+                               $skin = $context->getSkin();
+                       }
+
+                       $outputPage = new OutputPage( $context );
+                       $outputPage->addParserOutputMetadata( $p_result );
+                       $context->setOutput( $outputPage );
+               }
+
                if ( !is_null( $oldid ) ) {
                        $result_array['revid'] = intval( $oldid );
                }
@@ -286,10 +322,6 @@ class ApiParse extends ApiBase {
                        $result_array['redirects'] = $redirValues;
                }
 
-               if ( $params['disabletoc'] ) {
-                       $p_result->setTOCEnabled( false );
-               }
-
                if ( isset( $prop['text'] ) ) {
                        $result_array['text'] = $p_result->getText();
                        $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'text';
@@ -303,19 +335,19 @@ class ApiParse extends ApiBase {
                }
 
                if ( isset( $prop['langlinks'] ) ) {
-                       $langlinks = $p_result->getLanguageLinks();
-
-                       if ( $params['effectivelanglinks'] ) {
-                               // Link flags are ignored for now, but may in the future be
-                               // included in the result.
-                               $linkFlags = [];
-                               Hooks::run( 'LanguageLinks', [ $titleObj, &$langlinks, &$linkFlags ] );
+                       if ( $skin ) {
+                               $langlinks = $outputPage->getLanguageLinks();
+                       } else {
+                               $langlinks = $p_result->getLanguageLinks();
+                               // The deprecated 'effectivelanglinks' option depredates OutputPage
+                               // support via 'useskin'. If not already applied, then run just this
+                               // one hook of OutputPage::addParserOutputMetadata here.
+                               if ( $params['effectivelanglinks'] ) {
+                                       $linkFlags = [];
+                                       Hooks::run( 'LanguageLinks', [ $titleObj, &$langlinks, &$linkFlags ] );
+                               }
                        }
-               } else {
-                       $langlinks = false;
-               }
 
-               if ( isset( $prop['langlinks'] ) ) {
                        $result_array['langlinks'] = $this->formatLangLinks( $langlinks );
                }
                if ( isset( $prop['categories'] ) ) {
@@ -350,38 +382,42 @@ class ApiParse extends ApiBase {
                }
 
                if ( isset( $prop['headitems'] ) ) {
-                       $result_array['headitems'] = $this->formatHeadItems( $p_result->getHeadItems() );
+                       if ( $skin ) {
+                               $result_array['headitems'] = $this->formatHeadItems( $outputPage->getHeadItemsArray() );
+                       } else {
+                               $result_array['headitems'] = $this->formatHeadItems( $p_result->getHeadItems() );
+                       }
                        $this->addDeprecation( 'apiwarn-deprecation-parse-headitems', 'action=parse&prop=headitems' );
                }
 
                if ( isset( $prop['headhtml'] ) ) {
-                       $context = new DerivativeContext( $this->getContext() );
-                       $context->setTitle( $titleObj );
-                       $context->setWikiPage( $pageObj );
-
-                       // We need an OutputPage tied to $context, not to the
-                       // RequestContext at the root of the stack.
-                       $output = new OutputPage( $context );
-                       $output->addParserOutputMetadata( $p_result );
-
-                       $result_array['headhtml'] = $output->headElement( $context->getSkin() );
+                       $result_array['headhtml'] = $outputPage->headElement( $context->getSkin() );
                        $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'headhtml';
                }
 
                if ( isset( $prop['modules'] ) ) {
-                       $result_array['modules'] = array_values( array_unique( $p_result->getModules() ) );
-                       $result_array['modulescripts'] = array_values( array_unique( $p_result->getModuleScripts() ) );
-                       $result_array['modulestyles'] = array_values( array_unique( $p_result->getModuleStyles() ) );
+                       if ( $skin ) {
+                               $result_array['modules'] = $outputPage->getModules();
+                               $result_array['modulescripts'] = $outputPage->getModuleScripts();
+                               $result_array['modulestyles'] = $outputPage->getModuleStyles();
+                       } else {
+                               $result_array['modules'] = array_values( array_unique( $p_result->getModules() ) );
+                               $result_array['modulescripts'] = array_values( array_unique( $p_result->getModuleScripts() ) );
+                               $result_array['modulestyles'] = array_values( array_unique( $p_result->getModuleStyles() ) );
+                       }
                }
 
                if ( isset( $prop['jsconfigvars'] ) ) {
-                       $result_array['jsconfigvars'] =
-                               ApiResult::addMetadataToResultVars( $p_result->getJsConfigVars() );
+                       $jsconfigvars = $skin ? $outputPage->getJsConfigVars() : $p_result->getJsConfigVars();
+                       $result_array['jsconfigvars'] = ApiResult::addMetadataToResultVars( $jsconfigvars );
                }
 
                if ( isset( $prop['encodedjsconfigvars'] ) ) {
+                       $jsconfigvars = $skin ? $outputPage->getJsConfigVars() : $p_result->getJsConfigVars();
                        $result_array['encodedjsconfigvars'] = FormatJson::encode(
-                               $p_result->getJsConfigVars(), false, FormatJson::ALL_OK
+                               $jsconfigvars,
+                               false,
+                               FormatJson::ALL_OK
                        );
                        $result_array[ApiResult::META_SUBELEMENTS][] = 'encodedjsconfigvars';
                }
@@ -392,7 +428,11 @@ class ApiParse extends ApiBase {
                }
 
                if ( isset( $prop['indicators'] ) ) {
-                       $result_array['indicators'] = (array)$p_result->getIndicators();
+                       if ( $skin ) {
+                               $result_array['indicators'] = (array)$outputPage->getIndicators();
+                       } else {
+                               $result_array['indicators'] = (array)$p_result->getIndicators();
+                       }
                        ApiResult::setArrayType( $result_array['indicators'], 'BCkvp', 'name' );
                }
 
@@ -794,7 +834,10 @@ class ApiParse extends ApiBase {
                        'wrapoutputclass' => 'mw-parser-output',
                        'pst' => false,
                        'onlypst' => false,
-                       'effectivelanglinks' => false,
+                       'effectivelanglinks' => [
+                               ApiBase::PARAM_DFLT => false,
+                               ApiBase::PARAM_DEPRECATED => true,
+                       ],
                        'section' => null,
                        'sectiontitle' => [
                                ApiBase::PARAM_TYPE => 'string',
@@ -816,6 +859,9 @@ class ApiParse extends ApiBase {
                        'preview' => false,
                        'sectionpreview' => false,
                        'disabletoc' => false,
+                       'useskin' => [
+                               ApiBase::PARAM_TYPE => array_keys( Skin::getAllowedSkins() ),
+                       ],
                        'contentformat' => [
                                ApiBase::PARAM_TYPE => ContentHandler::getAllContentFormats(),
                        ],
index 5f52a1e..a391662 100644 (file)
        "apihelp-parse-param-preview": "Parse in preview mode.",
        "apihelp-parse-param-sectionpreview": "Parse in section preview mode (enables preview mode too).",
        "apihelp-parse-param-disabletoc": "Omit table of contents in output.",
+       "apihelp-parse-param-useskin": "Apply the selected skin to the parser output. May affect the following properties: <kbd>langlinks</kbd>, <kbd>headitems</kbd>, <kbd>modules</kbd>, <kbd>jsconfigvars</kbd>, <kbd>indicators</kbd>.",
        "apihelp-parse-param-contentformat": "Content serialization format used for the input text. Only valid when used with $1text.",
        "apihelp-parse-param-contentmodel": "Content model of the input text. If omitted, $1title must be specified, and default will be the model of the specified title. Only valid when used with $1text.",
        "apihelp-parse-example-page": "Parse a page.",
index 672b7f0..ee28dd6 100644 (file)
        "apihelp-parse-param-generatexml": "{{doc-apihelp-param|parse|generatexml|params=* $1 - Value of the constant CONTENT_MODEL_WIKITEXT|paramstart=2}}",
        "apihelp-parse-param-preview": "{{doc-apihelp-param|parse|preview}}",
        "apihelp-parse-param-sectionpreview": "{{doc-apihelp-param|parse|sectionpreview}}",
+       "apihelp-parse-param-useskin": "{{doc-apihelp-param|parse|useskin}}",
        "apihelp-parse-param-disabletoc": "{{doc-apihelp-param|parse|disabletoc}}",
        "apihelp-parse-param-contentformat": "{{doc-apihelp-param|parse|contentformat}}",
        "apihelp-parse-param-contentmodel": "{{doc-apihelp-param|parse|contentmodel}}",