Localisation updates from https://translatewiki.net.
[mediawiki.git] / resources / src / mediawiki.template.js
blob5204013a6080ad5290e0fa1f42f0bc5b7a7685d8
1 /**
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.
5  *
6  * @example
7  * // returns $( '<div>hello world</div>' );
8  * const $node = mw.template.compile( '<div>hello world</div>', 'html' ).render();
9  *
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( {
13  *     text: 'Hello world'
14  *   }, {
15  *     Foo: mw.template.compile( '{{text}}', 'mustache' )
16  *   } );
17  * } );
18  * @namespace mw.template
19  */
21 /**
22  * Compiles a template for rendering.
23  *
24  * @typedef {Function} mw.template~TemplateCompileFunction
25  * @param {string} src source of the template
26  * @return {TemplateRenderer} for rendering
27  */
29 /**
30  * Renders the template to create a jQuery object.
31  *
32  * @typedef {Function} mw.template~TemplateRenderFunction
33  * @param {Object} [data] for the template
34  * @param {Object} [partials] additional partial templates
35  * @return {jQuery}
36  */
38 /**
39  * @typedef {Object} mw.template~TemplateRenderer
40  * @property {TemplateRenderFunction} render
41  */
43 /**
44  * @typedef {Object} mw.template~TemplateCompiler
45  * @property {TemplateCompileFunction} compile
46  */
47 ( function () {
48         const compiledTemplates = {},
49                 compilers = {};
51         mw.template = {
52                 /**
53                  * Register a new compiler.
54                  *
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.
57                  *
58                  * The compiler name must correspond with the name suffix of templates that use this compiler.
59                  *
60                  * @param {string} name Compiler name
61                  * @param {TemplateCompiler} compiler
62                  */
63                 registerCompiler: function ( name, compiler ) {
64                         if ( !compiler.compile ) {
65                                 throw new Error( 'Compiler must implement a compile method' );
66                         }
67                         compilers[ name ] = compiler;
68                 },
70                 /**
71                  * Get the name of the associated compiler based on a template name.
72                  *
73                  * @param {string} templateName Name of a template (including suffix)
74                  * @return {string} Name of a compiler
75                  */
76                 getCompilerName: function ( templateName ) {
77                         const nameParts = templateName.split( '.' );
78                         if ( nameParts.length < 2 ) {
79                                 throw new Error( 'Template name must have a suffix' );
80                         }
81                         return nameParts[ nameParts.length - 1 ];
82                 },
84                 /**
85                  * Get a compiler via its name.
86                  *
87                  * @param {string} name Name of a compiler
88                  * @return {TemplateCompiler} The compiler
89                  * @throws {Error} when unknown compiler provided
90                  */
91                 getCompiler: function ( name ) {
92                         const compiler = compilers[ name ];
93                         if ( !compiler ) {
94                                 throw new Error( 'Unknown compiler ' + name );
95                         }
96                         return compiler;
97                 },
99                 /**
100                  * Register a template associated with a module.
101                  *
102                  * Precompiles the newly added template based on the suffix in its name.
103                  *
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
108                  */
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 ] = {};
114                         }
115                         compiledTemplates[ moduleName ][ templateName ] = compiled;
117                         return compiled;
118                 },
120                 /**
121                  * Get a compiled template by module and template name.
122                  *
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
126                  */
127                 get: function ( moduleName, templateName ) {
128                         // Try cache first
129                         if ( compiledTemplates[ moduleName ] && compiledTemplates[ moduleName ][ templateName ] ) {
130                                 return compiledTemplates[ moduleName ][ templateName ];
131                         }
133                         const moduleTemplates = mw.templates.get( moduleName );
134                         if ( !moduleTemplates || moduleTemplates[ templateName ] === undefined ) {
135                                 throw new Error( 'Template ' + templateName + ' not found in module ' + moduleName );
136                         }
138                         // Compiled and add to cache
139                         return this.add( moduleName, templateName, moduleTemplates[ templateName ] );
140                 },
142                 /**
143                  * Compile a string of template markup with an engine of choice.
144                  *
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.
149                  */
150                 compile: function ( templateBody, compilerName ) {
151                         return this.getCompiler( compilerName ).compile( templateBody );
152                 }
153         };
155         // Register basic html compiler
156         mw.template.registerCompiler( 'html', {
157                 compile: function ( src ) {
158                         return {
159                                 render: function () {
160                                         return $( $.parseHTML( src.trim() ) );
161                                 }
162                         };
163                 }
164         } );
166 }() );