2 * An extensible library for rendering templates in different template languages.
3 * By default only the `html` template library is provided.
4 * The Mustache library is also provided in mediawiki core via the mediawiki.template.mustache library.
7 * // returns $( '<div>hello world</div>' );
8 * const $node = mw.template.compile( '<div>hello world</div>', 'html' ).render();
10 * // also returns $( '<div>hello world</div>' );
11 * mw.loader.using( 'mediawiki.template.mustache' ).then( () => {
12 * const $node = mw.template.compile( '<div>{{ >Foo }}</div>', 'mustache' ).render( {
15 * Foo: mw.template.compile( '{{text}}', 'mustache' )
18 * @namespace mw.template
22 * Compiles a template for rendering.
24 * @typedef {Function} mw.template~TemplateCompileFunction
25 * @param {string} src source of the template
26 * @return {TemplateRenderer} for rendering
30 * Renders the template to create a jQuery object.
32 * @typedef {Function} mw.template~TemplateRenderFunction
33 * @param {Object} [data] for the template
34 * @param {Object} [partials] additional partial templates
39 * @typedef {Object} mw.template~TemplateRenderer
40 * @property {TemplateRenderFunction} render
44 * @typedef {Object} mw.template~TemplateCompiler
45 * @property {TemplateCompileFunction} compile
48 const compiledTemplates = {},
53 * Register a new compiler.
55 * A compiler is any object that implements a {@link mw.template.compile} method. The compile() method must
56 * return a Template interface with a method render() that returns HTML.
58 * The compiler name must correspond with the name suffix of templates that use this compiler.
60 * @param {string} name Compiler name
61 * @param {TemplateCompiler} compiler
63 registerCompiler: function ( name, compiler ) {
64 if ( !compiler.compile ) {
65 throw new Error( 'Compiler must implement a compile method' );
67 compilers[ name ] = compiler;
71 * Get the name of the associated compiler based on a template name.
73 * @param {string} templateName Name of a template (including suffix)
74 * @return {string} Name of a compiler
76 getCompilerName: function ( templateName ) {
77 const nameParts = templateName.split( '.' );
78 if ( nameParts.length < 2 ) {
79 throw new Error( 'Template name must have a suffix' );
81 return nameParts[ nameParts.length - 1 ];
85 * Get a compiler via its name.
87 * @param {string} name Name of a compiler
88 * @return {TemplateCompiler} The compiler
89 * @throws {Error} when unknown compiler provided
91 getCompiler: function ( name ) {
92 const compiler = compilers[ name ];
94 throw new Error( 'Unknown compiler ' + name );
100 * Register a template associated with a module.
102 * Precompiles the newly added template based on the suffix in its name.
104 * @param {string} moduleName Name of the ResourceLoader module the template is associated with
105 * @param {string} templateName Name of the template (including suffix)
106 * @param {string} templateBody Contents of the template (e.g. html markup)
107 * @return {TemplateRenderer} Compiled template
109 add: function ( moduleName, templateName, templateBody ) {
110 // Precompile and add to cache
111 const compiled = this.compile( templateBody, this.getCompilerName( templateName ) );
112 if ( !compiledTemplates[ moduleName ] ) {
113 compiledTemplates[ moduleName ] = {};
115 compiledTemplates[ moduleName ][ templateName ] = compiled;
121 * Get a compiled template by module and template name.
123 * @param {string} moduleName Name of the module to retrieve the template from
124 * @param {string} templateName Name of template to be retrieved
125 * @return {TemplateRenderer} Compiled template
127 get: function ( moduleName, templateName ) {
129 if ( compiledTemplates[ moduleName ] && compiledTemplates[ moduleName ][ templateName ] ) {
130 return compiledTemplates[ moduleName ][ templateName ];
133 const moduleTemplates = mw.templates.get( moduleName );
134 if ( !moduleTemplates || moduleTemplates[ templateName ] === undefined ) {
135 throw new Error( 'Template ' + templateName + ' not found in module ' + moduleName );
138 // Compiled and add to cache
139 return this.add( moduleName, templateName, moduleTemplates[ templateName ] );
143 * Compile a string of template markup with an engine of choice.
145 * @param {string} templateBody Template body
146 * @param {string} compilerName The name of a registered compiler.
147 * @return {TemplateRenderer} Compiled template
148 * @throws {Error} when unknown compiler name provided.
150 compile: function ( templateBody, compilerName ) {
151 return this.getCompiler( compilerName ).compile( templateBody );
155 // Register basic html compiler
156 mw.template.registerCompiler( 'html', {
157 compile: function ( src ) {
159 render: function () {
160 return $( $.parseHTML( src.trim() ) );