1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
/**
* 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 $( '<div>hello world</div>' );
* const $node = mw.template.compile( '<div>hello world</div>', 'html' ).render();
*
* // also returns $( '<div>hello world</div>' );
* mw.loader.using( 'mediawiki.template.mustache' ).then( () => {
* const $node = mw.template.compile( '<div>{{ >Foo }}</div>', '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() ) );
}
};
}
} );
}() );
|