Skip to content

Commit

Permalink
Optionally load headers and footers asynchronously (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesmontalvo3 authored Sep 6, 2018
1 parent 95c5a5c commit 314dc59
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 27 deletions.
79 changes: 79 additions & 0 deletions ApiGetHeaderFooter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

/**
* API module for MediaWiki's HeaderFooter extension.
*
* @author James Montalvo
* @since Version 3.0
*/

/**
* API module to review revisions
*/
class ApiGetHeaderFooter extends ApiBase {

public function execute() {

$params = $this->extractRequestParams();
$contextTitle = Title::newFromDBkey( $params['contexttitle'] );
if ( ! $contextTitle ) {
$this->dieUsage( "Not a valid contexttitle.", 'notarget' );
}

$messageId = $params['messageid'];

$messageText = wfMessage( $messageId )->title( $contextTitle )->text();

// don't need to bother if there is no content.
if ( empty( $messageText ) ) {
$messageText = '';
}

if ( wfMessage( $messageId )->inContentLanguage()->isBlank() ) {
$messageText = '';
}

global $wgParser;

$messageText = $wgParser->parse(
$messageText,
$contextTitle,
ParserOptions::newFromUser( $this->getUser() )
)->getText();

$this->getResult()->addValue( null, $this->getModuleName(), array( 'result' => $messageText ) );

}

public function getAllowedParams() {
return array(
'contexttitle' => array(
ApiBase::PARAM_REQUIRED => true,
ApiBase::PARAM_TYPE => 'string'
),
'messageid' => array(
ApiBase::PARAM_REQUIRED => true,
ApiBase::PARAM_TYPE => 'string'
)
);
}

/**
* @see ApiBase::getExamplesMessages()
*/
protected function getExamplesMessages() {
return array(
'action=getheaderfooter&contexttitle=Main_Page&messageid=Hf-nsfooter-'
=> 'apihelp-getheaderfooter-example-1',
);
}

public function mustBePosted() {
return false;
}

public function isWriteMode() {
return false;
}

}
70 changes: 48 additions & 22 deletions HeaderFooter.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,26 @@ public static function hOutputPageParserOutput( &$op, $parserOutput ) {

$text = $parserOutput->getText();

$nsheader = "hf-nsheader-$ns";
$nsfooter = "hf-nsfooter-$ns";
$nsheader = self::conditionalInclude( $text, '__NONSHEADER__', 'hf-nsheader', $ns );
$header = self::conditionalInclude( $text, '__NOHEADER__', 'hf-header', $name );
$footer = self::conditionalInclude( $text, '__NOFOOTER__', 'hf-footer', $name );
$nsfooter = self::conditionalInclude( $text, '__NONSFOOTER__', 'hf-nsfooter', $ns );

$header = "hf-header-$name";
$footer = "hf-footer-$name";
$parserOutput->setText( $nsheader . $header . $text . $footer . $nsfooter );

$text = '<div class="hf-header">'.self::conditionalInclude( $text, '__NOHEADER__', $header ).'</div>'.$text;
$text = '<div class="hf-nsheader">'.self::conditionalInclude( $text, '__NONSHEADER__', $nsheader ).'</div>'.$text;

$text .= '<div class="hf-footer">'.self::conditionalInclude( $text, '__NOFOOTER__', $footer ).'</div>';
$text .= '<div class="hf-nsfooter">'.self::conditionalInclude( $text, '__NONSFOOTER__', $nsfooter ).'</div>';

$parserOutput->setText( $text );
global $egHeaderFooterEnableAsyncHeader, $egHeaderFooterEnableAsyncFooter;
if ( $egHeaderFooterEnableAsyncFooter || $egHeaderFooterEnableAsyncHeader ) {
$op->addModules( 'ext.headerfooter.dynamicload' );
}

return true;
}

/**
* Verifies & Strips ''disable command'', returns $content if all OK.
*/
static function conditionalInclude( &$text, $disableWord, &$msgId ) {
static function conditionalInclude( &$text, $disableWord, $class, $unique ) {

// is there a disable command lurking around?
$disable = strpos( $text, $disableWord ) !== false;

Expand All @@ -55,18 +53,46 @@ static function conditionalInclude( &$text, $disableWord, &$msgId ) {
return null;
}

$msgText = wfMessage( $msgId )->parse();
$msgId = "$class-$unique"; // also HTML ID
$div = "<div class='$class' id='$msgId'>";

// don't need to bother if there is no content.
if ( empty( $msgText ) ) {
return null;
global $egHeaderFooterEnableAsyncHeader, $egHeaderFooterEnableAsyncFooter;

$isHeader = $class === 'hf-nsheader' || $class === 'hf-header';
$isFooter = $class === 'hf-nsfooter' || $class === 'hf-footer';

if ( ( $egHeaderFooterEnableAsyncFooter && $isFooter )
|| ( $egHeaderFooterEnableAsyncHeader && $isHeader ) ) {

// Just drop an empty div into the page. Will fill it with async
// request after page load
return $div . '</div>';
}
else {
$msgText = wfMessage( $msgId )->parse();

if ( wfMessage( $msgId )->inContentLanguage()->isBlank() ) {
return null;
}
// don't need to bother if there is no content.
if ( empty( $msgText ) ) {
return null;
}

if ( wfMessage( $msgId )->inContentLanguage()->isBlank() ) {
return null;
}

return $div . $msgText . '</div>';
}
}

public static function onResourceLoaderGetConfigVars ( array &$vars ) {
global $egHeaderFooterEnableAsyncHeader, $egHeaderFooterEnableAsyncFooter;

return $msgText;
$vars['egHeaderFooter'] = [
'enableAsyncHeader' => $egHeaderFooterEnableAsyncHeader,
'enableAsyncFooter' => $egHeaderFooterEnableAsyncFooter,
];

return true;
}

}
}
27 changes: 23 additions & 4 deletions extension.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,31 @@
"descriptionmsg": "headerfooter-desc",
"type": "other",
"AutoloadClasses": {
"HeaderFooter": "HeaderFooter.class.php"
"HeaderFooter": "HeaderFooter.class.php",
"ApiGetHeaderFooter": "ApiGetHeaderFooter.php"
},
"APIModules": {
"getheaderfooter": "ApiGetHeaderFooter"
},
"Hooks": {
"OutputPageParserOutput": [
"HeaderFooter::hOutputPageParserOutput"
]
"OutputPageParserOutput": "HeaderFooter::hOutputPageParserOutput",
"ResourceLoaderGetConfigVars": "HeaderFooter::onResourceLoaderGetConfigVars"
},
"ResourceFileModulePaths": {
"localBasePath": "modules",
"remoteExtPath": "HeaderFooter/modules"
},
"ResourceModules": {
"ext.headerfooter.dynamicload": {
"scripts": [
"dynamicload.js"
]
}
},
"config": {
"_prefix": "eg",
"HeaderFooterEnableAsyncHeader": false,
"HeaderFooterEnableAsyncFooter": false
},
"manifest_version": 1
}
7 changes: 6 additions & 1 deletion i18n/en.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{
"headerfooter-desc": "Enables per-page/per-namespace headers and footers"
"headerfooter-desc": "Enables per-page/per-namespace headers and footers",
"apihelp-getheaderfooter-description": "Retrieve the parsed output of a header or footer in the context of a certain page.",
"apihelp-getheaderfooter-summary": "Retrieve the parsed output of a header or footer in the context of a certain page.",
"apihelp-getheaderfooter-param-contexttitle": "The title of the page that the header or footer is being added to.",
"apihelp-getheaderfooter-param-messageid": "Which header or footer is being requested (e.g. a namespace header)",
"apihelp-getheaderfooter-example-1": "Get the NS_MAIN footer for Main Page"
}
48 changes: 48 additions & 0 deletions modules/dynamicload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@

var egHeaderFooter = mw.config.get( 'egHeaderFooter' );

if ( egHeaderFooter.enableAsyncHeader ) {
var extHeaderFooterBlocks = [ "hf-nsheader", "hf-header" ];
}
else {
var extHeaderFooterBlocks = [];
}
extHeaderFooterBlocks = extHeaderFooterBlocks.concat( [ "hf-footer", "hf-nsfooter" ] );

for ( var i = 0; i < extHeaderFooterBlocks.length; i++ ) {
var block = extHeaderFooterBlocks[i];

$( "." + block ).each( function( i, e ) {

// FIXME: At some point, put some method of indicating unloaded content here

// FIXME: At some point, add method to further delay loading of dynamic
// footers. Headers should be loaded right away, but footers should
// only be loaded if the user can see them (or is scrolling toward
// them).

// Message ID of block (header or footer) is in the HTML ID. hf-nsheader
// will have an ID like hf-nsheader-Help for the help namespace.
var msgId = $(e).attr('id');

$.get(
mw.config.get("wgScriptPath") + "/api.php",
{
action: "getheaderfooter",
messageid: msgId,
contexttitle: mw.config.get('wgPageName'),
format: "json"
},
function ( response ) {
// var blockText = response.query.allmessages[0]["*"];
var blockText = response.getheaderfooter.result;
$( "#" + msgId ).html( blockText );
$( "#" + msgId ).find( "#headertabs" ).each( function(i,e) {
$(e).tabs();
});
}
)

} );

}

0 comments on commit 314dc59

Please sign in to comment.