1 | var fs = require('fs'),
|
2 | path = require('path');
|
3 |
|
4 | function Controller() {}
|
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 | Controller.prototype.render = function render(view, params, callback) {
|
39 | var start = Date.now();
|
40 | var self = this;
|
41 | var compound = self.compound;
|
42 | var app = compound.app;
|
43 | var structure = compound.structure;
|
44 | var views = structure.views;
|
45 | var inAction = this.context.inAction;
|
46 |
|
47 | Array.prototype.forEach.call(arguments, function (arg) {
|
48 | switch (typeof arg) {
|
49 | case 'object': return params = arg;
|
50 | case 'function': return callback = arg;
|
51 | case 'string': return view = arg;
|
52 | }
|
53 | });
|
54 |
|
55 | if (typeof view !== 'string') view = self.actionName;
|
56 | if (typeof params !== 'object') params = {};
|
57 |
|
58 | params = safeMerge({}, params);
|
59 |
|
60 | params.request = self.context.req;
|
61 | params.params = self.params;
|
62 |
|
63 | var vc = self.prepareViewContext(params);
|
64 |
|
65 | ensureFlash(this.req);
|
66 |
|
67 | var layout = getLayoutName();
|
68 | var file = getViewFilename();
|
69 |
|
70 | layout = layout ? 'layouts/' + layout : false;
|
71 |
|
72 | compound.emit('render', vc, self, layout, file);
|
73 |
|
74 | layout = calcView(compound, layout, params);
|
75 | file = calcView(compound, file, params);
|
76 |
|
77 | if (!layout) {
|
78 | return self.renderView(file);
|
79 | }
|
80 |
|
81 | self.renderView(file, function(err, html) {
|
82 | if (err) {
|
83 | return self.next(err);
|
84 | }
|
85 | self.viewContext.body = html;
|
86 | self.renderView(layout);
|
87 | if (self.logger) {
|
88 | self.logger.emit('render', file, layout, Date.now() - start);
|
89 | }
|
90 |
|
91 | });
|
92 |
|
93 | function getLayoutName() {
|
94 | if ('layout' in vc) {
|
95 | return vc.layout ? vc.layout + '_layout' : false;
|
96 | }
|
97 | return self.layout();
|
98 | }
|
99 |
|
100 | function getViewFilename() {
|
101 | return path.join(self.controllerName, view).replace(/\\/g, "/");
|
102 | }
|
103 |
|
104 | |
105 |
|
106 |
|
107 | function calcView(compound, view, params) {
|
108 | var calcParams = {
|
109 | view: view,
|
110 | params: params
|
111 | };
|
112 |
|
113 | compound.emit('calcview', calcParams);
|
114 |
|
115 | return calcParams.result || view;
|
116 | }
|
117 |
|
118 | };
|
119 |
|
120 | Controller.prototype.prepareViewContext = function prepareViewContext(params) {
|
121 |
|
122 | var self = this;
|
123 | var helpers = this.compound.structure.helpers;
|
124 | this.viewContext = safeMerge(
|
125 | params || {}, this.locals,
|
126 | new Pers(helpers[this.controllerName + '_helper']),
|
127 | new Pers(helpers.application_helper),
|
128 | this.helpers()
|
129 | );
|
130 |
|
131 | return this.viewContext;
|
132 |
|
133 | function Pers(helper) {
|
134 | if (!helper) return;
|
135 |
|
136 | for (var method in helper) {
|
137 | if ('function' === typeof helper[method]) {
|
138 | this[method] = Function.prototype.bind.call(helper[method], self);
|
139 | }
|
140 | }
|
141 | }
|
142 |
|
143 | };
|
144 |
|
145 | Controller.prototype.renderView = function renderView(view, callback) {
|
146 | var filename = this.compound.structure.views[view];
|
147 | if (!filename) {
|
148 | var err = new Error('Template ' + view + ' not found');
|
149 | if (callback) {
|
150 | return callback(err);
|
151 | } else {
|
152 | throw err;
|
153 | }
|
154 | }
|
155 | if (callback) {
|
156 | this.res.render(filename, this.viewContext, callback);
|
157 | } else {
|
158 | this.res.render(filename, this.viewContext);
|
159 | if (this.context.inAction) {
|
160 | this.next();
|
161 | }
|
162 | }
|
163 | };
|
164 |
|
165 | Controller.prototype.helpers = function () {
|
166 | if (!this._helpers) {
|
167 | this._helpers = this.compound.helpers.personalize(this);
|
168 | }
|
169 | return this._helpers;
|
170 | };
|
171 |
|
172 | Controller.prototype.contentFor = function (name, content) {
|
173 | return this.helpers().contentFor(name, content);
|
174 | };
|
175 |
|
176 | Controller.prototype.sendError = function (err) {
|
177 | this.res.send({
|
178 | code: 500,
|
179 | error: err
|
180 | });
|
181 | };
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 | Controller.prototype.format = function format(handlers) {
|
202 | var requestedFormat = this.req.param('format');
|
203 | if (requestedFormat in handlers) {
|
204 | return handlers[requestedFormat].call(this.locals);
|
205 | }
|
206 | var defaultFormat = this.req.app.get('default format') || 'html';
|
207 | if (defaultFormat in handlers) {
|
208 | return handlers[defaultFormat].call(this.locals);
|
209 | }
|
210 | };
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 | Controller.prototype.safe = function safe(callback) {
|
240 | var c = this;
|
241 | return function safeCallback(err) {
|
242 | if (err) {
|
243 | return c.next(err);
|
244 | }
|
245 | callback.apply(c.locals, Array.prototype.slice.call(arguments, 1));
|
246 | };
|
247 | };
|
248 |
|
249 | function ensureFlash(req) {
|
250 | if (req.flash) {
|
251 | return;
|
252 | }
|
253 | req.flash = function _flash(type, msg) {
|
254 | if (this.session === undefined) {
|
255 | return [];
|
256 | }
|
257 | var msgs = this.session.flash = this.session.flash || {};
|
258 | if (type && msg) {
|
259 |
|
260 |
|
261 |
|
262 |
|
263 |
|
264 | return (msgs[type] = msgs[type] || []).push(msg);
|
265 | } else if (type) {
|
266 | var arr = msgs[type];
|
267 | delete msgs[type];
|
268 | return arr || [];
|
269 | } else {
|
270 | this.session.flash = {};
|
271 | return msgs;
|
272 | }
|
273 | };
|
274 | }
|
275 |
|
276 |
|
277 |
|
278 |
|
279 |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 |
|
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 |
|
296 |
|
297 |
|
298 |
|
299 | Controller.prototype.layout = function layout(l) {
|
300 | var compound = this.compound;
|
301 | var viewOpts = compound.app.set('view options') || {};
|
302 | if (viewOpts.layout === false) return false;
|
303 |
|
304 | if (typeof l !== 'undefined') {
|
305 | this.constructor.layout = l;
|
306 | }
|
307 | if (typeof this.constructor.layout === 'undefined') {
|
308 | var layoutName = 'layouts/' + this.controllerName + '_layout';
|
309 | this.constructor.layout = layoutName in compound.structure.views ?
|
310 | this.controllerName : 'application';
|
311 | }
|
312 | return this.constructor.layout ? this.constructor.layout + '_layout' : null;
|
313 | };
|
314 |
|
315 |
|
316 |
|
317 |
|
318 |
|
319 |
|
320 | Controller.prototype.load = function(controllerName) {
|
321 | var fullName = controllerName + '_controller';
|
322 | var source = this.compound.structure.controllers[fullName];
|
323 | this.build(source);
|
324 | };
|
325 |
|
326 |
|
327 |
|
328 |
|
329 |
|
330 |
|
331 | Controller.prototype.t = function() {
|
332 | if (!this._t) {
|
333 | this._t = this.compound.T();
|
334 | this._t.locale = this.app.settings.defaultLocale || 'en';
|
335 | this._T = this.compound.T;
|
336 | }
|
337 | return this._t.apply(this, [].slice.call(arguments));
|
338 |
|
339 | };
|
340 |
|
341 |
|
342 |
|
343 |
|
344 |
|
345 |
|
346 |
|
347 |
|
348 | Controller.prototype.setLocale = function (locale) {
|
349 | if (!this._t) {
|
350 | this._t = this.compound.T();
|
351 | this._t.locale = locale;
|
352 | this._T = this.compound.T;
|
353 | } else {
|
354 | this._t.locale = locale;
|
355 | }
|
356 | };
|
357 |
|
358 |
|
359 |
|
360 |
|
361 | module.exports = Controller.prototype;
|
362 |
|
363 | function safeMerge(mergeWhat) {
|
364 | mergeWhat = mergeWhat || {};
|
365 | Array.prototype.forEach.call(arguments, function(mergeWith, i) {
|
366 | if (i === 0) {
|
367 | return;
|
368 | }
|
369 | for (var key in mergeWith) {
|
370 | if (key in mergeWhat) continue;
|
371 | mergeWhat[key] = mergeWith[key];
|
372 | }
|
373 | });
|
374 | return mergeWhat;
|
375 | }
|