resourceloader: Add support for delivering templates
A base ResourceLoaderModule::getTemplates() exists for subclasses to override. An implementation is provided for ResourceLoaderFileModule. For file modules, templates can be specified in the following manner: 'example' => array( 'templates' => array( 'bar' => 'templates/foo.html', ), 'scripts' => 'example.js', ), The delivery system is template language agnostic, and currently only supports "compiling" plain HTML templates. This also adds template support to the following modules as a POC: * mediawiki.feedback * mediawiki.action.view.postEdit * mediawiki.special.upload Works with $wgResourceLoaderStorageEnabled Change-Id: Ia0c5c8ec960aa6dff12c9626cee41ae9a3286b76
This commit is contained in:
parent
79168e0f8b
commit
ebeb297236
20 changed files with 449 additions and 63 deletions
|
|
@ -974,12 +974,20 @@ class ResourceLoader {
|
|||
case 'messages':
|
||||
$out .= self::makeMessageSetScript( new XmlJsCode( $messagesBlob ) );
|
||||
break;
|
||||
case 'templates':
|
||||
$out .= Xml::encodeJsCall(
|
||||
'mw.templates.set',
|
||||
array( $name, (object)$module->getTemplates() ),
|
||||
ResourceLoader::inDebugMode()
|
||||
);
|
||||
break;
|
||||
default:
|
||||
$out .= self::makeLoaderImplementScript(
|
||||
$name,
|
||||
$scripts,
|
||||
$styles,
|
||||
new XmlJsCode( $messagesBlob )
|
||||
new XmlJsCode( $messagesBlob ),
|
||||
$module->getTemplates()
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
|
@ -1044,15 +1052,20 @@ class ResourceLoader {
|
|||
* @param mixed $messages List of messages associated with this module. May either be an
|
||||
* associative array mapping message key to value, or a JSON-encoded message blob containing
|
||||
* the same data, wrapped in an XmlJsCode object.
|
||||
* @param array $templates Keys are name of templates and values are the source of
|
||||
* the template.
|
||||
* @throws MWException
|
||||
* @return string
|
||||
*/
|
||||
public static function makeLoaderImplementScript( $name, $scripts, $styles, $messages ) {
|
||||
public static function makeLoaderImplementScript( $name, $scripts, $styles,
|
||||
$messages, $templates
|
||||
) {
|
||||
if ( is_string( $scripts ) ) {
|
||||
$scripts = new XmlJsCode( "function ( $, jQuery ) {\n{$scripts}\n}" );
|
||||
} elseif ( !is_array( $scripts ) ) {
|
||||
throw new MWException( 'Invalid scripts error. Array of URLs or string of code expected.' );
|
||||
}
|
||||
|
||||
return Xml::encodeJsCall(
|
||||
'mw.loader.implement',
|
||||
array(
|
||||
|
|
@ -1064,7 +1077,8 @@ class ResourceLoader {
|
|||
// PHP/json_encode() consider empty arrays to be numerical arrays and
|
||||
// output javascript "[]" instead of "{}". This fixes that.
|
||||
(object)$styles,
|
||||
(object)$messages
|
||||
(object)$messages,
|
||||
(object)$templates,
|
||||
),
|
||||
ResourceLoader::inDebugMode()
|
||||
);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
|
|||
/** @var string Remote base path, see __construct() */
|
||||
protected $remoteBasePath = '';
|
||||
|
||||
/** @var array Saves a list of the templates named by the modules. */
|
||||
protected $templates = array();
|
||||
|
||||
/**
|
||||
* @var array List of paths to JavaScript files to always include
|
||||
* @par Usage:
|
||||
|
|
@ -199,6 +202,9 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
|
|||
* 'loaderScripts' => [file path string or array of file path strings],
|
||||
* // Modules which must be loaded before this module
|
||||
* 'dependencies' => [module name string or array of module name strings],
|
||||
* 'templates' => array(
|
||||
* [template alias with file.ext] => [file path to a template file],
|
||||
* ),
|
||||
* // Styles to always load
|
||||
* 'styles' => [file path string or array of file path strings],
|
||||
* // Styles to include in specific skin contexts
|
||||
|
|
@ -223,6 +229,8 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
|
|||
$localBasePath = null,
|
||||
$remoteBasePath = null
|
||||
) {
|
||||
// Flag to decide whether to automagically add the mediawiki.template module
|
||||
$hasTemplates = false;
|
||||
// localBasePath and remoteBasePath both have unbelievably long fallback chains
|
||||
// and need to be handled separately.
|
||||
list( $this->localBasePath, $this->remoteBasePath ) =
|
||||
|
|
@ -238,6 +246,10 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
|
|||
case 'styles':
|
||||
$this->{$member} = (array)$option;
|
||||
break;
|
||||
case 'templates':
|
||||
$hasTemplates = true;
|
||||
$this->{$member} = (array)$option;
|
||||
break;
|
||||
// Collated lists of file paths
|
||||
case 'languageScripts':
|
||||
case 'skinScripts':
|
||||
|
|
@ -281,6 +293,9 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if ( $hasTemplates ) {
|
||||
$this->dependencies[] = 'mediawiki.template';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -535,6 +550,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
|
|||
$files = array_merge(
|
||||
$files,
|
||||
$this->scripts,
|
||||
$this->templates,
|
||||
$context->getDebug() ? $this->debugScripts : array(),
|
||||
$this->getLanguageScripts( $context->getLanguage() ),
|
||||
self::tryForKey( $this->skinScripts, $context->getSkin(), 'default' ),
|
||||
|
|
@ -590,6 +606,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
|
|||
'dependencies',
|
||||
'messages',
|
||||
'targets',
|
||||
'templates',
|
||||
'group',
|
||||
'position',
|
||||
'skipFunction',
|
||||
|
|
@ -959,4 +976,30 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
|
|||
protected function getLessCompiler( ResourceLoaderContext $context = null ) {
|
||||
return ResourceLoader::getLessCompiler( $this->getConfig() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes named templates by the module and returns an array mapping.
|
||||
*
|
||||
* @return array of templates mapping template alias to content
|
||||
*/
|
||||
public function getTemplates() {
|
||||
$templates = array();
|
||||
|
||||
foreach ( $this->templates as $alias => $templatePath ) {
|
||||
// Alias is optional
|
||||
if ( is_int( $alias ) ) {
|
||||
$alias = $templatePath;
|
||||
}
|
||||
$localPath = $this->getLocalPath( $templatePath );
|
||||
if ( file_exists( $localPath ) ) {
|
||||
$content = file_get_contents( $localPath );
|
||||
$templates[ $alias ] = $content;
|
||||
} else {
|
||||
$msg = __METHOD__ . ": template file not found: \"$localPath\"";
|
||||
wfDebugLog( 'resourceloader', $msg );
|
||||
throw new MWException( $msg );
|
||||
}
|
||||
}
|
||||
return $templates;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,6 +134,16 @@ abstract class ResourceLoaderModule {
|
|||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes named templates by the module and returns an array mapping.
|
||||
*
|
||||
* @return array of templates mapping template alias to content
|
||||
*/
|
||||
public function getTemplates() {
|
||||
// Stub, override expected.
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Config
|
||||
* @since 1.24
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@
|
|||
"mw.html",
|
||||
"mw.html.Cdata",
|
||||
"mw.html.Raw",
|
||||
"mw.hook"
|
||||
"mw.hook",
|
||||
"mw.template"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -779,6 +779,10 @@ return array(
|
|||
'mediawiki.hlist',
|
||||
),
|
||||
),
|
||||
'mediawiki.template' => array(
|
||||
'scripts' => 'resources/src/mediawiki/mediawiki.template.js',
|
||||
'targets' => array( 'desktop', 'mobile' ),
|
||||
),
|
||||
'mediawiki.apipretty' => array(
|
||||
'styles' => 'resources/src/mediawiki/mediawiki.apipretty.css',
|
||||
'targets' => array( 'desktop', 'mobile' ),
|
||||
|
|
@ -851,6 +855,9 @@ return array(
|
|||
'position' => 'bottom',
|
||||
),
|
||||
'mediawiki.feedback' => array(
|
||||
'templates' => array(
|
||||
'dialog.html' => 'resources/src/mediawiki/templates/dialog.html',
|
||||
),
|
||||
'scripts' => 'resources/src/mediawiki/mediawiki.feedback.js',
|
||||
'styles' => 'resources/src/mediawiki/mediawiki.feedback.css',
|
||||
'dependencies' => array(
|
||||
|
|
@ -1063,6 +1070,9 @@ return array(
|
|||
),
|
||||
),
|
||||
'mediawiki.action.view.postEdit' => array(
|
||||
'templates' => array(
|
||||
'postEdit.html' => 'resources/src/mediawiki.action/templates/postEdit.html',
|
||||
),
|
||||
'scripts' => 'resources/src/mediawiki.action/mediawiki.action.view.postEdit.js',
|
||||
'styles' => 'resources/src/mediawiki.action/mediawiki.action.view.postEdit.css',
|
||||
'dependencies' => array(
|
||||
|
|
@ -1337,6 +1347,9 @@ return array(
|
|||
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.undelete.js',
|
||||
),
|
||||
'mediawiki.special.upload' => array(
|
||||
'templates' => array(
|
||||
'thumbnail.html' => 'resources/src/mediawiki.special/templates/thumbnail.html',
|
||||
),
|
||||
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.upload.js',
|
||||
'messages' => array(
|
||||
'widthheight',
|
||||
|
|
|
|||
|
|
@ -30,14 +30,7 @@
|
|||
data.message = $.parseHTML( mw.message( 'postedit-confirmation-saved', data.user || mw.user ).escaped() );
|
||||
}
|
||||
|
||||
$div = $(
|
||||
'<div class="postedit-container">' +
|
||||
'<div class="postedit">' +
|
||||
'<div class="postedit-icon postedit-icon-checkmark postedit-content"></div>' +
|
||||
'<a href="#" class="postedit-close">×</a>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
);
|
||||
$div = mw.template.get( 'mediawiki.action.view.postEdit', 'postEdit.html' ).render();
|
||||
|
||||
if ( typeof data.message === 'string' ) {
|
||||
$div.find( '.postedit-content' ).text( data.message );
|
||||
|
|
|
|||
6
resources/src/mediawiki.action/templates/postEdit.html
Normal file
6
resources/src/mediawiki.action/templates/postEdit.html
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<div class="postedit-container">
|
||||
<div class="postedit">
|
||||
<div class="postedit-icon postedit-icon-checkmark postedit-content"></div>
|
||||
<a href="#" class="postedit-close">×</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -294,12 +294,7 @@
|
|||
ctx,
|
||||
meta,
|
||||
previewSize = 180,
|
||||
thumb = $( '<div id="mw-upload-thumbnail" class="thumb tright">' +
|
||||
'<div class="thumbinner">' +
|
||||
'<div class="mw-small-spinner" style="width: 180px; height: 180px"></div>' +
|
||||
'<div class="thumbcaption"><div class="filename"></div><div class="fileinfo"></div></div>' +
|
||||
'</div>' +
|
||||
'</div>' );
|
||||
thumb = mw.template.get( 'mediawiki.special.upload', 'thumbnail.html' ).render();
|
||||
|
||||
thumb.find( '.filename' ).text( file.name ).end()
|
||||
.find( '.fileinfo' ).text( prettySize( file.size ) ).end();
|
||||
|
|
|
|||
9
resources/src/mediawiki.special/templates/thumbnail.html
Normal file
9
resources/src/mediawiki.special/templates/thumbnail.html
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<div id="mw-upload-thumbnail" class="thumb tright">
|
||||
<div class="thumbinner">
|
||||
<div class="mw-small-spinner" style="width: 180px; height: 180px"></div>
|
||||
<div class="thumbcaption">
|
||||
<div class="filename"></div>
|
||||
<div class="fileinfo"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -100,47 +100,20 @@
|
|||
target: '_blank'
|
||||
} );
|
||||
|
||||
// TODO: Use a stylesheet instead of these inline styles
|
||||
this.$dialog =
|
||||
$( '<div style="position: relative;"></div>' ).append(
|
||||
$( '<div class="feedback-mode feedback-form"></div>' ).append(
|
||||
$( '<small>' ).append(
|
||||
$( '<p>' ).msg(
|
||||
'feedback-bugornote',
|
||||
$bugNoteLink,
|
||||
fb.title.getNameText(),
|
||||
$feedbackPageLink.clone()
|
||||
)
|
||||
),
|
||||
$( '<div style="margin-top: 1em;"></div>' )
|
||||
.msg( 'feedback-subject' )
|
||||
.append(
|
||||
$( '<br>' ),
|
||||
$( '<input type="text" class="feedback-subject" name="subject" maxlength="60" style="width: 100%; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;"/>' )
|
||||
),
|
||||
$( '<div style="margin-top: 0.4em;"></div>' )
|
||||
.msg( 'feedback-message' )
|
||||
.append(
|
||||
$( '<br>' ),
|
||||
$( '<textarea name="message" class="feedback-message" rows="5" cols="60"></textarea>' )
|
||||
)
|
||||
),
|
||||
$( '<div class="feedback-mode feedback-bugs"></div>' ).append(
|
||||
$( '<p>' ).msg( 'feedback-bugcheck', $bugsListLink )
|
||||
),
|
||||
$( '<div class="feedback-mode feedback-submitting" style="text-align: center; margin: 3em 0;"></div>' )
|
||||
.msg( 'feedback-adding' )
|
||||
.append(
|
||||
$( '<br>' ),
|
||||
$( '<span class="feedback-spinner"></span>' )
|
||||
),
|
||||
$( '<div class="feedback-mode feedback-thanks" style="text-align: center; margin:1em"></div>' ).msg(
|
||||
'feedback-thanks', fb.title.getNameText(), $feedbackPageLink.clone()
|
||||
),
|
||||
$( '<div class="feedback-mode feedback-error" style="position: relative;"></div>' ).append(
|
||||
$( '<div class="feedback-error-msg style="color: #990000; margin-top: 0.4em;"></div>' )
|
||||
)
|
||||
);
|
||||
// TODO: Use a stylesheet instead of these inline styles in the template
|
||||
this.$dialog = mw.template.get( 'mediawiki.feedback', 'dialog.html' ).render();
|
||||
this.$dialog.find( '.feedback-mode small p' ).msg(
|
||||
'feedback-bugornote',
|
||||
$bugNoteLink,
|
||||
fb.title.getNameText(),
|
||||
$feedbackPageLink.clone()
|
||||
);
|
||||
this.$dialog.find( '.feedback-form .subject span' ).msg( 'feedback-subject' );
|
||||
this.$dialog.find( '.feedback-form .message span' ).msg( 'feedback-message' );
|
||||
this.$dialog.find( '.feedback-bugs p' ).msg( 'feedback-bugcheck', $bugsListLink );
|
||||
this.$dialog.find( '.feedback-submitting span' ).msg( 'feedback-adding' );
|
||||
this.$dialog.find( '.feedback-thanks' ).msg( 'feedback-thanks', fb.title.getNameText(),
|
||||
$feedbackPageLink.clone() );
|
||||
|
||||
this.$dialog.dialog( {
|
||||
width: 500,
|
||||
|
|
|
|||
|
|
@ -483,6 +483,12 @@
|
|||
*/
|
||||
messages: new Map(),
|
||||
|
||||
/**
|
||||
* Templates associated with a module
|
||||
* @property {mw.Map}
|
||||
*/
|
||||
templates: new Map(),
|
||||
|
||||
/* Public Methods */
|
||||
|
||||
/**
|
||||
|
|
@ -1170,6 +1176,11 @@
|
|||
mw.messages.set( registry[module].messages );
|
||||
}
|
||||
|
||||
// Initialise templates
|
||||
if ( registry[module].templates ) {
|
||||
mw.templates.set( module, registry[module].templates );
|
||||
}
|
||||
|
||||
if ( $.isReady || registry[module].async ) {
|
||||
// Make sure we don't run the scripts until all (potentially asynchronous)
|
||||
// stylesheet insertions have completed.
|
||||
|
|
@ -1660,8 +1671,9 @@
|
|||
* whether it's safe to extend the stylesheet (see #canExpandStylesheetWith).
|
||||
*
|
||||
* @param {Object} msgs List of key/value pairs to be added to mw#messages.
|
||||
* @param {Object} [templates] List of key/value pairs to be added to mw#templates.
|
||||
*/
|
||||
implement: function ( module, script, style, msgs ) {
|
||||
implement: function ( module, script, style, msgs, templates ) {
|
||||
// Validate input
|
||||
if ( typeof module !== 'string' ) {
|
||||
throw new Error( 'module must be a string, not a ' + typeof module );
|
||||
|
|
@ -1675,6 +1687,9 @@
|
|||
if ( !$.isPlainObject( msgs ) ) {
|
||||
throw new Error( 'msgs must be an object, not a ' + typeof msgs );
|
||||
}
|
||||
if ( templates !== undefined && !$.isPlainObject( templates ) ) {
|
||||
throw new Error( 'templates must be an object, not a ' + typeof templates );
|
||||
}
|
||||
// Automatically register module
|
||||
if ( registry[module] === undefined ) {
|
||||
mw.loader.register( module );
|
||||
|
|
@ -1687,6 +1702,8 @@
|
|||
registry[module].script = script;
|
||||
registry[module].style = style;
|
||||
registry[module].messages = msgs;
|
||||
// Templates are optional (for back-compat)
|
||||
registry[module].templates = templates || {};
|
||||
// The module may already have been marked as erroneous
|
||||
if ( $.inArray( registry[module].state, ['error', 'missing'] ) === -1 ) {
|
||||
registry[module].state = 'loaded';
|
||||
|
|
@ -2057,7 +2074,8 @@
|
|||
// Unversioned, private, or site-/user-specific
|
||||
( !descriptor.version || $.inArray( descriptor.group, [ 'private', 'user', 'site' ] ) !== -1 ) ||
|
||||
// Partial descriptor
|
||||
$.inArray( undefined, [ descriptor.script, descriptor.style, descriptor.messages ] ) !== -1
|
||||
$.inArray( undefined, [ descriptor.script, descriptor.style,
|
||||
descriptor.messages, descriptor.templates ] ) !== -1
|
||||
) {
|
||||
// Decline to store
|
||||
return false;
|
||||
|
|
@ -2070,7 +2088,8 @@
|
|||
String( descriptor.script ) :
|
||||
JSON.stringify( descriptor.script ),
|
||||
JSON.stringify( descriptor.style ),
|
||||
JSON.stringify( descriptor.messages )
|
||||
JSON.stringify( descriptor.messages ),
|
||||
JSON.stringify( descriptor.templates )
|
||||
];
|
||||
// Attempted workaround for a possible Opera bug (bug 57567).
|
||||
// This regex should never match under sane conditions.
|
||||
|
|
|
|||
123
resources/src/mediawiki/mediawiki.template.js
Normal file
123
resources/src/mediawiki/mediawiki.template.js
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* @class mw.template
|
||||
* @singleton
|
||||
*/
|
||||
( function ( mw, $ ) {
|
||||
var compiledTemplates = {},
|
||||
compilers = {};
|
||||
|
||||
mw.template = {
|
||||
/**
|
||||
* Register a new compiler and template.
|
||||
*
|
||||
* @param {string} name of compiler. Should also match with any file extensions of templates that want to use it.
|
||||
* @param {Function} compiler which must implement a compile function
|
||||
*/
|
||||
registerCompiler: function ( name, compiler ) {
|
||||
if ( !compiler.compile ) {
|
||||
throw new Error( 'Compiler must implement compile method.' );
|
||||
}
|
||||
compilers[name] = compiler;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the name of the compiler associated with a template based on its name.
|
||||
*
|
||||
* @param {string} templateName Name of template (including file suffix)
|
||||
* @return {String} Name of compiler
|
||||
*/
|
||||
getCompilerName: function ( templateName ) {
|
||||
var templateParts = templateName.split( '.' );
|
||||
|
||||
if ( templateParts.length < 2 ) {
|
||||
throw new Error( 'Unable to identify compiler. Template name must have a suffix.' );
|
||||
}
|
||||
return templateParts[ templateParts.length - 1 ];
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the compiler for a given compiler name.
|
||||
*
|
||||
* @param {string} compilerName Name of the compiler
|
||||
* @return {Object} The compiler associated with that name
|
||||
*/
|
||||
getCompiler: function ( compilerName ) {
|
||||
var compiler = compilers[ compilerName ];
|
||||
if ( !compiler ) {
|
||||
throw new Error( 'Unknown compiler ' + compilerName );
|
||||
}
|
||||
return compiler;
|
||||
},
|
||||
|
||||
/**
|
||||
* Register a template associated with a module.
|
||||
*
|
||||
* Compiles the newly added template based on the suffix in its name.
|
||||
*
|
||||
* @param {string} moduleName Name of ResourceLoader module to get the template from
|
||||
* @param {string} templateName Name of template to add including file extension
|
||||
* @param {string} templateBody Contents of a template (e.g. html markup)
|
||||
* @return {Function} Compiled template
|
||||
*/
|
||||
add: function ( moduleName, templateName, templateBody ) {
|
||||
var compiledTemplate,
|
||||
compilerName = this.getCompilerName( templateName );
|
||||
|
||||
if (!compiledTemplates[moduleName]) {
|
||||
compiledTemplates[moduleName] = {};
|
||||
}
|
||||
|
||||
compiledTemplate = this.compile( templateBody, compilerName );
|
||||
compiledTemplates[moduleName][ templateName ] = compiledTemplate;
|
||||
return compiledTemplate;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve a template by module and template name.
|
||||
*
|
||||
* @param {string} moduleName Name of the module to retrieve the template from
|
||||
* @param {string} templateName Name of template to be retrieved
|
||||
* @return {Object} Compiled template
|
||||
*/
|
||||
get: function ( moduleName, templateName ) {
|
||||
var moduleTemplates, compiledTemplate;
|
||||
|
||||
// Check if the template has already been compiled, compile it if not
|
||||
if ( !compiledTemplates[ moduleName ] || !compiledTemplates[ moduleName ][ templateName ] ) {
|
||||
moduleTemplates = mw.templates.get( moduleName );
|
||||
if ( !moduleTemplates || !moduleTemplates[ templateName ] ) {
|
||||
throw new Error( 'Template ' + templateName + ' not found in module ' + moduleName );
|
||||
}
|
||||
|
||||
// Add compiled version
|
||||
compiledTemplate = this.add( moduleName, templateName, moduleTemplates[ templateName ] );
|
||||
} else {
|
||||
compiledTemplate = compiledTemplates[ moduleName ][ templateName ];
|
||||
}
|
||||
return compiledTemplate;
|
||||
},
|
||||
|
||||
/**
|
||||
* Wrap our template engine of choice.
|
||||
*
|
||||
* @param {string} templateBody Template body
|
||||
* @param {string} compilerName The name of a registered compiler
|
||||
* @return {Object} Template interface
|
||||
*/
|
||||
compile: function ( templateBody, compilerName ) {
|
||||
return this.getCompiler( compilerName ).compile( templateBody );
|
||||
}
|
||||
};
|
||||
|
||||
// Register basic html compiler
|
||||
mw.template.registerCompiler( 'html', {
|
||||
compile: function ( src ) {
|
||||
return {
|
||||
render: function () {
|
||||
return $( $.parseHTML( $.trim( src ) ) );
|
||||
}
|
||||
};
|
||||
}
|
||||
} );
|
||||
|
||||
}( mediaWiki, jQuery ) );
|
||||
25
resources/src/mediawiki/templates/dialog.html
Normal file
25
resources/src/mediawiki/templates/dialog.html
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<div style="position: relative; display: block;" class="ui-dialog-content ui-widget-content">
|
||||
<div class="feedback-mode feedback-form">
|
||||
<small><p></p></small>
|
||||
<div class="subject" style="margin-top: 1em;">
|
||||
<span></span><br>
|
||||
<input type="text" class="feedback-subject" name="subject" maxlength="60"
|
||||
style="width: 100%; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;">
|
||||
</div>
|
||||
<div class="message" style="margin-top: 0.4em;">
|
||||
<span></span><br>
|
||||
<textarea name="message" class="feedback-message" rows="5" cols="60"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feedback-mode feedback-bugs">
|
||||
<p></p>
|
||||
</div>
|
||||
<div class="feedback-mode feedback-submitting" style="text-align: center; margin: 3em 0;">
|
||||
<span></span><br>
|
||||
<span class="feedback-spinner"></span>
|
||||
</div>
|
||||
<div class="feedback-mode feedback-thanks" style="text-align: center; margin:1em"></div>
|
||||
<div class="feedback-mode feedback-error" style="position: relative;">
|
||||
<div class="feedback-error-msg" style=" color:#990000; margin-top:0.4em;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -172,7 +172,7 @@ mw.test.baz({token:123});mw.loader.state({"test.quux":"ready"});
|
|||
array(
|
||||
array( 'test.quux', ResourceLoaderModule::TYPE_COMBINED ),
|
||||
'<script>if(window.mw){
|
||||
mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{"css":[".mw-icon{transition:none}\n"]},{});
|
||||
mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{"css":[".mw-icon{transition:none}\n"]},{},{});
|
||||
|
||||
}</script>
|
||||
'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group ResourceLoader
|
||||
*/
|
||||
class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase {
|
||||
|
||||
protected function setUp() {
|
||||
|
|
@ -15,6 +18,76 @@ class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase {
|
|||
);
|
||||
}
|
||||
|
||||
public static function getModules() {
|
||||
$base = array(
|
||||
'localBasePath' => realpath( dirname( __FILE__ ) ),
|
||||
);
|
||||
|
||||
return array(
|
||||
'noTemplateModule' => array(),
|
||||
|
||||
'htmlTemplateModule' => $base + array(
|
||||
'templates' => array(
|
||||
'templates/template.html',
|
||||
'templates/template2.html',
|
||||
)
|
||||
),
|
||||
|
||||
'aliasedHtmlTemplateModule' => $base + array(
|
||||
'templates' => array(
|
||||
'foo.html' => 'templates/template.html',
|
||||
'bar.html' => 'templates/template2.html',
|
||||
)
|
||||
),
|
||||
|
||||
'templateModuleHandlebars' => $base + array(
|
||||
'templates' => array(
|
||||
'templates/template_awesome.handlebars',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public static function providerGetTemplates() {
|
||||
$modules = self::getModules();
|
||||
|
||||
return array(
|
||||
array(
|
||||
$modules['noTemplateModule'],
|
||||
array(),
|
||||
),
|
||||
array(
|
||||
$modules['templateModuleHandlebars'],
|
||||
array(
|
||||
'templates/template_awesome.handlebars' => "wow\n",
|
||||
),
|
||||
),
|
||||
array(
|
||||
$modules['htmlTemplateModule'],
|
||||
array(
|
||||
'templates/template.html' => "<strong>hello</strong>\n",
|
||||
'templates/template2.html' => "<div>goodbye</div>\n",
|
||||
),
|
||||
),
|
||||
array(
|
||||
$modules['aliasedHtmlTemplateModule'],
|
||||
array(
|
||||
'foo.html' => "<strong>hello</strong>\n",
|
||||
'bar.html' => "<div>goodbye</div>\n",
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public static function providerGetModifiedTime() {
|
||||
$modules = self::getModules();
|
||||
|
||||
return array(
|
||||
// Check the default value when no templates present in module is 1
|
||||
array( $modules['noTemplateModule'], 1 ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ResourceLoaderFileModule::getAllSkinStyleFiles
|
||||
*/
|
||||
|
|
@ -58,4 +131,25 @@ class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase {
|
|||
array_map( 'basename', $module->getAllStyleFiles() )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerGetTemplates
|
||||
* @covers ResourceLoaderFileModule::getTemplates
|
||||
*/
|
||||
public function testGetTemplates( $module, $expected ) {
|
||||
$rl = new ResourceLoaderFileModule( $module );
|
||||
|
||||
$this->assertEquals( $rl->getTemplates(), $expected );
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerGetModifiedTime
|
||||
* @covers ResourceLoaderFileModule::getModifiedTime
|
||||
*/
|
||||
public function testGetModifiedTime( $module, $expected ) {
|
||||
$rl = new ResourceLoaderFileModule( $module );
|
||||
$ts = $rl->getModifiedTime( new ResourceLoaderContext(
|
||||
new ResourceLoader, new FauxRequest() ) );
|
||||
$this->assertEquals( $ts, $expected );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
<strong>hello</strong>
|
||||
|
|
@ -0,0 +1 @@
|
|||
<div>goodbye</div>
|
||||
|
|
@ -0,0 +1 @@
|
|||
wow
|
||||
|
|
@ -66,6 +66,7 @@ return array(
|
|||
'tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js',
|
||||
'tests/qunit/suites/resources/mediawiki/mediawiki.test.js',
|
||||
'tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js',
|
||||
'tests/qunit/suites/resources/mediawiki/mediawiki.template.test.js',
|
||||
'tests/qunit/suites/resources/mediawiki/mediawiki.toc.test.js',
|
||||
'tests/qunit/suites/resources/mediawiki/mediawiki.Uri.test.js',
|
||||
'tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js',
|
||||
|
|
@ -106,6 +107,7 @@ return array(
|
|||
'mediawiki.toc',
|
||||
'mediawiki.Uri',
|
||||
'mediawiki.user',
|
||||
'mediawiki.template',
|
||||
'mediawiki.util',
|
||||
'mediawiki.special.recentchanges',
|
||||
'mediawiki.language',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
( function ( mw ) {
|
||||
|
||||
QUnit.module( 'mediawiki.template', {
|
||||
setup: function () {
|
||||
var abcCompiler = {
|
||||
compile: function () {
|
||||
return 'abc default compiler';
|
||||
}
|
||||
};
|
||||
|
||||
// Register some template compiler languages
|
||||
mw.template.registerCompiler( 'abc', abcCompiler );
|
||||
mw.template.registerCompiler( 'xyz', {
|
||||
compile: function () {
|
||||
return 'xyz compiler';
|
||||
}
|
||||
} );
|
||||
|
||||
// Stub register some templates
|
||||
this.sandbox.stub( mw.templates, 'get' ).returns( {
|
||||
'test_templates_foo.xyz': 'goodbye',
|
||||
'test_templates_foo.abc': 'thankyou'
|
||||
} );
|
||||
}
|
||||
} );
|
||||
|
||||
QUnit.test( 'add', 1, function ( assert ) {
|
||||
assert.throws(
|
||||
function () {
|
||||
mw.template.add( 'module', 'test_templates_foo', 'hello' );
|
||||
},
|
||||
'When no prefix throw exception'
|
||||
);
|
||||
} );
|
||||
|
||||
QUnit.test( 'compile', 1, function ( assert ) {
|
||||
assert.throws(
|
||||
function () {
|
||||
mw.template.compile( '{{foo}}', 'rainbow' );
|
||||
},
|
||||
'Unknown compiler names throw exceptions'
|
||||
);
|
||||
} );
|
||||
|
||||
QUnit.test( 'get', 4, function ( assert ) {
|
||||
assert.strictEqual( mw.template.get( 'test.mediawiki.template', 'test_templates_foo.xyz' ), 'xyz compiler' );
|
||||
assert.strictEqual( mw.template.get( 'test.mediawiki.template', 'test_templates_foo.abc' ), 'abc default compiler' );
|
||||
assert.throws(
|
||||
function () {
|
||||
mw.template.get( 'this.should.not.exist', 'hello' );
|
||||
},
|
||||
'When bad module name given throw error.'
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
function () {
|
||||
mw.template.get( 'mediawiki.template', 'hello' );
|
||||
},
|
||||
'The template hello should not exist in the mediawiki.templates module and should throw an exception.'
|
||||
);
|
||||
} );
|
||||
|
||||
}( mediaWiki ) );
|
||||
Loading…
Reference in a new issue