Skip to content

Instantly share code, notes, and snippets.

@AMSTKO
Forked from adrienj/(controller)default.js
Created July 13, 2011 20:58
Show Gist options
  • Save AMSTKO/1081314 to your computer and use it in GitHub Desktop.
Save AMSTKO/1081314 to your computer and use it in GitHub Desktop.
ToyFW.js
/*
* default
*/
module.exports = function (req, res, met, send) {
var sgl = this;
this.cfg.cache_controller = false;
switch (req.fct) {
case 'index':
var users = this.mvc.model('users');
if(req.post && req.body.inscription) {
users.signup(req.body, function (status) {
switch (status) {
case 1:
txt = 'error..';
break;
case 2:
txt = 'Login invalide !';
break;
case 3:
txt = 'Passwd invalide !';
break;
case 4:
txt = 'Inscription ok :)';
break;
case 5:
txt = 'Login déjà utilisé';
break;
}
send(sgl.mvc.template('index', {'status':txt}));
});
}
else if (req.post && req.body.connection) {
send(sgl.mvc.template('index', {'status':'.. on assiste la a une connexion...'}));
}
else {
users.list(function (arr) {
var txt = '';
for(x in arr) {
txt = arr[x].login + '. ' + txt;
}
send(sgl.mvc.template('index', {'status':txt}));
});
}
break;
default:
send(404);
}
};
/*
* fr
*/
module.exports = {
'welcome': 'Bienvenue {user} ! :)'
}
/*
* users model
*/
module.exports = function () {
var _ = require('underscore'),
sgl = this;
this.cfg.cache_model = false;
return {
signup : function (input, callback) {
// checl input
if(_.isUndefined(input.login) || _.isUndefined(input.passwd)) {
callback(1);
}
if (!input.login.match(/^[a-z0-9.]{3,20}$/i)) {
callback(2);
}
if (!input.passwd.match(/^.{5,}$/i)) {
callback(3);
}
sgl.mongodb.collection('users2', function(e,c) {
c.count({'login':input.login}, function(e,count) {
if(count===0) {
c.insert({'login':input.login});
callback(4);
}
else {
callback(5);
}
});
});
},
list : function (callback) {
sgl.mongodb.collection('users2', function(e,c) {
c.count(function(e,count) {
c.find(function(e,cursor) {
var arr = [];
cursor.each(function (e, item) {
item ? arr.push(item) : callback(arr);
});
});
});
});
}
};
};
<!DOCTYPE html>
<html>
<head>
<title>Site.com</title>
<meta charset="UTF-8" />
<link rel="stylesheet" href="/public/css/normalize.css" />
<link rel="stylesheet" href="/public/css/default.css" />
</head>
<body>
<div id="head" >
<div class="wrap_1000" >
<a href="http://site.com" >SITE</a>
</div>
</div>
<div id="content" >
<%=status%>
<h1>Inscription</h1>
<form action="/" method="post" >
login: <input type="text" name="login" /><br />
passwd: <input type="password" name="passwd" /><br >
<input type="submit" name="inscription" value="ok" />
</form>
<h1>Login</h1>
<form action="/" method="post" >
login: <input type="text" name="login" /><br />
passwd: <input type="password" name="passwd" /><br />
<input type="submit" name="connection" value="ok" />
</form>
</div>
</body>
</html>

ToyFW.js

ToyFW.js is a MVC framework for node.js that is currently in development. ToyFW uses Express to create servers and has a built-in dispatcher to route controllers. The model part is not yet implemented.

Features

  • Multidomain
  • Model View Controller (MVC)
  • Highly configurable
  • Internationalization

Getting Started

server.js :

require('./toyfw.js')({
	domains: {
		'*abcde.com': {
			srv : function (app, express, cfg) {
				app.use(app.router);
				app.use(express.logger());
				app.use(express.bodyParser());
				app.use(express.cookieParser());
				app.use(express.methodOverride());
				app.use(express.session({ secret: cfg.secret }));
			},

			cfg : {
				path:             '/srv/abcde.com',
				host:             'abcde.com',
				secret:           'lolcat',
				controller:       'default', // default controlleur
				cache_client:     'public, max-age=3600',
				cache_controller: false,
				lang:             'fr'
			}
		}
	},
	port: 80,
	ip: '127.0.0.1'
});

And then start the server :

$node server.js

As no configuration is passed, it listens on 127.0.0.1:80. And by default, the local directory is where should be controller/ and view/.

Usage

Folders

./
	toyfw.js
    server.js
	abcde.com/
		controller/
			default.js
			contact.js
			errors.js
		lang/
			en/
				name.lang.js
			fr/
				name.lang.js
		view/
			index.html
			contact.html
		public/
			img/
			css/
			js/

MVC

Controllers

A controller must be in the ./controller/ folder. If mysite.com/test is requested, then the controller test will be loaded. If it does not exist, then the default controller will be loaded.

If not redefined in the cfg section, controller/default.js is the default controller.

A controller must be defined like this :

controller/default.js :

module.exports = function () {
    return 'This text is generated from the controller';
};

A controller can hide himself by returning the number 404. Exemple :

controller/secure.js :

var isAllowed = function() { ... };
module.exports = function () {
    if(!isAllowed()) {
       return 404;
    } else {
       return 'Content of the secret page';
    }
};

Views

Views are in the ./view/ folder. this.mvc.template uses the underscore.js template engine.

Load a view with template :

controller/default.js :

module.exports = function () {
    return this.mvc.template('index', {message: 'Test Message!'});;
};

view/index.html :

<b>The message is :</b> <%=message%>

output :

The message is : Test Message!

Langs

Lang files are in the ./lang/ folder. Each lang is in its folder (like ./lang/en/). Usage :

controller/default.js :

module.exports = function () {
    this.mvc.langFile('mainwords');
    return this.mvc.template('index', {userName: 'admin'});;
};

view/index.html :

<h1><%=lang('welcome', { user: userName })%></h1>
<p><%=lang('connected', { count: Math.round(Math.random()*800) })%></p>

lang/en/mainwords.lang.js :

module.exports = {
    'welcome':      'Welcome {user}!',
    'connected':    '{count} users are online at this moment.'
};

output :

Welcome admin!

327 users are online at this moment.

ToyFW.js change log

1.7 - 21/08/2011

  • support des models;
  • plus asynchrone;
  • support mongodb;

1.6 - 20/08/2011

  • gestion des segments /default/index/ceci_est_un_segment et dans ton code tu peux le récupérer avec req.segments[0]. Par défaut les 4 premiers segments sont déclarés en tant que String vide.

  • Savoir si il y a des données envoyées en POST sur une requète: if(req.post) { console.log('Yes POST! login=' + req.body.login); }

  • Connaître la fct actuelle avec req.fct

  • Pour le moteur de templates tu as par défaut une variable status que tu peux mettre dans ton code <%=status%> et qui est une String vide. Et pour la remplir this.mvc.template('index', {status:'Message ok!'});

  • Un object sgl.share qui contient des choses que tu veux partager entre tous les utilisateurs (compteur de hits sur une page..)

/*
* ~/app$ node nsrv.js
*/
require('./toyfw.js')({
domains: {
'*abcde.com': {
srv : function (app, express, cfg) {
app.use(app.router);
app.use(express.logger());
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.methodOverride());
app.use(express.session({ secret: cfg.secret }));
},
cfg : {
path: '/srv/abcde.com',
host: 'abcde.com',
secret: 'lolcat',
controller: 'default', // default controlleur
cache_client: 'public, max-age=3600',
cache_controller: false,
lang: 'fr'
}
},
'*azerty.com': {
srv : function (app, express, cfg) {
app.use(app.router);
app.use(express.logger());
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.methodOverride());
app.use(express.session({ secret: cfg.secret }));
},
cfg : {
path: '/srv/azerty',
host: 'azerty.am',
secret: 'lolcat',
controller: 'default', // default controlleur
cache_client: 'public, max-age=3600',
cache_controller: false,
lang: 'fr'
}
}
},
port: 80,
ip: '127.0.0.1'
});
/*
* ToyFW
* release 1.7
*/
module.exports = (function () {
var fs = require('fs'),
path = require('path'),
mime = require('mime'),
express = require('express'),
_ = require('underscore'),
app = express.createServer();
this.server = function (sgl) {
// unique
var appre = express.createServer();
// config
sgl.cfg = _.extend({
path: './',
host: 'undefined',
secret: '123456789',
controller: 'default', // default controlleur
cache_client: 'public, max-age=3600',
cache_controller: true,
cache_model: true,
lang: 'fr',
ts: Math.round(+new Date/1000),
tsm: +new Date,
socket: false,
mongodb: false
}, sgl.cfg);
// object for general data shared
sgl.share = {};
// mvc
sgl.mvc = {
// view file
view: function (file) {
file = sgl.cfg.path + '/views/' + file + '.html';
return path.existsSync(file) ? fs.readFileSync(file, 'utf8') : '{view <em>' + file + '</em> not found}';
},
// routing management
routing: function (req, res, met) {
// req etat
req.fct = ''; // function
req.segments = ['','','',''];
req.post = !_.isUndefined(req.body);
req.is_send = false;
var requestUrl = req.url.replace(/\?.*$/gi, '').split('/'),
controller = requestUrl[1],
file = this.cfg.path + '/controllers/' + (controller === '' ? this.cfg.controller : controller) + '.js',
prev_cache_controller = this.cfg.cache_controller,
exists = path.existsSync(file);
if(!exists) {
file = this.cfg.path + '/controllers/' + this.cfg.controller + '.js';
}
// segment
for(var i=3; i<requestUrl.length; i++) {
req.segments[i-3] = requestUrl[i];
}
req.fct = exists ? ( requestUrl[2] || 'index' ) : controller;
var src = require(file).call(this, req, res, met, function (src) {
res.send(src === 404 ? '{page <em>' + req.url + '</em> not found}' : src);
});
// cache
if(!this.cfg.cache_controller) {
delete require.cache[file];
}
this.cfg.cache_controller = prev_cache_controller;
},
// model
model: function (name) {
var file = sgl.cfg.path + '/models/' + name + '.js',
prev_cache_model = sgl.cfg.cache_model;
if(path.existsSync(file)) {
var rtn = require(file).call(sgl);
if(!sgl.cfg.cache_model) {
delete require.cache[file];
}
sgl.cfg.cache_model = prev_cache_model;
return rtn;
}
},
// template
template: function (view, obj) {
_.templateSettings = {
interpolate : /<%=([\s\S]+?)%>/g
};
obj = _.extend({'lang':this.lang, 'langObj':this.langObj, 'status':''}, obj);
return _.template(this.view(view))(obj);
},
//langObj
langObj: {},
// lang
lang: function (tag, obj) {
_.templateSettings = {
interpolate : /\{(.+?)\}/g
};
return this.langObj[tag] ? _.template(this.langObj[tag])(obj) : '{lang tag <em>' + tag + '</em> not found}';
},
// langload
langFile: function (file) {
if(!sgl.cfg.lang) {
return;
}
var file = sgl.cfg.path + '/lang/' + sgl.cfg.lang + '/' + file + '.lang.js';
this.langObj = _.extend((path.existsSync(file) ? require(file) : {}), this.langObj);
}
};
// tools
if(path.existsSync('./tools.js')) {
sgl.tool = require('./tools.js');
}
// server config
appre.use(express.bodyParser());
appre.use(express.methodOverride());
appre.use(express.cookieParser());
appre.use(express.session({ secret: sgl.cfg.secret }));
// socket.io
if(sgl.cfg.socket) {
sgl.io = require('socket.io').listen(app);
console.log(sgl.cfg.host + ': socket.io [ok]');
}
// mongodb
if(sgl.cfg.mongodb) {
// config
sgl.cfg.mongodb = _.extend({
host: '127.0.0.1',
port: '27017',
dbname: 'default',
server_options: {},
db_options: {}
}, sgl.cfg.mongodb);
var mongodb = require("mongodb"),
mongoserver = new mongodb.Server(sgl.cfg.mongodb.host, sgl.cfg.mongodb.port, sgl.cfg.mongodb.server_options),
db_connector = new mongodb.Db(sgl.cfg.mongodb.dbname, mongoserver, sgl.cfg.mongodb.db_options);
db_connector.open(function (err, db) {
sgl.mongodb = db;
console.log(sgl.cfg.host + ': mongodb [ok]');
});
}
// static (/public)
appre.get('/public*', function(req, res){
filename = sgl.cfg.path + req.url;
if(req.url !== '/public/' && path.existsSync(filename)) {
fs.readFile(filename, "binary", function(err, file) {
res.writeHead(200, {'Content-Type': mime.lookup(filename), 'Cache-Control': sgl.cfg.cache_client});
res.write(file, "binary");
res.end();
});
}
else {
res.send('{file <em>' + req.url + '</em> not found}');
}
});
// request
appre.get('*', function(req, res) {
sgl.mvc.routing.call(sgl, req, res, 'get');
});
appre.post('*', function(req, res) {
sgl.mvc.routing.call(sgl, req, res, 'post');
});
return appre;
};
return function (sgl) {
// multi-domain support
if(sgl.domains) {
for(var domain in sgl.domains) {
if(hasOwnProperty.call(sgl.domains, domain)) {
app.use(express.vhost(domain, this.server(sgl.domains[domain])));
console.log(sgl.domains[domain].cfg.host + ' [load]');
}
}
app.listen(sgl.port || 80, sgl.ip || '127.0.0.1');
}
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment