/** * An extensible library for rendering templates in different template languages. * By default only the `html` template library is provided. * The Mustache library is also provided in mediawiki core via the mediawiki.template.mustache library. * * @example * // returns $( '
hello world
' ); * const $node = mw.template.compile( '
hello world
', 'html' ).render(); * * // also returns $( '
hello world
' ); * mw.loader.using( 'mediawiki.template.mustache' ).then( () => { * const $node = mw.template.compile( '
{{ >Foo }}
', 'mustache' ).render( { * text: 'Hello world' * }, { * Foo: mw.template.compile( '{{text}}', 'mustache' ) * } ); * } ); * @namespace mw.template */ /** * Compiles a template for rendering. * * @typedef {Function} mw.template~TemplateCompileFunction * @param {string} src source of the template * @return {TemplateRenderer} for rendering */ /** * Renders the template to create a jQuery object. * * @typedef {Function} mw.template~TemplateRenderFunction * @param {Object} [data] for the template * @param {Object} [partials] additional partial templates * @return {jQuery} */ /** * @typedef {Object} mw.template~TemplateRenderer * @property {TemplateRenderFunction} render */ /** * @typedef {Object} mw.template~TemplateCompiler * @property {TemplateCompileFunction} compile */ ( function () { const compiledTemplates = {}, compilers = {}; mw.template = { /** * Register a new compiler. * * A compiler is any object that implements a {@link mw.template.compile} method. The compile() method must * return a Template interface with a method render() that returns HTML. * * The compiler name must correspond with the name suffix of templates that use this compiler. * * @param {string} name Compiler name * @param {TemplateCompiler} compiler */ registerCompiler: function ( name, compiler ) { if ( !compiler.compile ) { throw new Error( 'Compiler must implement a compile method' ); } compilers[ name ] = compiler; }, /** * Get the name of the associated compiler based on a template name. * * @param {string} templateName Name of a template (including suffix) * @return {string} Name of a compiler */ getCompilerName: function ( templateName ) { const nameParts = templateName.split( '.' ); if ( nameParts.length < 2 ) { throw new Error( 'Template name must have a suffix' ); } return nameParts[ nameParts.length - 1 ]; }, /** * Get a compiler via its name. * * @param {string} name Name of a compiler * @return {TemplateCompiler} The compiler * @throws {Error} when unknown compiler provided */ getCompiler: function ( name ) { const compiler = compilers[ name ]; if ( !compiler ) { throw new Error( 'Unknown compiler ' + name ); } return compiler; }, /** * Register a template associated with a module. * * Precompiles the newly added template based on the suffix in its name. * * @param {string} moduleName Name of the ResourceLoader module the template is associated with * @param {string} templateName Name of the template (including suffix) * @param {string} templateBody Contents of the template (e.g. html markup) * @return {TemplateRenderer} Compiled template */ add: function ( moduleName, templateName, templateBody ) { // Precompile and add to cache const compiled = this.compile( templateBody, this.getCompilerName( templateName ) ); if ( !compiledTemplates[ moduleName ] ) { compiledTemplates[ moduleName ] = {}; } compiledTemplates[ moduleName ][ templateName ] = compiled; return compiled; }, /** * Get a compiled 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 {TemplateRenderer} Compiled template */ get: function ( moduleName, templateName ) { // Try cache first if ( compiledTemplates[ moduleName ] && compiledTemplates[ moduleName ][ templateName ] ) { return compiledTemplates[ moduleName ][ templateName ]; } const moduleTemplates = mw.templates.get( moduleName ); if ( !moduleTemplates || moduleTemplates[ templateName ] === undefined ) { throw new Error( 'Template ' + templateName + ' not found in module ' + moduleName ); } // Compiled and add to cache return this.add( moduleName, templateName, moduleTemplates[ templateName ] ); }, /** * Compile a string of template markup with an engine of choice. * * @param {string} templateBody Template body * @param {string} compilerName The name of a registered compiler. * @return {TemplateRenderer} Compiled template * @throws {Error} when unknown compiler name provided. */ 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( src.trim() ) ); } }; } } ); }() );