dotnode
Version:
.NET-like MVC framework for Node.js
244 lines (170 loc) • 6.57 kB
JavaScript
var BaseController = require('../controllers/controller'),
Injector = require('../ioc/injector'),
ActionResult = require('../models/actionResult'),
resultTypes = require('../models/actionResultType'),
ViewEngine = require('../views/viewEngine'),
UrlHelper = require('../routes/urlHelper'),
IDeferred = require('../models/iDeferred'),
extend = require('xtend');
var ControllerFactory = function (appContext) {
this._controllers = {};
this._appContext = appContext;
this._viewEngine = new ViewEngine();
this._injector = new Injector();
};
// #region private methods
ControllerFactory.prototype._handleResultSync = function (result, contextOptions) {
if (result instanceof ActionResult) {
this._handleActionResult(result, contextOptions);
}
return result;
};
ControllerFactory.prototype._handleResultAsync = function (result, contextOptions) {
var invokeOptions = {
request: contextOptions.request,
response: contextOptions.response
};
result.invoke(invokeOptions);
return result;
};
ControllerFactory.prototype._handleActionResult = function (result, options) {
switch (result.type) {
case resultTypes.viewResult:
{
this._handleViewResult(result, options);
break;
}
case resultTypes.jsonResult:
{
this._handleJsonResult(result, options);
break;
}
default:
{
break;
}
}
};
ControllerFactory.prototype._handleViewResult = function (result, options) {
var viewData = result.data;
var renderingOptions = extend(options, {
viewName: viewData.viewName,
model: viewData.model,
viewOptions: viewData.viewOptions,
controllerContext: options.controllerContext
});
this._viewEngine.render(renderingOptions);
};
ControllerFactory.prototype._handleJsonResult = function (result, options) {
var jsonData = result.data,
json = jsonData.object,
response = options.response;
response.writeHead(200, { 'Content-Type': 'application/json' });
response.end(JSON.stringify(json));
};
// #endregion
ControllerFactory.prototype.registerController = function (controllerName, Controller) {
if (typeof this._controllers[controllerName] == 'function') {
throw 'Controller with name ' + controllerName + ' already registered';
}
this._controllers[controllerName] = Controller;
};
ControllerFactory.prototype.registerControllers = function (controllers) {
for (var name in controllers) {
if (controllers.hasOwnProperty(name)) {
this.registerController(name, controllers[name]);
}
}
};
ControllerFactory.prototype.controllerIsRegistered = function (controllerName) {
return typeof this._controllers[controllerName] == 'function';
};
ControllerFactory.prototype.invoke = function (options) {
var actionName = options.actionName,
controllerName = options.controllerName,
areaName = options.areaName,
params = options.params,
request = options.request,
response = options.response;
var Controller = this._controllers[controllerName];
Controller.prototype = extend({}, BaseController.prototype, Controller.prototype);
var controllerInstance = new Controller();
controllerInstance.request = request;
controllerInstance.response = response;
var controllerContext = {
actionName: actionName,
controllerName: controllerName,
areaName: areaName,
request: request,
response: response,
viewBag: controllerInstance.viewBag
};
controllerInstance.url = new UrlHelper(this._appContext, controllerContext);
controllerContext.url = controllerInstance.url;
controllerInstance.controllerContext = controllerContext;
var action = Controller.prototype[actionName];
if (typeof action != 'function') {
throw 'Requested action is not a function';
}
var result = this._injector.invoke(action, controllerInstance, params);
if(typeof result == 'undefined'){
return;
}
controllerContext.viewBag = controllerInstance.viewBag;
controllerContext.pageOptions = controllerInstance.pageOptions;
var contextOptions = {
request: request,
response: response,
actionName: actionName,
controllerName: controllerName,
areaName: areaName,
controllerContext: controllerContext,
controllerInstance: controllerInstance
};
if (result instanceof IDeferred) {
return this._handleResultAsync(result, contextOptions);
} else {
return this._handleResultSync(result, contextOptions);
}
};
ControllerFactory.prototype.getVerbs = function (actionName, controllerName) {
var allVerbs = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'HEAD', 'TRACE', 'CONNECT'];
var Controller = this._controllers[controllerName];
if (typeof Controller != 'function') {
throw 'Controller ' + controllerName + ' is not registered';
}
var config = Controller.config;
if (typeof config == 'undefined') {
return allVerbs;
}
if (typeof config.attributes == 'undefined') {
return allVerbs;
}
var attributes = config.attributes[actionName];
if (!attributes) {
return allVerbs;
}
var specifiedVerbs = [],
ignoredVerbs = [];
for (var name in attributes) {
var invariantName = name.replace(/w+/g, '').toUpperCase();
if (attributes.hasOwnProperty(name) && (allVerbs.indexOf(invariantName) != -1)) {
if (attributes[name]) {
specifiedVerbs.push(invariantName);
} else {
ignoredVerbs.push(invariantName);
}
}
}
if (specifiedVerbs.length == 0 && ignoredVerbs.length == 0) {
return allVerbs;
}
var acceptedVerbs = [];
for (var i in specifiedVerbs) {
if (ignoredVerbs.indexOf(specifiedVerbs[i]) != -1) {
acceptedVerbs.push(specifiedVerbs[i]);
}
}
return specifiedVerbs;
};
module.exports = ControllerFactory;