Merge remote-tracking branch 'origin/master' into webserver.js-refactor

This commit is contained in:
psychobunny
2014-02-28 14:35:00 -05:00
15 changed files with 292 additions and 3093 deletions

View File

@@ -14,10 +14,7 @@ var nconf = require('nconf'),
nbb.on('message', function(cmd) {
if (cmd === 'nodebb:restart') {
nbb.on('exit', function() {
nbb_start();
});
nbb.kill();
nbb_restart();
}
});
},
@@ -29,10 +26,17 @@ var nconf = require('nconf'),
fs.unlinkSync(pidFilePath);
}
}
},
nbb_restart = function() {
nbb.on('exit', function() {
nbb_start();
});
nbb.kill();
};
process.on('SIGINT', nbb_stop);
process.on('SIGTERM', nbb_stop);
process.on('SIGHUP', nbb_restart);
nbb_start();
},

11
nodebb
View File

@@ -9,6 +9,7 @@ case "$1" in
echo "Starting NodeBB";
echo " \"./nodebb stop\" to stop the NodeBB server";
echo " \"./nodebb log\" to view server output";
echo "" > ./logs/output.log;
node loader -d "$@"
;;
@@ -17,7 +18,13 @@ case "$1" in
kill `cat pidfile`;
;;
reload|restart)
echo "Restarting NodeBB.";
kill -1 `cat pidfile`;
;;
log)
clear;
tail -F ./logs/output.log;
;;
@@ -54,11 +61,13 @@ case "$1" in
*)
echo "Welcome to NodeBB"
echo $"Usage: $0 {start|stop|log|setup|reset|upgrade|dev|watch}"
echo $"Usage: $0 {start|stop|reload|restart|log|setup|reset|upgrade|dev|watch}"
echo ''
column -s ' ' -t <<< '
start Start the NodeBB server
stop Stops the NodeBB server
reload Restarts NodeBB
restart Restarts NodeBB
log Opens the logging interface (useful for debugging)
setup Runs the NodeBB setup script
reset Disables all plugins, restores the default theme.

View File

@@ -21,7 +21,9 @@ var ajaxify = {};
window.onpopstate = function (event) {
if (event !== null && event.state && event.state.url !== undefined && !ajaxify.initialLoad) {
ajaxify.go(event.state.url, null, true);
ajaxify.go(event.state.url, function() {
$(window).trigger('action:popstate', {url: event.state.url});
}, true);
}
};
@@ -29,6 +31,7 @@ var ajaxify = {};
ajaxify.initialLoad = false;
ajaxify.go = function (url, callback, quiet) {
// "quiet": If set to true, will not call pushState
app.enterRoom('global');
@@ -101,7 +104,7 @@ var ajaxify = {};
}
});
if (callback) {
if (typeof callback === 'function') {
callback();
}
@@ -129,7 +132,7 @@ var ajaxify = {};
$this.addClass($this.attr('no-widget-class'));
});
}
next(err);
});
}, function(err) {

View File

@@ -448,13 +448,14 @@ var socket,
app.enableInfiniteLoading = function(callback) {
$(window).off('scroll').on('scroll', function() {
var top = $(window).height() * 0.1;
var bottom = ($(document).height() - $(window).height()) * 0.9;
var currentScrollTop = $(window).scrollTop();
if($(window).scrollTop() < top && previousScrollTop > currentScrollTop) {
if(currentScrollTop < top && currentScrollTop < previousScrollTop) {
callback(-1);
} else if ($(window).scrollTop() > bottom && previousScrollTop < currentScrollTop) {
} else if (currentScrollTop > bottom && currentScrollTop > previousScrollTop) {
callback(1);
}
previousScrollTop = currentScrollTop;

View File

@@ -38,13 +38,128 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
socket.on('event:new_topic', Category.onNewTopic);
enableInfiniteLoading();
$('#topics-container').on('click', '.topic-title', function() {
var clickedTid = $(this).parents('li.category-item[data-tid]').attr('data-tid');
$('#topics-container li.category-item').each(function(index, el) {
if($(el).offset().top - $(window).scrollTop() > 0) {
tid = $(el).attr('data-tid');
localStorage.setItem('category:bookmark', tid);
localStorage.setItem('category:bookmark:clicked', clickedTid);
return false;
}
});
});
};
$(window).on('action:popstate', function(ev, data) {
if(data.url.indexOf('category/') === 0) {
var bookmark = localStorage.getItem('category:bookmark');
var clicked = localStorage.getItem('category:bookmark:clicked');
if (bookmark) {
if(config.usePagination) {
socket.emit('topics.getTidPage', bookmark, function(err, page) {
if(err) {
return;
}
if(parseInt(page, 10) !== pagination.currentPage) {
pagination.loadPage(page);
} else {
Category.scrollToTopic(bookmark, clicked, 400);
}
});
} else {
socket.emit('topics.getTidIndex', bookmark, function(err, index) {
if(err) {
return;
}
if(index === 0) {
Category.highlightTopic(clicked);
return;
}
if (index < 0) {
index = 0;
}
$('#topics-container').empty();
loadingMoreTopics = false;
Category.loadMoreTopics(templates.get('category_id'), index, function() {
Category.scrollToTopic(bookmark, clicked, 0);
});
});
}
}
}
});
Category.highlightTopic = function(tid) {
var highlight = $('#topics-container li.category-item[data-tid="' + tid + '"]');
if(highlight.length && !highlight.hasClass('highlight')) {
highlight.addClass('highlight');
setTimeout(function() {
highlight.removeClass('highlight');
}, 5000);
}
};
Category.scrollToTopic = function(tid, clickedTid, duration, offset) {
if(!tid) {
return;
}
if(!offset) {
offset = 0;
}
if($('#topics-container li.category-item[data-tid="' + tid + '"]').length) {
var cid = templates.get('category_id');
var scrollTo = $('#topics-container li.category-item[data-tid="' + tid + '"]');
if (cid && scrollTo.length) {
$('html, body').animate({
scrollTop: (scrollTo.offset().top - $('#header-menu').height() - offset) + 'px'
}, duration !== undefined ? duration : 400, function() {
Category.highlightTopic(clickedTid);
});
}
}
};
function enableInfiniteLoading() {
if(!config.usePagination) {
app.enableInfiniteLoading(function() {
if(!loadingMoreTopics) {
Category.loadMoreTopics(templates.get('category_id'));
app.enableInfiniteLoading(function(direction) {
if(!loadingMoreTopics && $('#topics-container').children().length) {
var after = 0;
var el = null;
if(direction > 0) {
el = $('#topics-container .category-item[data-tid]').last();
after = parseInt(el.attr('data-index'), 10) + 1;
} else {
el = $('#topics-container .category-item[data-tid]').first();
after = parseInt(el.attr('data-index'), 10);
after -= config.topicsPerPage;
if(after < 0) {
after = 0;
}
}
var offset = el.offset().top - $('#header-menu').offset().top + $('#header-menu').height();
Category.loadMoreTopics(templates.get('category_id'), after, function() {
if(direction < 0 && el) {
Category.scrollToTopic(el.attr('data-tid'), null, 0, offset);
}
});
}
});
} else {
@@ -94,56 +209,112 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
$(window).trigger('action:categories.new_topic.loaded');
});
}
};
Category.onTopicsLoaded = function(topics, callback) {
if(!topics || !topics.length) {
return;
}
function removeAlreadyAddedTopics() {
topics = topics.filter(function(topic) {
return $('#topics-container li[data-tid="' + topic.tid +'"]').length === 0;
});
}
var after = null,
before = null;
function findInsertionPoint() {
if (!$('#topics-container .category-item[data-tid]').length) {
return;
}
var last = $('#topics-container .category-item[data-tid]').last();
var lastIndex = last.attr('data-index');
var firstIndex = topics[topics.length - 1].index;
if (firstIndex > lastIndex) {
after = last;
} else {
before = $('#topics-container .category-item[data-tid]').first();
}
}
removeAlreadyAddedTopics();
if(!topics.length) {
return;
}
findInsertionPoint();
Category.onTopicsLoaded = function(topics) {
var html = templates.prepare(templates['category'].blocks['topics']).parse({
topics: topics
});
translator.translate(html, function(translatedHTML) {
var container = $('#topics-container');
var container = $('#topics-container'),
html = $(translatedHTML);
$('#topics-container, .category-sidebar').removeClass('hidden');
$('#category-no-topics').remove();
html = $(translatedHTML);
if(config.usePagination) {
container.empty().append(html);
} else {
container.append(html);
if(after) {
html.insertAfter(after);
} else if(before) {
html.insertBefore(before);
} else {
container.append(html);
}
}
$('#topics-container span.timeago').timeago();
app.createUserTooltips();
app.makeNumbersHumanReadable(html.find('.human-readable-number'));
});
}
Category.loadMoreTopics = function(cid) {
if (typeof callback === 'function') {
callback(topics);
}
});
};
Category.loadMoreTopics = function(cid, after, callback) {
if (loadingMoreTopics || !$('#topics-container').length) {
return;
}
if(after === 0 && $('#topics-container li.category-item[data-index="0"]').length) {
return;
}
$(window).trigger('action:categories.loading');
loadingMoreTopics = true;
socket.emit('categories.loadMore', {
cid: cid,
after: $('#topics-container').attr('data-nextstart')
after: after
}, function (err, data) {
loadingMoreTopics = false;
if(err) {
return app.alertError(err.message);
}
if (data && data.topics.length) {
Category.onTopicsLoaded(data.topics);
Category.onTopicsLoaded(data.topics, callback);
$('#topics-container').attr('data-nextstart', data.nextStart);
} else {
if (typeof callback === 'function') {
callback(data.topics);
}
}
loadingMoreTopics = false;
$(window).trigger('action:categories.loaded');
});
}
};
return Category;
});

View File

@@ -1027,14 +1027,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
}
$('#pagination').html(index + ' out of ' + Topic.postCount);
$('.progress-bar').width((index / Topic.postCount * 100) + '%');
return false;
}
});
$('.posts > .post-row').each(function() {
var el = $(this);
if (elementInView(el)) {
if(!parseInt(el.attr('data-index'), 10)) {
localStorage.removeItem('topic:' + templates.get('topic_id') + ':bookmark');
} else {
@@ -1063,7 +1056,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
var elTop = el.offset().top;
var elBottom = elTop + Math.floor(el.height());
return !(elTop > scrollBottom || elBottom < scrollTop);
return (elTop >= scrollTop && elBottom <= scrollBottom) || (elTop <= scrollTop && elBottom >= scrollTop);
}
Topic.scrollToPost = function(pid, highlight, duration, offset) {

View File

@@ -20,9 +20,7 @@
<ul id="users-container" class="users admin">
<!-- BEGIN users -->
<div class="users-box" data-uid="{users.uid}" data-admin="{users.administrator}" data-username="{users.username}" data-banned="{users.banned}">
<a href="{relative_path}/user/{users.userslug}">
<img src="{users.picture}" class="img-thumbnail"/>
</a>
<a href="{relative_path}/user/{users.userslug}"><img src="{users.picture}" class="img-thumbnail"/></a>
<br/>
<a href="{relative_path}/user/{users.userslug}">{users.username}</a>
<br/>

View File

@@ -39,7 +39,7 @@
<ul id="topics-container" itemscope itemtype="http://www.schema.org/ItemList" data-nextstart="{nextStart}">
<meta itemprop="itemListOrder" content="descending">
<!-- BEGIN topics -->
<li class="category-item <!-- IF topics.deleted -->deleted<!-- ENDIF topics.deleted --><!-- IF topics.unread -->unread<!-- ENDIF topics.unread -->" itemprop="itemListElement">
<li class="category-item <!-- IF topics.deleted -->deleted<!-- ENDIF topics.deleted --><!-- IF topics.unread -->unread<!-- ENDIF topics.unread -->" itemprop="itemListElement" data-tid="{topics.tid}" data-index="{topics.index}">
<div class="col-md-12 col-xs-12 panel panel-default topic-row">

File diff suppressed because one or more lines are too long

View File

@@ -85,11 +85,13 @@ var db = require('./database'),
};
Categories.getCategoryTopics = function(cid, start, stop, uid, callback) {
var tids;
async.waterfall([
function(next) {
Categories.getTopicIds(cid, start, stop, next);
},
function(tids, next) {
function(topicIds, next) {
tids = topicIds;
topics.getTopicsByTids(tids, uid, next);
},
function(topics, next) {
@@ -100,6 +102,15 @@ var db = require('./database'),
});
}
var indices = {};
for(var i=0; i<tids.length; ++i) {
indices[tids[i]] = start + i;
}
for(var i=0; i<topics.length; ++i) {
topics[i].index = indices[topics[i].tid];
}
db.sortedSetRevRank('categories:' + cid + ':tid', topics[topics.length - 1].tid, function(err, rank) {
if(err) {
return next(err);
@@ -118,6 +129,16 @@ var db = require('./database'),
db.getSortedSetRevRange('categories:' + cid + ':tid', start, stop, callback);
};
Categories.getTopicIndex = function(tid, callback) {
topics.getTopicField(tid, 'cid', function(err, cid) {
if(err) {
return callback(err);
}
db.sortedSetRevRank('categories:' + cid + ':tid', tid, callback);
});
};
Categories.getPageCount = function(cid, uid, callback) {
db.sortedSetCard('categories:' + cid + ':tid', function(err, topicCount) {
if(err) {

View File

@@ -1,3 +1,5 @@
'use strict';
var db = require('./database'),
utils = require('./../public/src/utils'),
user = require('./user'),
@@ -43,7 +45,7 @@ var db = require('./database'),
},
function(pid, next) {
plugins.fireHook('filter:post.save', content, function(err, newContent) {
next(err, pid, newContent)
next(err, pid, newContent);
});
},
function(pid, newContent, next) {
@@ -62,7 +64,7 @@ var db = require('./database'),
};
if (toPid) {
postData['toPid'] = toPid;
postData.toPid = toPid;
}
db.setObject('post:' + pid, postData, function(err) {
@@ -196,7 +198,7 @@ var db = require('./database'),
db.sortedSetRevRank('uid:' + uid + ':posts', posts[posts.length - 1].pid, function(err, rank) {
if(err) {
return calllback(err);
return callback(err);
}
var userPosts = {
posts: posts,
@@ -207,7 +209,7 @@ var db = require('./database'),
});
});
});
}
};
Posts.addUserInfoToPost = function(post, callback) {
user.getUserFields(post.uid, ['username', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned'], function(err, userData) {
@@ -299,7 +301,7 @@ var db = require('./database'),
postData.title = validator.escape(topicData.title);
postData.topicSlug = topicData.slug;
next(null, postData);
})
});
});
},
function(postData, next) {
@@ -404,7 +406,7 @@ var db = require('./database'),
}
});
});
}
};
Posts.uploadPostImage = function(image, callback) {
@@ -418,7 +420,7 @@ var db = require('./database'),
callback(new Error('Uploads are disabled!'));
}
}
}
};
Posts.uploadPostFile = function(file, callback) {
@@ -450,9 +452,8 @@ var db = require('./database'),
});
});
}
}
};
// this function should really be called User.getFavouritePosts
Posts.getFavourites = function(uid, start, end, callback) {
db.getSortedSetRevRange('uid:' + uid + ':favourites', start, end, function(err, pids) {
if (err) {
@@ -470,7 +471,7 @@ var db = require('./database'),
db.sortedSetRevRank('uid:' + uid + ':favourites', posts[posts.length - 1].pid, function(err, rank) {
if(err) {
return calllback(err);
return callback(err);
}
var favourites = {
posts: posts,
@@ -480,28 +481,20 @@ var db = require('./database'),
});
});
});
}
};
Posts.getPidPage = function(pid, uid, callback) {
if(!pid) {
return callback(new Error('invalid-pid'));
}
var index = 0;
async.waterfall([
function(next) {
Posts.getPostField(pid, 'tid', next);
Posts.getPidIndex(pid, next);
},
function(tid, next) {
topics.getPids(tid, next);
},
function(pids, next) {
index = pids.indexOf(pid.toString());
if(index === -1) {
return next(new Error('pid not found'));
}
next();
},
function(next) {
function(result, next) {
index = result;
user.getSettings(uid, next);
},
function(settings, next) {
@@ -518,6 +511,6 @@ var db = require('./database'),
db.sortedSetRank('tid:' + tid + ':posts', pid, callback);
});
}
};
}(exports));

View File

@@ -120,7 +120,7 @@ SocketAdmin.categories.create = function(socket, data, callback) {
SocketAdmin.categories.update = function(socket, data) {
if(!data) {
return callback(new Error('invalid data'));
throw new Error('invalid data');
}
admin.categories.update(data, socket);
@@ -380,4 +380,4 @@ SocketAdmin.groups.update = function(socket, data, callback) {
});
};
module.exports = SocketAdmin;
module.exports = SocketAdmin;

View File

@@ -243,11 +243,11 @@ SocketPosts.getFavouritedUsers = function(socket, pid, callback) {
SocketPosts.getPidPage = function(socket, pid, callback) {
posts.getPidPage(pid, socket.uid, callback);
}
};
SocketPosts.getPidIndex = function(socket, pid, callback) {
posts.getPidIndex(pid, callback);
}
};
SocketPosts.flag = function(socket, pid, callback) {
if (!socket.uid) {

View File

@@ -1,4 +1,5 @@
var topics = require('../topics'),
categories = require('../categories'),
threadTools = require('../threadTools'),
index = require('./index'),
user = require('../user'),
@@ -291,9 +292,16 @@ SocketTopics.loadMoreFromSet = function(socket, data, callback) {
topics.getTopicsFromSet(socket.uid, data.set, start, end, callback);
};
SocketTopics.getPageCount = function(socket, tid, callback) {
topics.getPageCount(tid, socket.uid, callback);
};
SocketTopics.getTidPage = function(socket, tid, callback) {
topics.getTidPage(tid, socket.uid, callback);
};
SocketTopics.getTidIndex = function(socket, tid, callback) {
categories.getTopicIndex(tid, callback);
};
module.exports = SocketTopics;

View File

@@ -426,6 +426,26 @@ var async = require('async'),
});
};
Topics.getTidPage = function(tid, uid, callback) {
if(!tid) {
return callback(new Error('invalid-tid'));
}
async.parallel({
index: function(next) {
categories.getTopicIndex(tid, next);
},
settings: function(next) {
user.getSettings(uid, next);
}
}, function(err, results) {
if(err) {
return callback(err);
}
callback(null, Math.ceil((results.index + 1) / results.settings.topicsPerPage));
});
};
Topics.getCategoryData = function(tid, callback) {
Topics.getTopicField(tid, 'cid', function(err, cid) {
if(err) {