From 842cd17979d8ba62a19bf19062a85bef717a0330 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 29 Oct 2013 12:34:41 -0400 Subject: [PATCH 1/8] themes - added ability to route custom templates --- src/meta.js | 5 ++--- src/webserver.js | 9 ++++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/meta.js b/src/meta.js index 771839e684..c2a1ee5cfa 100644 --- a/src/meta.js +++ b/src/meta.js @@ -120,9 +120,8 @@ var utils = require('./../public/src/utils.js'), }); }, function(config, next) { - if (config.staticDir) { - themeData['theme:staticDir'] = config.staticDir; - } + themeData['theme:staticDir'] = config.staticDir ? config.staticDir : false; + themeData['theme:templates'] = config.templates ? config.templates : false; RDB.hmset('config', themeData, next); } diff --git a/src/webserver.js b/src/webserver.js index c4502787f0..3b69aafb6d 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -165,7 +165,7 @@ var express = require('express'), }, function(next) { // Theme configuration - RDB.hmget('config', 'theme:type', 'theme:id', 'theme:staticDir', function(err, themeData) { + RDB.hmget('config', 'theme:type', 'theme:id', 'theme:staticDir', 'theme:templates', function(err, themeData) { var themeId = (themeData[1] || 'nodebb-theme-vanilla'); // Detect if a theme has been selected, and handle appropriately @@ -183,6 +183,13 @@ var express = require('express'), } } + if (themeData[3]) { + app.use('/templates', express.static(path.join(__dirname, '../node_modules', themeData[1], themeData[3]))); + if (process.env.NODE_ENV === 'development') { + winston.info('Custom templates directory routed for theme: ' + themeData[1]); + } + } + app.use(require('less-middleware')({ src: path.join(__dirname, '../node_modules/' + themeId), dest: path.join(__dirname, '../public/css'), From bbb716723fc030962720fb237cf9cb97c520ca86 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 29 Oct 2013 14:04:07 -0400 Subject: [PATCH 2/8] templates - basic implementation of conditionals show me --- public/src/templates.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/public/src/templates.js b/public/src/templates.js index cb153ed10d..5e9d5e35f5 100644 --- a/public/src/templates.js +++ b/public/src/templates.js @@ -227,6 +227,10 @@ return new RegExp("[\\s\\S]*", 'g'); } + function makeConditionalRegex(block) { + return new RegExp("[\\s\\S]*", 'g'); + } + function getBlock(regex, block, template) { data = template.match(regex); if (data == null) return; @@ -240,6 +244,19 @@ return data; } + function getConditionalBlock(regex, block, template) { + data = template.match(regex); + if (data == null) return; + + if (self.blocks && block !== undefined) self.blocks[block] = data[0]; + + data = data[0] + .replace("", "") + .replace("", ""); + + return data; + } + function setBlock(regex, block, template) { return template.replace(regex, block); } @@ -289,6 +306,14 @@ block = parse(data[d], namespace, block); template = setBlock(regex, block, template); } else { + var conditional = makeConditionalRegex(d), + block = getConditionalBlock(conditional, namespace, template); + + if (block && !data[d]) { + template = template.replace(conditional, ''); + } + + template = replace(namespace + d, data[d], template); } } From 89540172b2eaa4300bac5daf47bf7ec9cb52ea4f Mon Sep 17 00:00:00 2001 From: Baris Soner Usakli Date: Tue, 29 Oct 2013 14:16:03 -0400 Subject: [PATCH 3/8] closes #464 --- public/src/forum/admin/topics.js | 1 + public/templates/admin/topics.tpl | 2 +- src/topics.js | 9 +++++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/public/src/forum/admin/topics.js b/public/src/forum/admin/topics.js index 8960bed25d..5750e83f37 100644 --- a/public/src/forum/admin/topics.js +++ b/public/src/forum/admin/topics.js @@ -59,6 +59,7 @@ define(function() { topicsListEl.innerHTML += html; btnEl.innerHTML = 'Load More Topics'; + $('span.timeago').timeago(); } else { // Exhausted all topics btnEl.className += ' disabled'; diff --git a/public/templates/admin/topics.tpl b/public/templates/admin/topics.tpl index 1521f400ac..f970823db8 100644 --- a/public/templates/admin/topics.tpl +++ b/public/templates/admin/topics.tpl @@ -11,7 +11,7 @@ {topics.title}
    -
  • Posted {topics.relativeTime} ago by {topics.username}
  • +
  • Posted by {topics.username}
  • {topics.postcount} post(s)
diff --git a/src/topics.js b/src/topics.js index b40b67eb7c..76408b9fb5 100644 --- a/src/topics.js +++ b/src/topics.js @@ -22,8 +22,12 @@ var RDB = require('./redis.js'), Topics.getTopicData = function(tid, callback) { RDB.hgetall('topic:' + tid, function(err, data) { if (err === null) { - if(data) + if(data) { data.title = validator.sanitize(data.title).escape(); + if(data.timestamp) { + data.relativeTime = new Date(parseInt(data.timestamp, 10)).toISOString(); + } + } callback(data); } else { @@ -327,8 +331,6 @@ var RDB = require('./redis.js'), topicData['lock-icon'] = topicData.locked === '1' ? 'icon-lock' : 'none'; topicData['deleted-class'] = topicData.deleted === '1' ? 'deleted' : ''; - topicData.relativeTime = new Date(parseInt(topicData.timestamp, 10)).toISOString(); - topicData.username = topicInfo.username; topicData.badgeclass = (topicInfo.hasread && current_user != 0) ? '' : 'badge-important'; topicData.teaser_text = topicInfo.teaserInfo.text || '', @@ -455,7 +457,6 @@ var RDB = require('./redis.js'), hasRead = results[1], teaser = results[2]; - topicData.relativeTime = new Date(parseInt(topicData.timestamp,10)).toISOString(); topicData.badgeclass = hasRead ? '' : 'badge-important'; topicData.teaser_text = teaser.text || ''; topicData.teaser_username = teaser.username || ''; From 1d5a2088968cea3006507662ee7e95a725ff3fc0 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 29 Oct 2013 14:40:29 -0400 Subject: [PATCH 4/8] themes - added ability to route custom templates serverside --- app.js | 5 ++++- public/src/templates.js | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app.js b/app.js index 4324d6f2e4..e8b662bbd4 100644 --- a/app.js +++ b/app.js @@ -96,6 +96,8 @@ global.translator = translator; translator.loadServer(); + + var customTemplates = meta.config['theme:templates'] ? path.join(__dirname, 'node_modules', meta.config['theme:id'], meta.config['theme:templates']) : false; // todo: replace below with read directory code, derp. templates.init([ @@ -104,7 +106,8 @@ 'emails/header', 'emails/footer', 'noscript/header', 'noscript/home', 'noscript/category', 'noscript/topic' - ]); + ], customTemplates); + templates.ready(webserver.init); diff --git a/public/src/templates.js b/public/src/templates.js index 5e9d5e35f5..3329d2782b 100644 --- a/public/src/templates.js +++ b/public/src/templates.js @@ -57,13 +57,13 @@ return template; }; - function loadTemplates(templatesToLoad) { + function loadTemplates(templatesToLoad, customTemplateDir) { function loadServer() { var loaded = templatesToLoad.length; for (var t in templatesToLoad) { (function (file) { - fs.readFile(__dirname + '/../templates/' + file + '.tpl', function (err, html) { + fs.readFile((customTemplateDir ? customTemplateDir : __dirname + '/../templates') + '/' + file + '.tpl', function (err, html) { var template = function () { this.toString = function () { return this.html; @@ -96,8 +96,8 @@ } - templates.init = function (templates_to_load) { - loadTemplates(templates_to_load || []); + templates.init = function (templates_to_load, custom_templates) { + loadTemplates(templates_to_load || [], custom_templates || false); } templates.getTemplateNameFromUrl = function (url) { From ca9cd3606776c558e390adff56eff496115c2913 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 29 Oct 2013 14:51:58 -0400 Subject: [PATCH 5/8] fix for switching back to a theme without a custom template dir --- src/meta.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/meta.js b/src/meta.js index c2a1ee5cfa..6ee119e8c0 100644 --- a/src/meta.js +++ b/src/meta.js @@ -120,8 +120,8 @@ var utils = require('./../public/src/utils.js'), }); }, function(config, next) { - themeData['theme:staticDir'] = config.staticDir ? config.staticDir : false; - themeData['theme:templates'] = config.templates ? config.templates : false; + themeData['theme:staticDir'] = config.staticDir ? config.staticDir : ''; + themeData['theme:templates'] = config.templates ? config.templates : ''; RDB.hmset('config', themeData, next); } From 30a45ee78ef97783bbf4aafdaad31d641d02b534 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 29 Oct 2013 15:13:07 -0400 Subject: [PATCH 6/8] prevent a potentially badly written theme.json from blowing up your forum --- public/src/templates.js | 49 +++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/public/src/templates.js b/public/src/templates.js index 3329d2782b..2adb4553de 100644 --- a/public/src/templates.js +++ b/public/src/templates.js @@ -61,26 +61,37 @@ function loadServer() { var loaded = templatesToLoad.length; - for (var t in templatesToLoad) { - (function (file) { - fs.readFile((customTemplateDir ? customTemplateDir : __dirname + '/../templates') + '/' + file + '.tpl', function (err, html) { - var template = function () { - this.toString = function () { - return this.html; - }; - } - - template.prototype.file = file; - template.prototype.parse = parse; - template.prototype.html = String(html); - - global.templates[file] = new template; - - loaded--; - if (loaded == 0) templates.ready(); - }); - }(templatesToLoad[t])); + function getTemplates(directory) { + for (var t in templatesToLoad) { + (function (file) { + fs.readFile(directory + '/' + file + '.tpl', function (err, html) { + var template = function () { + this.toString = function () { + return this.html; + }; + } + + template.prototype.file = file; + template.prototype.parse = parse; + template.prototype.html = String(html); + + global.templates[file] = new template; + + loaded--; + if (loaded == 0) templates.ready(); + }); + }(templatesToLoad[t])); + } + } + if (customTemplateDir) { + fs.exists(customTemplateDir, function (exists) { + var directory = (exists ? customTemplateDir : __dirname + '/../templates'); + getTemplates(customTemplateDir); + }); + } else { + getTemplates(__dirname + '/../templates'); } + } function loadClient() { From 7eba0b85f4fa6976fe6c78b363454714be0007e2 Mon Sep 17 00:00:00 2001 From: Baris Soner Usakli Date: Tue, 29 Oct 2013 15:19:29 -0400 Subject: [PATCH 7/8] fixed andrews fail --- public/src/templates.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/templates.js b/public/src/templates.js index 2adb4553de..bd3f376ca8 100644 --- a/public/src/templates.js +++ b/public/src/templates.js @@ -86,7 +86,7 @@ if (customTemplateDir) { fs.exists(customTemplateDir, function (exists) { var directory = (exists ? customTemplateDir : __dirname + '/../templates'); - getTemplates(customTemplateDir); + getTemplates(directory); }); } else { getTemplates(__dirname + '/../templates'); From a71870de28f80e7a7f0255389e78cc0a1e3219a9 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 29 Oct 2013 17:27:23 -0400 Subject: [PATCH 8/8] pass in site description as well for potential themes to take advantage of --- src/webserver.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/webserver.js b/src/webserver.js index 3b69aafb6d..08dbeab485 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -74,6 +74,7 @@ var express = require('express'), cssSrc: meta.config['theme:src'] || nconf.get('relative_path') + '/vendor/bootstrap/css/bootstrap.min.css', pluginCSS: plugins.cssFiles.map(function(file) { return { path: file } }), title: meta.config.title || '', + description: meta.config.description || '', 'brand:logo': meta.config['brand:logo'] || '', 'brand:logo:display': meta.config['brand:logo']?'':'hide', browserTitle: meta.config.title || 'NodeBB',