Baris Usakli 12 years ago
commit eb1c1c78d4

@ -81,6 +81,7 @@
};
var templates = require('./public/src/templates.js'),
translator = require('./public/src/translator.js'),
webserver = require('./src/webserver.js'),
SocketIO = require('socket.io').listen(global.server, { log: false, transports: ['websocket', 'xhr-polling', 'jsonp-polling', 'flashsocket']}),
websockets = require('./src/websockets.js'),
@ -89,6 +90,11 @@
websockets.init(SocketIO);
global.templates = {};
global.translator = translator;
translator.loadServer();
// todo: replace below with read directory code, derp.
templates.init([
'header', 'footer', 'logout', 'outgoing', 'admin/header', 'admin/footer', 'admin/index',
'emails/reset', 'emails/reset_plaintext', 'emails/email_confirm', 'emails/email_confirm_plaintext',

@ -0,0 +1,3 @@
NPM INSTALL
For now, language packs will be stored here. Eventually, will be moved to server side to allow for npm install-ability.
When that happens, server code will generate compressed JSON language files in this folder.

@ -0,0 +1,7 @@
{
"new_topic_button": "New Topic",
"no_topics": "<strong>There are no topics in this category.</strong><br />Why don't you try posting one?",
"sidebar.recent_replies": "Recent Replies",
"sidebar.active_participants": "Active Participants",
"sidebar.moderators": "Moderators"
}

@ -0,0 +1,12 @@
{
"disconnect.title": "Socket Disconnect",
"disconnect.message": "Looks like you disconnected, try reloading the page.",
"disconnect.reload_button": "Reload",
"chat.chatting_with": "Chat with <span id='chat-with-name'></span>",
"chat.placeholder": "type chat message, here press enter to send",
"chat.send": "Send",
"stats.online": "Online",
"stats.users": "Users",
"stats.topics": "Topics",
"stats.posts": "Posts"
}

@ -0,0 +1,17 @@
{
"home": "Home",
"search": "Search",
"buttons.close": "Close",
"403.title": "Access Denied",
"403.message": "You seem to have stumbled upon a page that you do not have access to. Perhaps you should <a href='/login'>try logging in</a>?",
"404.title": "Not Found",
"404.message": "You seem to have stumbled upon a page that does not exist. Return to the <a href='/''>home page</a>.",
"logout": "Logout",
"logout.title": "You are now logged out.",
"logout.message": "You have successfully logged out of NodeBB",
"header.recent": "Recent",
"header.unread": "Unread",
"header.users": "Users",
"header.search": "Search",
"notifications.loading": "Loading Notifications"
}

@ -0,0 +1,10 @@
{
"login": "Login",
"username": "Username",
"password": "Password",
"remember_me": "Remember Me?",
"forgot_password": "Forgot Password?",
"alternative_logins": "Alternative Logins",
"failed_login_attempt": "Failed login attempt, please try again.",
"login_successful": "You have successfully logged in!"
}

@ -0,0 +1,16 @@
{
"register": "Register",
"help.email": "By default, your email will be hidden from the public.",
"help.username_restrictions": "A unique username between %1 and %2 characters. Others can mention you with @<span id='yourUsername'>username</span>.",
"help.minimum_password_length": "Your password's length must be at least %1 characters.",
"email_address": "Email Address",
"email_address_placeholder": "Enter Email Address",
"username": "Username",
"username_placeholder": "Enter Username",
"password": "Password",
"password_placeholder": "Enter Password",
"confirm_password": "Confirm Password",
"confirm_password_placeholder": "Confirm Password",
"register_now_button": "Register Now",
"alternative_registration": "Alternative Registration"
}

@ -0,0 +1,21 @@
{
"profile": "Profile",
"chat": "Chat",
"notify_me": "Be notified of new replies in this topic",
"favourite": "Favourite",
"quote": "Quote",
"reply": "Reply",
"edit": "Edit",
"delete": "Delete",
"banned": "banned",
"link": "Link",
"thread_tools.title": "Thread Tools",
"thread_tools.pin": "Pin Thread",
"thread_tools.lock": "Lock Thread",
"thread_tools.move": "Move Thread",
"thread_tools.delete": "Delete Thread",
"load_categories": "Loading Categories",
"confirm_move": "Move",
"favourites.not_logged_in.title": "Not Logged In",
"favourites.not_logged_in.message": "Please log in in order to favourite this post"
}

@ -0,0 +1,5 @@
{
"no_unread_topics": "There are no unread topics.",
"mark_all_read": "Mark all as Read",
"load_more": "Load More"
}

@ -0,0 +1,9 @@
{
"latest_users": "Latest Users",
"top_posters": "Top Posters",
"most_reputation": "Most Reputation",
"online": "Online",
"search": "Search",
"enter_username": "Enter a username to search",
"load_more": "Load More"
}

@ -2,6 +2,7 @@ var ajaxify = {};
(function ($) {
/*global app, templates, utils*/
var location = document.location || window.location,
rootUrl = location.protocol + '//' + (location.hostname || location.host) + (location.port ? ':' + location.port : ''),
@ -68,6 +69,8 @@ var ajaxify = {};
}
}
translator.load(tpl_url);
jQuery('#footer, #content').fadeOut(100);
templates.flush();
@ -95,7 +98,7 @@ var ajaxify = {};
}
return false;
}
};
$('document').ready(function () {
if (!window.history || !window.history.pushState) return; // no ajaxification for old browsers
@ -132,7 +135,7 @@ var ajaxify = {};
function nodeName(elem, name) {
return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
};
}
function evalScript(elem) {
var data = (elem.text || elem.textContent || elem.innerHTML || ""),
@ -154,7 +157,7 @@ var ajaxify = {};
head.insertBefore(script, head.firstChild);
//TODO: remove from head before inserting?, doing this breaks scripts in safari so commented out for now
//head.removeChild(script);
};
}
var scripts = [],
script,
@ -177,6 +180,6 @@ var ajaxify = {};
}
evalScript(scripts[i]);
}
};
}
}(jQuery));

@ -180,7 +180,9 @@
else
template_data['relative_path'] = RELATIVE_PATH;
document.getElementById('content').innerHTML = templates[tpl_url].parse(template_data);
translator.translate(templates[tpl_url].parse(template_data), function (translatedTemplate) {
document.getElementById('content').innerHTML = translatedTemplate;
});
jQuery('#content [template-variable]').each(function (index, element) {
var value = null;

@ -0,0 +1,165 @@
(function (module) {
"use strict";
/*global RELATIVE_PATH*/
/*
* TODO:
*
* 1. language en is hardcoded while system is developed. to switch language packs for now please edit DEFAULT_LANGUAGE
* b. need to write fallback system to default language if keys are missing (is this even necessary?)
* 2. recursion needed when parsing language keys (ex. topics:modal.delete.title), right now json is all one level deep
* 3. server side settings for default language
* 4. user side settings for preferred language
*
*/
var DEFAULT_LANGUAGE = 'en';
var translator = {},
files = {
loaded: {},
loading: {},
callbacks: {} // could be combined with "loading" in future.
},
isServer = false;
module.exports = translator;
translator.get = function (key, callback) {
var parsedKey = key.split(':'),
languageFile = parsedKey[0];
parsedKey = parsedKey[1];
translator.load(languageFile, function (languageData) {
if (callback) {
callback(languageData[parsedKey]);
}
return languageData[parsedKey];
});
};
/*
* TODO: Not fully converted to server side yet, ideally server should be able to parse whole templates on demand if necessary
* fix: translator.load should determine if server side and immediately return appropriate language file.
*/
translator.translate = function (data, callback) {
var keys = data.match(/\[\[.*?\]\]/g),
loading = 0;
function insertLanguage(text, key, value, variables) {
if (value) {
for (var i = 1, ii = variables.length; i < ii; i++) {
var variable = variables[i].replace(']]', '');
value = value.replace('%' + i, variable);
}
text = text.replace(key, value);
}
return text;
}
for (var key in keys) {
if (keys.hasOwnProperty(key)) {
var variables = keys[key].split(/[,][?\s+]/);
var parsedKey = keys[key].replace('[[', '').replace(']]', '').split(':'),
languageFile = parsedKey[0];
parsedKey = parsedKey[1].split(',')[0];
if (files.loaded[languageFile]) {
data = insertLanguage(data, keys[key], files.loaded[languageFile][parsedKey], variables);
} else {
loading++;
(function (languageKey, parsedKey) {
translator.load(languageFile, function (languageData) {
data = insertLanguage(data, languageKey, languageData[parsedKey], variables);
loading--;
checkComplete();
});
}(keys[key], parsedKey));
}
}
}
checkComplete();
function checkComplete() {
if (loading === 0) {
callback(data);
}
}
};
translator.load = function (filename, callback) {
if (isServer === true) {
if (callback) {
callback(files.loaded[filename]);
}
return files.loaded[filename];
}
if (files.loaded[filename] && !files.loading[filename]) {
if (callback) {
callback(files.loaded[filename]);
}
} else if (files.loading[filename]) {
if (callback) {
files.callbacks[filename] = files.callbacks[filename] || [];
files.callbacks[filename].push(callback);
}
} else {
var timestamp = new Date().getTime(); //debug
files.loading[filename] = true;
jQuery.getJSON(RELATIVE_PATH + '/language/' + DEFAULT_LANGUAGE + '/' + filename + '.json?v=' + timestamp, function (language) {
files.loaded[filename] = language;
if (callback) {
callback(language);
}
while (files.callbacks[filename] && files.callbacks[filename].length) {
files.callbacks[filename].pop()(language);
}
files.loading[filename] = false;
});
}
};
translator.loadServer = function () {
isServer = true;
var utils = require('./utils.js'),
path = require('path'),
fs = require('fs');
utils.walk(path.join(__dirname, '../../', 'public/language/' + DEFAULT_LANGUAGE), function (err, data) {
var loaded = data.length;
for (var d in data) {
if (data.hasOwnProperty(d)) {
files.loaded[path.basename(data[d]).replace('.json', '')] = require(data[d]);
}
}
});
};
if ('undefined' !== typeof window) {
window.translator = module.exports;
}
})('undefined' === typeof module ? {
module: {
exports: {}
}
} : module);

@ -1,4 +1,4 @@
<div class="alert alert-danger">
<strong>Access Denied</strong>
<p>You seem to have stumbled upon a page that you do not have access to. Perhaps you should <a href="/login">try logging in?</a></p>
<strong>[[global:403.title]]</strong>
<p>[[global:403.message]]</p>
</div>

@ -1,4 +1,4 @@
<div class="alert alert-danger">
<strong>Not found</strong>
<p>You seem to have stumbled upon a page that does not exist. Return to the <a href="/">home page</a></p>
<strong>[[global:404.title]]</strong>
<p>[[global:404.message]]</p>
</div>

@ -16,6 +16,7 @@
<script type="text/javascript" src="{relative_path}/socket.io/socket.io.js"></script>
<script type="text/javascript" src="{relative_path}/src/app.js"></script>
<script type="text/javascript" src="{relative_path}/src/templates.js"></script>
<script type="text/javascript" src="{relative_path}/src/translator.js"></script>
<script type="text/javascript" src="{relative_path}/src/ajaxify.js"></script>
<script src="{relative_path}/vendor/jquery/js/jquery.timeago.js"></script>
<script src="{relative_path}/vendor/requirejs/require.js"></script>

@ -1,6 +1,6 @@
<ol class="breadcrumb">
<li itemscope="itemscope" itemtype="http://data-vocabulary.org/Breadcrumb">
<a href="/" itemprop="url"><span itemprop="title">Home</span></a>
<a href="/" itemprop="url"><span itemprop="title">[[global:home]]</span></a>
</li>
<li class="active" itemscope="itemscope" itemtype="http://data-vocabulary.org/Breadcrumb">
<span itemprop="title">{category_name} <a target="_blank" href="../{category_id}.rss"><i class="icon-rss-sign"></i></a></span>
@ -9,7 +9,7 @@
</ol>
<div>
<button id="new_post" class="btn btn-primary btn-lg {show_topic_button}">New Topic</button>
<button id="new_post" class="btn btn-primary btn-lg {show_topic_button}">[[category:new_topic_button]]</button>
<div class="inline-block pull-right">
<a href="#" id="facebook-share"><i class="icon-facebook-sign icon-2x"></i></a>&nbsp;
@ -21,8 +21,7 @@
<hr/>
<div class="alert alert-warning hide {no_topics_message}" id="category-no-topics">
<strong>There are no topics in this category.</strong><br />
Why don't you try posting one?
[[category:no_topics]]
</div>
<div class="category row">
@ -65,7 +64,7 @@
<div class="sidebar-block img-thumbnail">
<div class="block-header">
Recent Replies
[[category:sidebar.recent_replies]]
</div>
<div class="block-content recent-replies">
<ul id="category_recent_replies"></ul>
@ -73,7 +72,7 @@
</div>
<div class="sidebar-block img-thumbnail">
<div class="block-header">
Active Participants
[[category:sidebar.active_participants]]
</div>
<div class="block-content">
<!-- BEGIN active_users -->
@ -83,7 +82,7 @@
</div>
<div class="sidebar-block img-thumbnail {moderator_block_class}">
<div class="block-header">
Moderators
[[category:sidebar.moderators]]
</div>
<div class="block-content">
<!-- BEGIN moderators -->

@ -6,13 +6,13 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 id="myModalLabel">Socket Disconnect</h3>
<h3 id="myModalLabel">[[footer:disconnect.title]]</h3>
</div>
<div class="modal-body">
<span id="disconnect-text">Looks like you disconnected, try reloading the page.</span>
<span id="disconnect-text">[[footer:disconnect.message]]</span>
</div>
<div class="modal-footer">
<a id="reload-button" href="/" class="btn btn-primary">Reload</a>
<a id="reload-button" href="/" class="btn btn-primary">[[footer:disconnect.reload_button]]</a>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
@ -23,15 +23,15 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 id="myModalLabel">Chat with <span id="chat-with-name"></span></h3>
<h3 id="myModalLabel">[[footer:chat.chatting_with]]</h3>
</div>
<div class="modal-body">
<textarea class="form-control" id="chat-content" cols="40" rows="10" readonly></textarea><br/>
<input id="chat-message-input" type="text" class="form-control" name="chat-message" placeholder="type chat message, here press enter to send"/>
<input id="chat-message-input" type="text" class="form-control" name="chat-message" placeholder="[[footer:chat.placeholder]]"/>
</div>
<div class="modal-footer">
<button type="button" id="chat-message-send-btn" href="#" class="btn btn-primary btn-lg btn-block
">Send</button>
">[[footer:chat.send]]</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
@ -45,22 +45,22 @@
<div class="row footer-stats">
<div class="col-md-3 col-xs-6">
<div class="stats-card well">
<h2><span id="stats_online"></span><br /><small>Online</small></h2>
<h2><span id="stats_online"></span><br /><small>[[footer:stats.online]]</small></h2>
</div>
</div>
<div class="col-md-3 col-xs-6">
<div class="stats-card well">
<h2><span id="stats_users"></span><br /><small>Users</small></h2>
<h2><span id="stats_users"></span><br /><small>[[footer:stats.users]]</small></h2>
</div>
</div>
<div class="col-md-3 col-xs-6">
<div class="stats-card well">
<h2><span id="stats_topics"></span><br /><small>Topics</small></h2>
<h2><span id="stats_topics"></span><br /><small>[[footer:stats.topics]]</small></h2>
</div>
</div>
<div class="col-md-3 col-xs-6">
<div class="stats-card well">
<h2><span id="stats_posts"></span><br /><small>Posts</small></h2>
<h2><span id="stats_posts"></span><br /><small>[[footer:stats.posts]]</small></h2>
</div>
</div>
</div>

@ -39,13 +39,16 @@
<div class="navbar-collapse collapse navbar-ex1-collapse">
<ul id="main-nav" class="nav navbar-nav">
<li>
<a href="/recent">Recent</a>
<a href="/recent">[[global:header.recent]]</a>
</li>
<li class="nodebb-loggedin">
<a href="/unread"><span id="numUnreadBadge" class="badge badge-inverse">0</span> Unread</a>
<a href="/unread"><span id="numUnreadBadge" class="badge badge-inverse">0</span> [[global:header.unread]]</a>
</li>
<li>
<a href="/users">Users</a>
<a href="/users">[[global:header.users]]</a>
</li>
<li class="visible-xs">
<a href="/search">[[global:header.search]]</a>
</li>
<li class="visible-xs">
<a href="/search">Search</a>
@ -60,7 +63,7 @@
<div class="form-group">
<input type="text" class="form-control" placeholder="Search" name="query" value="">
</div>
<button type="submit" class="btn btn-default hide">Search</button>
<button type="submit" class="btn btn-default hide">[[global:search]]</button>
</div>
<button id="search-button" type="button" class="btn btn-link"><i class="icon-search"></i></button>
</form>
@ -70,7 +73,7 @@
<a class="dropdown-toggle" data-toggle="dropdown" href="#" id="notif_dropdown"><i class="icon-circle-blank"></i></a>
<ul id="notif-list" class="dropdown-menu" aria-labelledby="notif_dropdown">
<li>
<a href="#"><i class="icon-refresh icon-spin"></i> Loading Notifications</a>
<a href="#"><i class="icon-refresh icon-spin"></i> [[global:notifications.loading]]</a>
</li>
</ul>
</li>

@ -1,9 +1,9 @@
<ol class="breadcrumb">
<li itemscope="itemscope" itemtype="http://data-vocabulary.org/Breadcrumb">
<a href="/" itemprop="url"><span itemprop="title">Home</span></a>
<a href="/" itemprop="url"><span itemprop="title">[[global:home]]</span></a>
</li>
<li class="active" itemscope="itemscope" itemtype="http://data-vocabulary.org/Breadcrumb">
<span itemprop="title">Login</span>
<span itemprop="title">[[login:login]]</span>
</li>
</ol>
@ -13,18 +13,18 @@
<div class="well well-lg">
<div class="alert alert-danger" id="login-error-notify" style="display:none">
<button type="button" class="close" data-dismiss="alert">&times;</button>
<strong>Failed Login Attempt</strong> <p></p>
<strong>[[login:failed_login_attempt]]</strong> <p></p>
</div>
<form class="form-horizontal" role="form">
<div class="form-group">
<label for="username" class="col-lg-2 control-label">Username</label>
<label for="username" class="col-lg-2 control-label">[[login:username]]</label>
<div class="col-lg-10">
<input class="form-control" type="text" placeholder="Enter Username" name="username" id="username" />
</div>
</div>
<div class="form-group">
<label for="password" class="col-lg-2 control-label">Password</label>
<label for="password" class="col-lg-2 control-label">[[login:password]]</label>
<div class="col-lg-10">
<input class="form-control" type="password" placeholder="Enter Password" name="password" id="password" />
</div>
@ -33,14 +33,14 @@
<div class="col-lg-offset-2 col-lg-10">
<div class="checkbox">
<label>
<input type="checkbox"> Remember me
<input type="checkbox"> [[login:remember_me]]
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-primary" id="login" type="submit">Login</button> &nbsp; <a href="/reset">Forgot Password?</a>
<button class="btn btn-primary" id="login" type="submit">[[login:login]]</button> &nbsp; <a href="/reset">[[login:forgot_password]]</a>
</div>
</div>
<input type="hidden" name="_csrf" value="{token}" id="csrf-token" />
@ -48,10 +48,10 @@
</div>
</div>
<div class="col-md-6 {alternate_logins:display}">
<div class="well well-lg">
<h4>Alternative Logins</h4>
<h4>[[login:alternative_logins]]</h4>
<ul class="alt-logins">
<li data-url="/auth/twitter" class="twitter {twitter:display}"><i class="icon-twitter-sign icon-3x"></i></li>
<li data-url="/auth/google" class="google {google:display}"><i class="icon-google-plus-sign icon-3x"></i></li>

@ -1,13 +1,13 @@
<ol class="breadcrumb">
<li itemscope="itemscope" itemtype="http://data-vocabulary.org/Breadcrumb">
<a href="/" itemprop="url"><span itemprop="title">Home</span></a>
<a href="/" itemprop="url"><span itemprop="title">[[global:home]]</span></a>
</li>
<li class="active" itemscope="itemscope" itemtype="http://data-vocabulary.org/Breadcrumb">
<span itemprop="title">Logout</span>
<span itemprop="title">[[global:logout]]</span>
</li>
</ol>
<div class="alert alert-success" id="message">
<h4>You are now logged out.</h4>
<p>You have successfully logged out of NodeBB</p>
<h4>[[global:logout.title]]</h4>
<p>[[global:logout.message]]</p>
</div>

@ -1,9 +1,9 @@
<ol class="breadcrumb">
<li itemscope="itemscope" itemtype="http://data-vocabulary.org/Breadcrumb">
<a href="/" itemprop="url"><span itemprop="title">Home</span></a>
<a href="/" itemprop="url"><span itemprop="title">[[global:home]]</span></a>
</li>
<li class="active" itemscope="itemscope" itemtype="http://data-vocabulary.org/Breadcrumb">
<span itemprop="title">Register</span>
<span itemprop="title">[[register:register]]</span>
</li>
</ol>
@ -12,46 +12,46 @@
<div class="well well-lg">
<form class="form-horizontal" role="form" action="{relative_path}/register" method="post">
<div class="form-group">
<label for="email" class="col-lg-4 control-label">Email Address</label>
<label for="email" class="col-lg-4 control-label">[[register:email_address]]</label>
<div class="col-lg-8">
<div class="input-group">
<input class="form-control" type="text" placeholder="Enter Email Address" name="email" id="email" />
<input class="form-control" type="text" placeholder="[[register:email_address_placeholder]]" name="email" id="email" />
<span class="input-group-addon">
<span id="email-notify"><i class="icon icon-circle-blank"></i></span>
</span>
</div>
<span class="help-block">By default, your email will be hidden from the public.</span>
<span class="help-block">[[register:help.email]]</span>
</div>
</div>
<div class="form-group">
<label for="username" class="col-lg-4 control-label">Username</label>
<label for="username" class="col-lg-4 control-label">[[register:username]]</label>
<div class="col-lg-8">
<div class="input-group">
<input class="form-control" type="text" placeholder="Enter Username" name="username" id="username" />
<input class="form-control" type="text" placeholder="[[register:username_placeholder]]" name="username" id="username" />
<span class="input-group-addon">
<span id="username-notify"><i class="icon icon-circle-blank"></i></span>
</span>
</div>
<span class="help-block">A unique username. {minimumUsernameLength}-{maximumUsernameLength} characters. Others can mention you with @<span id="yourUsername">username</span>.</span>
<span class="help-block">[[register:help.username_restrictions, {minimumUsernameLength}, {maximumUsernameLength}]]</span>
</div>
</div>
<div class="form-group">
<label for="password" class="col-lg-4 control-label">Password</label>
<label for="password" class="col-lg-4 control-label">[[register:password]]</label>
<div class="col-lg-8">
<div class="input-group">
<input class="form-control" type="password" placeholder="Enter Password" name="password" id="password" />
<input class="form-control" type="password" placeholder="[[register:password_placeholder]]" name="password" id="password" />
<span class="input-group-addon">
<span id="password-notify"><i class="icon icon-circle-blank"></i></span>
</span>
</div>
<span class="help-block">Your password's length must be at least {minimumPasswordLength} characters.</span>
<span class="help-block">[[register:help.minimum_password_length, {minimumPasswordLength}]]</span>
</div>
</div>
<div class="form-group">
<label for="password-confirm" class="col-lg-4 control-label">Confirm Password</label>
<label for="password-confirm" class="col-lg-4 control-label">[[register:confirm_password]]</label>
<div class="col-lg-8">
<div class="input-group">
<input class="form-control" type="password" placeholder="Confirm Password" name="password-confirm" id="password-confirm" />
<input class="form-control" type="password" placeholder="[[register:confirm_password_placeholder]]" name="password-confirm" id="password-confirm" />
<span class="input-group-addon">
<span id="password-confirm-notify"><i class="icon icon-circle-blank"></i></span>
</span>
@ -61,7 +61,7 @@
<div class="form-group">
<div class="col-lg-offset-4 col-lg-8">
<hr />
<button class="btn btn-primary btn-lg btn-block" id="register" type="submit">Register Now</button>
<button class="btn btn-primary btn-lg btn-block" id="register" type="submit">[[register:register_now_button]]</button>
</div>
</div>
<input type="hidden" name="_csrf" value="{token}" />
@ -70,7 +70,7 @@
</div>
<div class="col-md-6 {alternate_logins:display}">
<div class="well well-lg">
<h4>Alternative Registration</h4>
<h4>[[register:alternative_registration]]</h4>
<ul class="alt-logins">
<li data-url="/auth/twitter" class="twitter {twitter:display}"><i class="icon-twitter-sign icon-3x"></i></li>
<li data-url="/auth/google" class="google {google:display}"><i class="icon-google-plus-sign icon-3x"></i></li>

@ -1,7 +1,7 @@
<div class="topic">
<ol class="breadcrumb">
<li itemscope="itemscope" itemtype="http://data-vocabulary.org/Breadcrumb">
<a href="/" itemprop="url"><span itemprop="title">Home</span></a>
<a href="/" itemprop="url"><span itemprop="title">[[global:home]]</span></a>
</li>
<li itemscope="itemscope" itemtype="http://data-vocabulary.org/Breadcrumb">
<a href="/category/{category_slug}" itemprop="url"><span itemprop="title">{category_name}</span></a>
@ -27,32 +27,32 @@
<div class="topic-buttons">
<div class="btn-group">
<button class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" type="button" title="Posted by {main_posts.username}">
<button class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" type="button" title="[[topic:posted_by, {main_posts.username}]]">
<span class="username-field" href="/user/{main_posts.userslug}">{main_posts.username}&nbsp;</span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="/user/{main_posts.userslug}"><i class="icon-user"></i> Profile</a></li>
<li><div class="chat"><i class="icon-comment"></i> Chat</div></li>
<li><a href="/user/{main_posts.userslug}"><i class="icon-user"></i> [[topic:profile]]</a></li>
<li><div class="chat"><i class="icon-comment"></i> [[topic:chat]]</div></li>
</ul>
</div>
<div class="btn-group">
<button class="btn btn-sm btn-default follow" type="button" title="Be notified of new replies in this topic"><i class="icon-eye-open"></i></button>
<button class="favourite btn btn-sm btn-default {main_posts.fav_button_class}" type="button">
<span class="favourite-text">Favourite</span>
<span class="favourite-text">[[topic:favourite]]</span>
<span class="post_rep_{main_posts.pid}">{main_posts.post_rep} </span><i class="{main_posts.fav_star_class}"></i>
</button>
</div>
<div class="btn-group">
<button class="btn btn-sm btn-default quote" type="button" title="Quote"><i class="icon-quote-left"></i></button>
<button class="btn btn-sm btn-primary btn post_reply" type="button">Reply <i class="icon-reply"></i></button>
<button class="btn btn-sm btn-default quote" type="button" title="[[topic:quote]]"><i class="icon-quote-left"></i></button>
<button class="btn btn-sm btn-primary btn post_reply" type="button">[[topic:reply]] <i class="icon-reply"></i></button>
</div>
<div class="btn-group pull-right post-tools">
<button class="btn btn-sm btn-default link" type="button" title="Link"><i class="icon-link"></i></button>
<button class="btn btn-sm btn-default edit {main_posts.display_moderator_tools}" type="button" title="Edit"><i class="icon-pencil"></i></button>
<button class="btn btn-sm btn-default delete {main_posts.display_moderator_tools}" type="button" title="Delete"><i class="icon-trash"></i></button>
<button class="btn btn-sm btn-default link" type="button" title="[[topic:link]]"><i class="icon-link"></i></button>
<button class="btn btn-sm btn-default edit {main_posts.display_moderator_tools}" type="button" title="[[topic:edit]]"><i class="icon-pencil"></i></button>
<button class="btn btn-sm btn-default delete {main_posts.display_moderator_tools}" type="button" title="[[topic:delete]]"><i class="icon-trash"></i></button>
</div>
@ -82,7 +82,7 @@
<a href="/user/{posts.userslug}">
<img src="{posts.picture}" align="left" class="img-thumbnail" />
</a>
<span class="label label-danger {posts.show_banned}">banned</span>
<span class="label label-danger {posts.show_banned}">[[topic:banned]]</span>
</div>
<div class="col-md-11">
<div class="post-block">
@ -94,26 +94,26 @@
</button>
<ul class="dropdown-menu">
<li><a href="/user/{posts.userslug}"><i class="icon-user"></i> Profile</a></li>
<li><div class="chat"><i class="icon-comment"></i> Chat</div></li>
<li><a href="/user/{posts.userslug}"><i class="icon-user"></i> [[topic:profile]]</a></li>
<li><div class="chat"><i class="icon-comment"></i> [[topic:chat]]</div></li>
</ul>
</div>
<div class="btn-group">
<button class="favourite btn btn-sm btn-default {posts.fav_button_class}" type="button">
<span class="favourite-text">Favourite</span>
<span class="favourite-text">[[topic:favourite]]</span>
<span class="post_rep_{posts.pid}">{posts.post_rep} </span><i class="{posts.fav_star_class}"></i>
</button>
</div>
<div class="btn-group">
<button class="btn btn-sm btn-default quote" type="button" title="Quote"><i class="icon-quote-left"></i></button>
<button class="btn btn-sm btn-primary btn post_reply" type="button">Reply <i class="icon-reply"></i></button>
<button class="btn btn-sm btn-default quote" type="button" title="[[topic:quote]]"><i class="icon-quote-left"></i></button>
<button class="btn btn-sm btn-primary btn post_reply" type="button">[[topic:reply]] <i class="icon-reply"></i></button>
</div>
<div class="btn-group pull-right post-tools">
<button class="btn btn-sm btn-default link" type="button" title="Link"><i class="icon-link"></i></button>
<button class="btn btn-sm btn-default edit {posts.display_moderator_tools}" type="button" title="Edit"><i class="icon-pencil"></i></button>
<button class="btn btn-sm btn-default delete {posts.display_moderator_tools}" type="button" title="Delete"><i class="icon-trash"></i></button>
<button class="btn btn-sm btn-default link" type="button" title="[[topic:link]]"><i class="icon-link"></i></button>
<button class="btn btn-sm btn-default edit {posts.display_moderator_tools}" type="button" title="[[topic:edit]]"><i class="icon-pencil"></i></button>
<button class="btn btn-sm btn-default delete {posts.display_moderator_tools}" type="button" title="[[topic:delete]]"><i class="icon-trash"></i></button>
</div>
<input id="post_{posts.pid}_link" value="" class="pull-right" style="display:none;"></input>
@ -142,16 +142,16 @@
<hr />
<div class="topic-main-buttons">
<button id="post_reply" class="btn btn-primary btn-lg post_reply" type="button">Reply</button>
<button id="post_reply" class="btn btn-primary btn-lg post_reply" type="button">[[topic:reply]]</button>
<div class="btn-group pull-right" id="thread-tools" style="visibility: hidden;">
<button class="btn btn-default btn-lg dropdown-toggle" data-toggle="dropdown" type="button">Thread Tools <span class="caret"></span></button>
<button class="btn btn-default btn-lg dropdown-toggle" data-toggle="dropdown" type="button">[[topic:thread_tools.title]] <span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a href="#" id="pin_thread"><i class="icon-pushpin"></i> Pin Thread</a></li>
<li><a href="#" id="lock_thread"><i class="icon-lock"></i> Lock Thread</a></li>
<li><a href="#" id="pin_thread"><i class="icon-pushpin"></i> [[topic:thread_tools.pin]]</a></li>
<li><a href="#" id="lock_thread"><i class="icon-lock"></i> [[topic:thread_tools.lock]]</a></li>
<li class="divider"></li>
<li><a href="#" id="move_thread"><i class="icon-move"></i> Move Thread</a></li>
<li><a href="#" id="move_thread"><i class="icon-move"></i> [[topic:thread_tools.move]]</a></li>
<li class="divider"></li>
<li><a href="#" id="delete_thread"><span class="text-error"><i class="icon-trash"></i> Delete Thread</span></a></li>
<li><a href="#" id="delete_thread"><span class="text-error"><i class="icon-trash"></i> [[topic:thread_tools.delete]]</span></a></li>
</ul>
</div>
</div>
@ -175,7 +175,7 @@
<h3>Move Thread</h3>
</div>
<div class="modal-body">
<p id="categories-loading"><i class="icon-spin icon-refresh"></i> Loading Categories</p>
<p id="categories-loading"><i class="icon-spin icon-refresh"></i> [[topic:load_categories]]</p>
<ul class="category-list"></ul>
<div id="move-confirm" style="display: none;">
<hr />
@ -183,8 +183,8 @@
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" id="move_thread_cancel">Close</a>
<button type="button" class="btn btn-primary" id="move_thread_commit" disabled>Move</a>
<button type="button" class="btn btn-default" data-dismiss="modal" id="move_thread_cancel">[[global:buttons.close]]</a>
<button type="button" class="btn btn-primary" id="move_thread_commit" disabled>[[topic:confirm_move]]</a>
</div>
</div>
</div>

@ -1,6 +1,6 @@
<div class="unread">
<ol class="breadcrumb">
<li><a href="/">Home</a></li>
<li><a href="/">[[global:home]]</a></li>
<li class="active">{category_name}</li>
<div id="category_active_users"></div>
</ol>
@ -10,10 +10,10 @@
</a>
<div class="alert alert-warning {no_topics_message}" id="category-no-topics">
<strong>There are no unread topics.</strong>
<strong>[[unread:no_unread_topics]]</strong>
</div>
<button id="mark-allread-btn" class="btn btn-primary {show_markallread_button}">Mark all as Read</button>
<button id="mark-allread-btn" class="btn btn-primary {show_markallread_button}">[[unread:mark_all_read]]</button>
<div class="category row">
<div class="{topic_row_size}">
@ -45,7 +45,7 @@
</a>
<!-- END topics -->
</ul>
<button id="load-more-btn" class="btn btn-primary hide">Load More</button>
<button id="load-more-btn" class="btn btn-primary hide">[[unread:load_more]]</button>
</div>
</div>
</div>

@ -1,17 +1,17 @@
<div class="users">
<ul class="nav nav-pills">
<li class=''><a href='/users/latest'>Latest Users</a></li>
<li class=''><a href='/users/sort-posts'>Top Posters</a></li>
<li class=''><a href='/users/sort-reputation'>Most Reputation</a></li>
<li class=''><a href='/users/online'>Online</a></li>
<li class=''><a href='/users/search'>Search</a></li>
<li class=''><a href='/users/latest'>[[users:latest_users]]</a></li>
<li class=''><a href='/users/sort-posts'>[[users:top_posters]]</a></li>
<li class=''><a href='/users/sort-reputation'>[[users:most_reputation]]</a></li>
<li class=''><a href='/users/online'>[[users:online]]</a></li>
<li class=''><a href='/users/search'>[[users:search]]</a></li>
</ul>
<br />
<div class="search {search_display} well">
<div class="input-group">
<input class="form-control" id="search-user" type="text" placeholder="Enter a username to search"/>
<input class="form-control" id="search-user" type="text" placeholder="[[users:enter_username]]"/>
<span class="input-group-addon">
<span id="user-notfound-notify"><i class="icon icon-circle-blank"></i></span>
</span>
@ -42,7 +42,7 @@
</ul>
<div class="text-center {loadmore_display}">
<button id="load-more-users-btn" class="btn btn-primary">Load More</button>
<button id="load-more-users-btn" class="btn btn-primary">[[users:load_more]]</button>
</div>
</div>

@ -1,16 +1,22 @@
var RDB = require('./redis.js'),
posts = require('./posts.js'),
user = require('./user.js');
user = require('./user.js'),
translator = require('./../public/src/translator.js');
(function (Favourites) {
"use strict";
Favourites.favourite = function (pid, room_id, uid, socket) {
if (uid === 0) {
var not_logged_in = {
message: translator.get('topic:favourites.not_logged_in.message'),
title: translator.get('topic:favourites.not_logged_in.title')
};
socket.emit('event:alert', {
alert_id: 'post_favourite',
title: 'Not Logged In',
message: 'Please log in in order to favourite this post',
title: not_logged_in.title,
message: not_logged_in.message,
type: 'danger',
timeout: 5000
});
@ -50,13 +56,6 @@ var RDB = require('./redis.js'),
Favourites.unfavourite = function (pid, room_id, uid, socket) {
if (uid === 0) {
socket.emit('event:alert', {
alert_id: 'post_favourite',
title: 'Not Logged In',
message: 'Please log in in order to favourite this post',
type: 'danger',
timeout: 5000
});
return;
}

@ -158,6 +158,7 @@ var utils = require('./../public/src/utils.js'),
'vendor/bootbox/bootbox.min.js',
'src/templates.js',
'src/ajaxify.js',
'src/translator.js',
'src/jquery.form.js',
'src/utils.js'
],
@ -222,4 +223,26 @@ var utils = require('./../public/src/utils.js'),
});
}
};
Meta.db = {
getFile: function (callback) {
var multi = RDB.multi();
multi.config('get', 'dir');
multi.config('get', 'dbfilename');
multi.exec(function (err, results) {
if (err) {
return callback(err);
} else {
results = results.reduce(function (memo, config) {
memo[config[0]] = config[1];
return memo;
}, {});
var dbFile = path.join(results.dir, results.dbfilename);
callback(null, dbFile);
}
});
}
};
}(exports));

@ -4,9 +4,11 @@ var user = require('./../user.js'),
RDB = require('./../redis.js'),
pkg = require('./../../package.json'),
categories = require('./../categories.js'),
Meta = require('../meta'),
plugins = require('../plugins'),
winston = require('winston'),
nconf = require('nconf');
nconf = require('nconf'),
fs = require('fs');
(function (Admin) {
Admin.isAdmin = function (req, res, next) {
@ -153,31 +155,55 @@ var user = require('./../user.js'),
});
});
app.get('/redis', function (req, res) {
RDB.info(function (err, data) {
data = data.split("\r\n");
var finalData = {};
app.namespace('/redis', function () {
app.get('/', function (req, res) {
RDB.info(function (err, data) {
data = data.split("\r\n");
var finalData = {};
for (var i in data) {
for (var i in data) {
if (data[i].indexOf(':') == -1 || !data[i])
continue;
if (data[i].indexOf(':') == -1 || !data[i])
continue;
try {
data[i] = data[i].replace(/:/, "\":\"");
var json = "{\"" + data[i] + "\"}";
try {
data[i] = data[i].replace(/:/, "\":\"");
var json = "{\"" + data[i] + "\"}";
var jsonObject = JSON.parse(json);
for (var key in jsonObject) {
finalData[key] = jsonObject[key];
var jsonObject = JSON.parse(json);
for (var key in jsonObject) {
finalData[key] = jsonObject[key];
}
} catch (err) {
winston.warn('can\'t parse redis status variable, ignoring', i, data[i], err);
}
} catch (err) {
winston.warn('can\'t parse redis status variable, ignoring', i, data[i], err);
}
}
res.json(finalData);
res.json(finalData);
});
});
// app.get('/export', Admin.isAdmin, function (req, res) {
// Meta.db.getFile(function (err, dbFile) {
// if (!err) {
// res.download(dbFile, 'redis.rdb', function (err) {
// console.log(err);
// res.send(500);
// if (err) {
// res.send(500);
// switch (err.code) {
// case 'EACCES':
// res.send(500, 'Require permissions from Redis database file: ', dbFile);
// break;
// default:
// res.send(500);
// break;
// }
// }
// });
// } else res.send(500);
// });
// });
});
app.get('/plugins', function (req, res) {

@ -66,7 +66,9 @@ var express = require('express'),
clientScripts: clientScripts
};
callback(null, templates.header.parse(templateValues));
translator.translate(templates.header.parse(templateValues), function(template) {
callback(null, template);
});
};
// Middlewares
@ -123,6 +125,15 @@ var express = require('express'),
module.exports.init = function () {
templates = global.templates;
// translate all static templates served by webserver here. ex. footer, logout
translator.translate(templates['footer'].toString(), function(parsedTemplate) {
templates['footer'] = parsedTemplate;
});
translator.translate(templates['logout'].toString(), function(parsedTemplate) {
templates['logout'] = parsedTemplate;
});
server.listen(nconf.get('PORT') || nconf.get('port'));
}

Loading…
Cancel
Save