-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
164 lines (138 loc) · 5.96 KB
/
server.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
158
159
160
161
162
163
164
/**
* node-publish server
*/
console.log("starting node-publish...");
console.log("NODE_ENV = %s", process.env.NODE_ENV);
var
express = require('express'),
resource = require('express-resource'),
md = require("node-markdown").Markdown,
avatar = require('node-gravatar'),
opt = require('./opt'),
path = require('path');
// create server
var app = module.exports = express.createServer();
// common middleware
console.log('adding commmon middleware...');
//app.use(express.methodOverride());
//app.use(express.bodyParser());
//app.use(express.cookieParser());
// set view options
console.log('setting view options...');
app.set('view engine', 'jade');
app.set('views', __dirname + '/views');
app.set('view options', { layout: true });
/**
* register the markdown pages for views
*/
app.register('.md', {
compile: function(str, options){
// add image references to bottom of markdown
// e.g. [id]: url/to/image "Optional title attribute"
if (opt.authorEmail) {
var avatarUrl = avatar.get(opt.authorEmail, 'G', 22);
str = str + "\n[avatar]:" + avatarUrl;
}
// NOTE: this is executed before the JADE header file
// that's why you can set the 'h1' local var here,
// and use it in the header.jade file
var html = md(str);
return function(locals){
// pass some options
locals['siteName'] = opt.siteName;
locals['siteUrl'] = opt.siteUrl;
locals['authorEmail'] = opt.authorEmail;
// locals variables substitution {<varname>}
var withlocals = html.replace(/\{([^}\s]+)\}/g, function(_, name){
return locals[name];
});
// extract H1 title
var matches = /h1>(.+)<\/h1/i.exec(withlocals);
if (matches)
locals['h1'] = matches[1];
else
locals['h1'] = 'unknown';
/**
* masage markdown output for mobile
* - if an index page, add data-role="listview" to lists
* - remove the <h1> tag, it's already included in the header
*/
if (locals.isMobile) {
if (locals.isIndex) {
withlocals = withlocals.replace(/<(o|u)l/, "<$1l data-role=\"listview\" ");
}
withlocals = withlocals.replace(/<h1>.*<\/h1>/, "");
}
// return markdown converted to html
return withlocals;
};
}
});
// NOTE: this is called by chrome on every request... ignore it
app.use('/favicon.ico', function(req, res) { res.send('no favicon yet, sry!', 404); });
/**
* mobile/tablet detect middleware
*/
app.use(function(req, res, next) {
var ua = req.headers['user-agent'].toLowerCase();
req.isMobile = (/android|avantgo|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(ua)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i.test(ua.substr(0,4)));
next();
});
/**
* generic configuration
*/
app.configure(function() {
console.log("generic configuration...");
});
/**
* production configuration
*/
app.configure('production', function(){
console.log("production configuration...");
var oneYear = 31557600000;
app.use('/static', express.static(__dirname + '/static', { maxAge: oneYear }));
app.use(express.errorHandler());
});
/**
* development config
*/
app.configure('development', function(){
console.log("development configuration...");
app.use('/static', express.static(__dirname + '/static'));
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
/**
* dynamic view helpers
*/
app.dynamicHelpers({
// is mobile
isMobile: function(req, res) {
return req.isMobile;
},
// site options
opt: function(req, res) {
return opt;
},
});
/**
* fancy express routing
*/
console.log("adding express resources...");
// site
var SiteResource = require('./site');
app.get(/^\/(\d{4})\/(\d{2})\/(\d{2})\/([a-z][a-z0-9-]+)\/?$/, SiteResource.showPost); // format: yyyy/mm/dd/slug
app.resource(SiteResource);
// errors
app.error(function(err, req, res){
var args = {
layout: (req.isMobile ? 'mobile/error.jade' : 'error.jade'),
error: err,
page: {class: 'error' },
};
res.render(path.join(opt.pagesPath, 'error.md'), args);
});
/**
* listen already!
*/
app.listen(opt.port);
console.log("listening on port %s...", opt.port);