express-mesh
Version:
A Gentics Mesh frontend for Express.
239 lines (238 loc) • 10 kB
JavaScript
;
var Q = require('q');
var meshClient = require('./meshRestClient');
var path = require('path');
var u = require('./meshUtil');
var handler = require('./meshHandlerStore');
var lang = require('./meshLanguages');
var querystring = require('querystring');
/**
* Render information that will be passed to the rendered template in the RenderData.
*/
var RenderInformation = (function () {
/**
* Constructor that initializes the render information.
* @param req The MeshRequest.
* @param node The MeshNode that should be rendered.
*/
function RenderInformation(req, node) {
var _this = this;
this.languageURLs = {};
this.activeLanguage = lang.getActiveLanguage(req);
if (u.isDefined(node)) {
this.availableLanguages = node.availableLanguages;
this.availableLanguages.forEach(function (lang) {
_this.languageURLs[lang] = node.languagePaths[lang];
});
}
else {
this.availableLanguages = req.meshConfig.languages;
this.availableLanguages.forEach(function (lang) {
var params = JSON.parse(JSON.stringify(req.query));
params.lang = lang;
_this.languageURLs[lang] = '?' + querystring.stringify(params);
});
}
this.username = req.session[meshClient.MeshAuth.MESH_USER_SESSION_KEY] ?
req.session[meshClient.MeshAuth.MESH_USER_SESSION_KEY] : req.meshConfig.publicUser.username;
this.loggedin = this.username !== req.meshConfig.publicUser.username;
}
return RenderInformation;
})();
exports.RenderInformation = RenderInformation;
/**
* Render data that is passed to the rendered template and contains the data that should be rendered.
*/
var RenderData = (function () {
function RenderData() {
this.meta = {};
}
return RenderData;
})();
exports.RenderData = RenderData;
/**
* The MeshRenderer is responsible for rendering templates.
*/
var MeshRenderer = (function () {
/**
* Initialize the renderer.
* @param app Express app.
* @param viewDir Directory that contains the templates.
*/
function MeshRenderer(app, viewDir) {
this.app = app;
this.viewDir = viewDir;
this.schemaHandlerStore = new handler.SchemaHandlerStore();
this.errorHandlerStore = new handler.ErrorHandlerStore();
this.viewHandlerStore = new handler.ViewHandlerStore();
}
MeshRenderer.prototype.registerSchemaHandler = function (schema, handler) {
this.schemaHandlerStore.registerSchemaHandler(schema, handler);
};
MeshRenderer.prototype.registerErrorHandler = function (status, handler) {
this.errorHandlerStore.registerErrorHandler(status, handler);
};
MeshRenderer.prototype.registerViewRenderHandler = function (handler) {
this.viewHandlerStore.registerViewHandler(handler);
};
MeshRenderer.prototype.renderMeshNode = function (node, req, res) {
var _this = this;
var schema = u.isDefined(node) && u.isDefined(node.schema) ? node.schema : {}, key = u.isDefined(schema.name) ? schema.name : schema.uuid;
if (u.isDefined(key)) {
this.handleMicroNodeFields(node, req, res).then(function (node) {
return _this.schemaHandlerStore.workSchemaHandlers(key, node, req, res);
})
.then(function (node) {
var renderData = _this.getRenderData(node, req);
_this.viewExists(key).then(function () {
_this.renderView(key, renderData, req, res);
}).catch(function () {
console.warn('Template for schema {' + key + '} not found, using default: ' + req.meshConfig.defaultView);
_this.renderView(req.meshConfig.defaultView, renderData, req, res);
});
}).catch(function (err) {
console.error('Error in schema handlers');
_this.renderError(u.STATUS_ERROR, req, res, err);
});
}
else {
this.renderError(u.STATUS_ERROR, req, res, { message: 'No schema found' });
}
};
MeshRenderer.prototype.renderError = function (status, req, res, err) {
var _this = this;
this.errorHandlerStore.workErrorHandler(status, err, req, res).catch(function () {
var viewname = '' + status, renderdata = new RenderData();
res.status(status);
console.error(status, err, err.stack);
renderdata.meta.error = err;
_this.viewExists(viewname).then(function () {
_this.renderView(viewname, renderdata, req, res);
}).catch(function () {
_this.renderView(req.meshConfig.defaultErrorView, renderdata, req, res);
});
});
};
MeshRenderer.prototype.viewExists = function (name) {
var filename = name + MeshRenderer.TEMPLATE_EXTENSION;
return u.fileExists(path.join(this.viewDir, filename));
};
MeshRenderer.prototype.renderView = function (name, data, req, res) {
this.viewHandlerStore.workViewHandlers(data, req, res).then(function (renderdata) {
if (req.meshConfig.logging.renderdata) {
console.log(JSON.stringify(renderdata, null, 4));
}
res.render(name, renderdata);
}).catch(function (err) {
console.error('ERROR IN VIEWHANDLER', err, err.stack);
if (req.meshConfig.logging.renderdata) {
console.log(JSON.stringify(data, null, 4));
}
data.meta.error = true;
res.render(name, data);
});
};
MeshRenderer.prototype.handleMicroNodeFields = function (node, req, res) {
var _this = this;
var deferred = Q.defer(), promises = [];
if (u.isDefined(node) && u.isDefined(node.fields)) {
Object.keys(node.fields).forEach(function (key) {
var field = node.fields[key];
promises.push(_this.resolveField(field, req, res).then(function (resolved) {
node.fields[key] = resolved;
}));
});
Q.all(promises).then(function () {
deferred.resolve(node);
});
}
else {
deferred.resolve(node);
}
return deferred.promise;
};
MeshRenderer.prototype.resolveField = function (field, req, res) {
var _this = this;
var listpromises = [];
if (u.isDefined(field) && Array.isArray(field)) {
field.forEach(function (listitem) {
// check if there is a schema, if not we just add the node itself
if (u.isDefined(listitem.schema) || u.isDefined(listitem.microschema)) {
listpromises.push(_this.meshNodeToString(listitem, req, res));
}
else {
listpromises.push(Q.fcall(function () {
return listitem;
}));
}
});
return Q.all(listpromises);
}
else if (u.isDefined(field) && (u.isDefined(field.schema) || u.isDefined(field.microschema))) {
return this.meshNodeToString(field, req, res);
}
else {
return Q.fcall(function () {
return field;
});
}
};
MeshRenderer.prototype.meshNodeToString = function (node, req, res) {
var _this = this;
var deferred = Q.defer(), key = u.isDefined(node) ? this.getSchemaKey(node) : undefined;
if (u.isDefined(key)) {
this.schemaHandlerStore.workSchemaHandlers(key, node, req, res).then(function (node) {
_this.viewExists(key).then(function () {
_this.renderTemplate(key, node).then(function (html) {
deferred.resolve(html);
}).catch(function (err) {
console.error('Error while rendering template for {' + key + '}. Using blank.', err);
deferred.resolve('');
});
}).catch(function () {
console.warn('Template for schema {' + key + '} not found. Using blank.');
deferred.resolve('');
});
}).catch(function (err) {
console.error('Error in schema handlers', err);
deferred.reject('');
});
}
else {
console.error('Schema for node not found', JSON.stringify(node, null, 4));
deferred.reject('');
}
return deferred.promise;
};
MeshRenderer.prototype.getSchemaKey = function (node) {
var schemaObj = u.isDefined(node.schema) ? node.schema : node.microschema, key = u.isDefined(schemaObj) ? (u.isDefined(schemaObj.name) ? schemaObj.name : schemaObj.uuid) : undefined;
return key;
};
MeshRenderer.prototype.renderTemplate = function (name, data) {
var deferred = Q.defer();
if (!u.isDefined(this.app)) {
deferred.reject("App not defined. Call setApp with the Express app.");
}
else {
this.app.render(name, data, function (err, html) {
if (u.isDefined(err)) {
deferred.reject(err);
}
else {
deferred.resolve(html);
}
});
}
return deferred.promise;
};
MeshRenderer.prototype.getRenderData = function (node, req) {
var data = new RenderData();
lang.setActiveLanguage(req, node.language);
data.node = node;
data.renderInformation = new RenderInformation(req, node);
return data;
};
MeshRenderer.TEMPLATE_EXTENSION = '.html';
return MeshRenderer;
})();
exports.MeshRenderer = MeshRenderer;