This repository has been archived by the owner on Jan 25, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
common.js
157 lines (133 loc) · 5.49 KB
/
common.js
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
"use strict";
var usecontent = require('dust-usecontent-helper');
var message = require('dust-message-helper');
var iferr = require('iferr');
module.exports = function(dust, debug, options, loader) {
options = options || {};
debug("registering");
// Default to true, but since it imposes some complexity and lack of clarity,
// about where things come from in the templates, allow it to be disabled.
var autoloadTemplateContent = options.autoloadTemplateContent == null || options.autoloadTemplateContent;
debug("will autoload template content? %j", autoloadTemplateContent);
usecontent.withLoader(loader).registerWith(dust);
// The message helper is the main user surface from the template side.
message.registerWith(dust, { enableMetadata: options.enableMetadata });
// Here's where the dirty bit of auto-wrapping templates with the content
// load is triggered.
if (autoloadTemplateContent) {
wrapOnLoad(dust, loader, debug);
}
};
function hackGibson(ctx, content, bundle) {
var oldShiftBlocks = ctx.shiftBlocks;
var oldPush = ctx.push;
// Alter the context to wrap each block shifted, so content will be
// present even in blocks rendered from other templates like layouts.
ctx.shiftBlocks = function(locals) {
return oldShiftBlocks.call(this, objMap(locals, function (l) {
return wrapBlock(l, content, bundle);
}));
};
// Alter the context to apply this same alteration to each context
// pushed below this one, maintaining this hack for all future
// context pushes.
ctx.push = function(/* head, idx, len */) {
var newCtx = oldPush.apply(this, arguments);
hackGibson(newCtx, content, bundle);
return newCtx;
};
}
function wrapBlock(block, content, bundle) {
// Return a block that re-pushes the content, and then passes to
// the original block. This makes sure the content is associated
// with the auto-loaded content bundle, not coming from the calling
// context, which could be a different template and have the wrong
// content loaded.
return function (chunk, ctx) {
ctx = ctx.push({intl: { messages: content, bundle: bundle }});
return block(chunk, ctx);
};
}
function objMap(obj, fn) {
var n = {};
Object.keys(obj).forEach(function (e) {
n[e] = fn(obj[e]);
});
return n;
}
// This is where the magic lies. To get a hook on templates and wrap them with
// javascript that is aware of the template's name
function wrapOnLoad(dust, loader, debug) {
var oldOnLoad = dust.onLoad;
if (!oldOnLoad) {
throw new Error("dust.onLoad must be configured to use automatic content loading");
}
debug("wrapping onLoad function to support content autoloading");
dust.onLoad = function(name, options, cb) {
var ourLoader = iferr(cb, function (srcOrTemplate) {
debug("got template %s", srcOrTemplate);
var tmpl = getTemplate(srcOrTemplate);
if (!tmpl) {
debug("Compiling template '%s'", name);
tmpl = dust.loadSource(dust.compile(srcOrTemplate, name));
}
if (tmpl.loadsDefaultContent) {
newTmpl = tmpl;
} else {
debug("wrapping template '%s' to look up default content", tmpl.templateName);
var newTmpl = function (chunk, ctx) {
return chunk.map(function (chunk) {
var bundle = tmpl.templateName + '.properties';
loader(ctx, bundle, function (err, content) {
if (err) {
chunk.setError(err);
} else {
hackGibson(ctx, content, bundle);
dust.helpers.useContent(chunk, ctx, { block: tmpl }, { bundle: bundle }).end();
}
});
});
};
newTmpl.templateName = tmpl.templateName;
newTmpl.loadsDefaultContent = true;
newTmpl.__dustBody = true;
}
if (dust.config.cache) {
// This actually replaces the template registered by
// compiling and loading above.
dust.cache[tmpl.templateName] = newTmpl;
}
cb(null, newTmpl);
});
debug("calling old onLoad to get template '%s'", name);
if (oldOnLoad.length === 2) {
return oldOnLoad.call(this, name, ourLoader);
} else {
return oldOnLoad.call(this, name, options, ourLoader);
}
};
/**
* Extracts a template function (body_0) from whatever is passed.
*
* This is an extract of the same function from the dustjs source.
*
* nameOrTemplate Could be:
* - the name of a template to load from cache
* - a CommonJS-compiled template (a function with a `template` property)
* - a template function
* returns a template function, if found
*/
function getTemplate(nameOrTemplate) {
if(!nameOrTemplate) {
return null;
}
if(typeof nameOrTemplate === 'function' && nameOrTemplate.template) {
// Sugar away CommonJS module templates
return nameOrTemplate.template;
}
if(dust.isTemplateFn(nameOrTemplate)) {
// Template functions passed directly
return nameOrTemplate;
}
}
}