diff --git a/public/src/forum/recent.js b/public/src/forum/recent.js
index 84d22ea8b8..44a078a278 100644
--- a/public/src/forum/recent.js
+++ b/public/src/forum/recent.js
@@ -47,20 +47,6 @@
++newPostCount;
updateAlertText();
});
-
- $('#mark-allread-btn').on('click', function() {
- var btn = $(this);
- socket.emit('api:topics.markAllRead', {} , function(success) {
- if(success) {
- btn.remove();
- $('#topics-container').empty();
- $('#category-no-topics').removeClass('hidden');
- app.alertSuccess('All topics marked as read!');
- } else {
- app.alertError('There was an error marking topics read!');
- }
- });
- });
function onTopicsLoaded(topics) {
diff --git a/public/src/forum/unread.js b/public/src/forum/unread.js
new file mode 100644
index 0000000000..8b2342df36
--- /dev/null
+++ b/public/src/forum/unread.js
@@ -0,0 +1,103 @@
+(function() {
+ var loadingMoreTopics = false;
+
+ app.enter_room('recent_posts');
+
+ ajaxify.register_events([
+ 'event:new_topic',
+ 'event:new_post'
+ ]);
+
+ var newTopicCount = 0, newPostCount = 0;
+
+ $('#new-topics-alert').on('click', function() {
+ $(this).hide();
+ });
+
+ socket.on('event:new_topic', function(data) {
+
+ ++newTopicCount;
+ updateAlertText();
+
+ });
+
+ function updateAlertText() {
+ var text = '';
+
+ if(newTopicCount > 1)
+ text = 'There are ' + newTopicCount + ' new topics';
+ else if(newTopicCount === 1)
+ text = 'There is 1 new topic';
+ else
+ text = 'There are no new topics';
+
+ if(newPostCount > 1)
+ text += ' and ' + newPostCount + ' new posts.';
+ else if(newPostCount === 1)
+ text += ' and 1 new post.';
+ else
+ text += ' and no new posts.';
+
+ text += ' Click here to reload.';
+
+ $('#new-topics-alert').html(text).fadeIn('slow');
+ }
+
+ socket.on('event:new_post', function(data) {
+ ++newPostCount;
+ updateAlertText();
+ });
+
+ $('#mark-allread-btn').on('click', function() {
+ var btn = $(this);
+ socket.emit('api:topics.markAllRead', {} , function(success) {
+ if(success) {
+ btn.remove();
+ $('#topics-container').empty();
+ $('#category-no-topics').removeClass('hidden');
+ app.alertSuccess('All topics marked as read!');
+ } else {
+ app.alertError('There was an error marking topics read!');
+ }
+ });
+ });
+
+ function onTopicsLoaded(topics) {
+
+ var html = templates.prepare(templates['unread'].blocks['topics']).parse({ topics: topics }),
+ container = $('#topics-container');
+
+ $('#category-no-topics').remove();
+
+ container.append(html);
+ }
+
+ function loadMoreTopics() {
+ loadingMoreTopics = true;
+ socket.emit('api:topics.loadMoreUnreadTopics', {after:parseInt($('#topics-container').attr('data-next-start'), 10)}, function(data) {
+ if(data.topics && data.topics.length) {
+ onTopicsLoaded(data.topics);
+ $('#topics-container').attr('data-next-start', data.nextStart);
+ }
+ loadingMoreTopics = false;
+ });
+ }
+
+ $(window).off('scroll').on('scroll', function() {
+ var windowHeight = document.body.offsetHeight - $(window).height(),
+ half = windowHeight / 2;
+
+ if (document.body.scrollTop > half && !loadingMoreTopics) {
+ loadMoreTopics();
+ }
+ });
+
+
+ if($("body").height() <= $(window).height() && $('#topics-container').children().length)
+ $('#load-more-btn').show();
+
+ $('#load-more-btn').on('click', function() {
+ loadMoreTopics();
+ });
+
+})();
\ No newline at end of file
diff --git a/public/templates/unread.tpl b/public/templates/unread.tpl
index a44d30aa1b..7e4481aeac 100644
--- a/public/templates/unread.tpl
+++ b/public/templates/unread.tpl
@@ -21,7 +21,7 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/posts.js b/src/posts.js
index 0a2bcd1cab..9a0dda28e4 100644
--- a/src/posts.js
+++ b/src/posts.js
@@ -178,34 +178,30 @@ var RDB = require('./redis.js'),
alert_id: 'post_error'
});
}
+
+ Posts.emitTooManyPostsAlert = function(socket) {
+ socket.emit('event:alert', {
+ title: 'Too many posts!',
+ message: 'You can only post every '+ (config.post_delay / 1000) + ' seconds.',
+ type: 'error',
+ timeout: 2000
+ });
+ }
- Posts.reply = function(socket, tid, uid, content, images) {
+ Posts.reply = function(tid, uid, content, images, callback) {
if(content) {
content = content.trim();
}
- if (uid < 1) {
- socket.emit('event:alert', {
- title: 'Reply Unsuccessful',
- message: 'You don't seem to be logged in, so you cannot reply.',
- type: 'error',
- timeout: 2000
- });
- return;
- } else if (!content || content.length < Posts.minimumPostLength) {
- Posts.emitContentTooShortAlert(socket);
+ if (!content || content.length < Posts.minimumPostLength) {
+ callback(new Error('content-too-short'), null);
return;
}
user.getUserField(uid, 'lastposttime', function(lastposttime) {
if(Date.now() - lastposttime < config.post_delay) {
- socket.emit('event:alert', {
- title: 'Too many posts!',
- message: 'You can only post every '+ (config.post_delay / 1000) + ' seconds.',
- type: 'error',
- timeout: 2000
- });
+ callback(new Error('too-many-posts'), null);
return;
}
@@ -221,18 +217,8 @@ var RDB = require('./redis.js'),
});
});
- Posts.getTopicPostStats(socket);
-
- // Send notifications to users who are following this topic
threadTools.notify_followers(tid, uid);
- socket.emit('event:alert', {
- title: 'Reply Successful',
- message: 'You have successfully replied. Click here to view your reply.',
- type: 'notify',
- timeout: 2000
- });
-
postData.content = postTools.markdownToHTML(postData.content);
postData.post_rep = 0;
postData.relativeTime = utils.relativeTime(postData.timestamp)
@@ -251,14 +237,9 @@ var RDB = require('./redis.js'),
io.sockets.in('recent_posts').emit('event:new_post', socketData);
});
-
+ callback(null, 'Reply successful');
} else {
- socket.emit('event:alert', {
- title: 'Reply Unsuccessful',
- message: 'Your reply could not be posted at this time. Please try again later.',
- type: 'notify',
- timeout: 2000
- });
+ callback(new Error('reply-error'), null);
}
});
});
diff --git a/src/routes/api.js b/src/routes/api.js
index a47a7a35ca..0414b1570f 100644
--- a/src/routes/api.js
+++ b/src/routes/api.js
@@ -115,7 +115,7 @@ var user = require('./../user.js'),
app.get('/api/unread', function(req, res) {
var uid = (req.user) ? req.user.uid : 0;
- topics.getUnreadTopics(uid, 0, -1, function(data) {
+ topics.getUnreadTopics(uid, 0, 19, function(data) {
res.json(data);
});
});
diff --git a/src/topics.js b/src/topics.js
index 3d3ba5bf86..6730ee00ac 100644
--- a/src/topics.js
+++ b/src/topics.js
@@ -148,6 +148,7 @@ marked.setOptions({
function sendUnreadTopics(topicIds) {
Topics.getTopicsByTids(topicIds, uid, function(topicData) {
unreadTopics.topics = topicData;
+ unreadTopics.nextStart = start + tids.length;
callback(unreadTopics);
});
}
@@ -532,7 +533,7 @@ marked.setOptions({
});
}
- Topics.post = function(socket, uid, title, content, category_id, images) {
+ Topics.post = function(uid, title, content, category_id, images, callback) {
if (!category_id)
throw new Error('Attempted to post without a category_id');
@@ -542,33 +543,20 @@ marked.setOptions({
title = title.trim();
if (uid === 0) {
- socket.emit('event:alert', {
- title: 'Thank you for posting',
- message: 'Since you are unregistered, your post is awaiting approval. Click here to register now.',
- type: 'warning',
- timeout: 7500,
- clickfn: function() {
- ajaxify.go('register');
- }
- });
- return; // for now, until anon code is written.
+ callback(new Error('not-logged-in'), null);
+ return;
} else if(!title || title.length < Topics.minimumTitleLength) {
- Topics.emitTitleTooShortAlert(socket);
+ callback(new Error('title-too-short'), null);
return;
} else if (!content || content.length < posts.miminumPostLength) {
- posts.emitContentTooShortAlert(socket);
+ callback(new Error('content-too-short'), null);
return;
}
user.getUserField(uid, 'lastposttime', function(lastposttime) {
if(Date.now() - lastposttime < config.post_delay) {
- socket.emit('event:alert', {
- title: 'Too many posts!',
- message: 'You can only post every '+ (config.post_delay / 1000) + ' seconds.',
- type: 'error',
- timeout: 2000
- });
+ callback(new Error('too-many-posts'), null);
return;
}
@@ -604,23 +592,6 @@ marked.setOptions({
topicSearch.index(title, tid);
RDB.set('topicslug:' + slug + ':tid', tid);
- posts.create(uid, tid, content, images, function(postData) {
- if (postData) {
- RDB.lpush(schema.topics(tid).posts, postData.pid);
-
- // Auto-subscribe the post creator to the newly created topic
- threadTools.toggleFollow(tid, uid);
-
- // Notify any users looking at the category that a new topic has arrived
- Topics.getTopicForCategoryView(tid, uid, function(topicData) {
- io.sockets.in('category_' + category_id).emit('event:new_topic', topicData);
- io.sockets.in('recent_posts').emit('event:new_topic', topicData);
- });
-
- posts.getTopicPostStats(socket);
- }
- });
-
user.addTopicIdToUser(uid, tid);
// let everyone know that there is an unread topic in this category
@@ -636,11 +607,21 @@ marked.setOptions({
feed.updateCategory(category_id);
- socket.emit('event:alert', {
- title: 'Thank you for posting',
- message: 'You have successfully posted. Click here to view your post.',
- type: 'notify',
- timeout: 2000
+ posts.create(uid, tid, content, images, function(postData) {
+ if (postData) {
+ RDB.lpush(schema.topics(tid).posts, postData.pid);
+
+ // Auto-subscribe the post creator to the newly created topic
+ threadTools.toggleFollow(tid, uid);
+
+ // Notify any users looking at the category that a new topic has arrived
+ Topics.getTopicForCategoryView(tid, uid, function(topicData) {
+ io.sockets.in('category_' + category_id).emit('event:new_topic', topicData);
+ io.sockets.in('recent_posts').emit('event:new_topic', topicData);
+ });
+
+ callback(null, postData);
+ }
});
});
});
diff --git a/src/webserver.js b/src/webserver.js
index aa2be7a669..379bec362f 100644
--- a/src/webserver.js
+++ b/src/webserver.js
@@ -400,6 +400,7 @@ var express = require('express'),
}
});
});
+
});
}(WebServer));
diff --git a/src/websockets.js b/src/websockets.js
index f7dc80c28b..57b6e1973f 100644
--- a/src/websockets.js
+++ b/src/websockets.js
@@ -304,7 +304,41 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
});
socket.on('api:topics.post', function(data) {
- topics.post(socket, uid, data.title, data.content, data.category_id, data.images);
+
+ topics.post(uid, data.title, data.content, data.category_id, data.images, function(err, result) {
+ if(err) {
+ if(err.message === 'not-logged-in') {
+ socket.emit('event:alert', {
+ title: 'Thank you for posting',
+ message: 'Since you are unregistered, your post is awaiting approval. Click here to register now.',
+ type: 'warning',
+ timeout: 7500,
+ clickfn: function() {
+ ajaxify.go('register');
+ }
+ });
+ } else if(err.message === 'title-too-short') {
+ topics.emitTitleTooShortAlert(socket);
+ } else if(err.message === 'content-too-short') {
+ posts.emitContentTooShortAlert(socket);
+ } else if (err.message === 'too-many-posts') {
+ posts.emitTooManyPostsAlert(socket);
+ }
+ return;
+ }
+
+ if(result) {
+ posts.getTopicPostStats(socket);
+
+ socket.emit('event:alert', {
+ title: 'Thank you for posting',
+ message: 'You have successfully posted. Click here to view your post.',
+ type: 'notify',
+ timeout: 2000
+ });
+ }
+ });
+
});
socket.on('api:topics.markAllRead', function(data, callback) {
@@ -318,7 +352,47 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
});
socket.on('api:posts.reply', function(data) {
- posts.reply(socket, data.topic_id, uid, data.content, data.images);
+ if(uid < 1) {
+ socket.emit('event:alert', {
+ title: 'Reply Unsuccessful',
+ message: 'You don't seem to be logged in, so you cannot reply.',
+ type: 'error',
+ timeout: 2000
+ });
+ return;
+ }
+
+ posts.reply(data.topic_id, uid, data.content, data.images, function(err, result) {
+ if(err) {
+ if(err.message === 'content-too-short') {
+ posts.emitContentTooShortAlert(socket);
+ } else if(err.messages === 'too-many-posts') {
+ posts.emitTooManyPostsAlert(socket);
+ } else if(err.message === 'reply-error') {
+ socket.emit('event:alert', {
+ title: 'Reply Unsuccessful',
+ message: 'Your reply could not be posted at this time. Please try again later.',
+ type: 'notify',
+ timeout: 2000
+ });
+ }
+ return;
+ }
+
+ if(result) {
+
+ posts.getTopicPostStats(socket);
+
+ socket.emit('event:alert', {
+ title: 'Reply Successful',
+ message: 'You have successfully replied. Click here to view your reply.',
+ type: 'notify',
+ timeout: 2000
+ });
+
+ }
+
+ });
});
socket.on('api:user.active.get', function() {
@@ -578,6 +652,16 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
callback(latestTopics);
});
});
+
+ socket.on('api:topics.loadMoreUnreadTopics', function(data, callback) {
+ var start = data.after,
+ end = start + 9;
+
+ console.log(start, end);
+ topics.getUnreadTopics(uid, start, end, function(unreadTopics) {
+ callback(unreadTopics);
+ });
+ });
socket.on('api:admin.topics.getMore', function(data) {
topics.getAllTopics(data.limit, data.after, function(topics) {