mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-01-01 21:30:30 +01:00
Merge branch 'master' of github.com:designcreateplay/NodeBB
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
"header.admin": "Admin",
|
||||
"header.recent": "Recent",
|
||||
"header.unread": "Unread",
|
||||
"header.popular": "Popular",
|
||||
"header.users": "Users",
|
||||
"header.chats": "Chats",
|
||||
"header.notifications": "Notifications",
|
||||
@@ -47,5 +48,8 @@
|
||||
"alert.banned.message": "You are banned you will be logged out!",
|
||||
|
||||
"alert.unfollow": "You are no longer following %1!",
|
||||
"alert.follow": "You are now following %1!"
|
||||
"alert.follow": "You are now following %1!",
|
||||
|
||||
"posts": "Posts",
|
||||
"views": "Views"
|
||||
}
|
||||
|
||||
46
public/src/forum/popular.js
Normal file
46
public/src/forum/popular.js
Normal file
@@ -0,0 +1,46 @@
|
||||
define(['forum/recent'], function(recent) {
|
||||
var Popular = {},
|
||||
loadingMoreTopics = false,
|
||||
active = '';
|
||||
|
||||
Popular.init = function() {
|
||||
app.enterRoom('recent_posts');
|
||||
|
||||
$('#new-topics-alert').on('click', function() {
|
||||
$(this).addClass('hide');
|
||||
});
|
||||
|
||||
recent.watchForNewPosts();
|
||||
|
||||
active = recent.selectActivePill();
|
||||
|
||||
app.enableInfiniteLoading(function() {
|
||||
if(!loadingMoreTopics) {
|
||||
loadMoreTopics();
|
||||
}
|
||||
});
|
||||
|
||||
function loadMoreTopics() {
|
||||
loadingMoreTopics = true;
|
||||
socket.emit('topics.loadMoreFromSet', {
|
||||
set: 'topics:' + $('.nav-pills .active a').html().toLowerCase(),
|
||||
after: $('#topics-container').attr('data-nextstart')
|
||||
}, function(err, data) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
if (data.topics && data.topics.length) {
|
||||
recent.onTopicsLoaded('popular', data.topics);
|
||||
$('#topics-container').attr('data-nextstart', data.nextStart);
|
||||
} else {
|
||||
$('#load-more-btn').hide();
|
||||
}
|
||||
|
||||
loadingMoreTopics = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return Popular;
|
||||
});
|
||||
@@ -7,27 +7,21 @@ define(function() {
|
||||
|
||||
var active = '';
|
||||
|
||||
function getActiveSection() {
|
||||
var url = window.location.href,
|
||||
parts = url.split('/'),
|
||||
active = parts[parts.length - 1];
|
||||
return active;
|
||||
}
|
||||
|
||||
Recent.init = function() {
|
||||
app.enterRoom('recent_posts');
|
||||
|
||||
Recent.watchForNewPosts();
|
||||
|
||||
function getActiveSection() {
|
||||
var url = window.location.href,
|
||||
parts = url.split('/'),
|
||||
active = parts[parts.length - 1];
|
||||
return active;
|
||||
}
|
||||
|
||||
active = getActiveSection();
|
||||
active = Recent.selectActivePill();
|
||||
|
||||
jQuery('.nav-pills li').removeClass('active');
|
||||
jQuery('.nav-pills li a').each(function() {
|
||||
if (this.getAttribute('href').match(active)) {
|
||||
jQuery(this.parentNode).addClass('active');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
$('#new-topics-alert').on('click', function() {
|
||||
$(this).addClass('hide');
|
||||
@@ -41,6 +35,20 @@ define(function() {
|
||||
});
|
||||
};
|
||||
|
||||
Recent.selectActivePill = function() {
|
||||
var active = getActiveSection();
|
||||
|
||||
jQuery('.nav-pills li').removeClass('active');
|
||||
jQuery('.nav-pills li a').each(function() {
|
||||
if (this.getAttribute('href').match(active)) {
|
||||
jQuery(this.parentNode).addClass('active');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return active;
|
||||
}
|
||||
|
||||
Recent.watchForNewPosts = function () {
|
||||
|
||||
newPostCount = 0;
|
||||
|
||||
@@ -57,11 +57,14 @@
|
||||
|
||||
<div class="navbar-collapse collapse navbar-ex1-collapse">
|
||||
<ul id="main-nav" class="nav navbar-nav">
|
||||
<li class="nodebb-loggedin">
|
||||
<a href="{relative_path}/unread"><i id="unread-count" class="fa fa-fw fa-inbox" data-content="0" title="[[global:header.unread]]"></i><span class="visible-xs-inline"> [[global:header.unread]]</span></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{relative_path}/recent"><i class="fa fa-fw fa-clock-o" title="[[global:header.recent]]"></i><span class="visible-xs-inline"> [[global:header.recent]]</span></a>
|
||||
</li>
|
||||
<li class="nodebb-loggedin">
|
||||
<a href="{relative_path}/unread"><i id="unread-count" class="fa fa-fw fa-inbox" data-content="0" title="[[global:header.unread]]"></i><span class="visible-xs-inline"> [[global:header.unread]]</span></a>
|
||||
<li>
|
||||
<a href="{relative_path}/popular"><i class="fa fa-fw fa-fire" title="[[global:header.popular]]"></i><span class="visible-xs-inline"> [[global:header.popular]]</span></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{relative_path}/users"><i class="fa fa-fw fa-users" title="[[global:header.users]]"></i><span class="visible-xs-inline"> [[global:header.users]]</span></a>
|
||||
|
||||
84
public/templates/popular.tpl
Normal file
84
public/templates/popular.tpl
Normal file
@@ -0,0 +1,84 @@
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="{relative_path}/">Home</a></li>
|
||||
<li class="active">[[global:header.popular]] <a href="{relative_path}/popular.rss"><i class="fa fa-rss-square"></i></a></li>
|
||||
</ol>
|
||||
|
||||
<ul class="nav nav-pills">
|
||||
<li class=''><a href='{relative_path}/popular/posts'>[[global:posts]]</a></li>
|
||||
<li class=''><a href='{relative_path}/popular/views'>[[global:views]]</a></li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
<a href="{relative_path}/popular">
|
||||
<div class="alert alert-warning hide" id="new-topics-alert"></div>
|
||||
</a>
|
||||
|
||||
<!-- IF !topics.length -->
|
||||
<div class="alert alert-warning" id="category-no-topics">
|
||||
<strong>There are no popular topics.</strong>
|
||||
</div>
|
||||
<!-- ENDIF !topics.length -->
|
||||
|
||||
<div class="category row">
|
||||
<div class="col-md-12">
|
||||
<ul id="topics-container" data-nextstart="{nextStart}">
|
||||
<!-- BEGIN topics -->
|
||||
<li class="category-item {topics.deleted-class}">
|
||||
<div class="col-md-12 col-xs-12 panel panel-default topic-row">
|
||||
<a href="{relative_path}/user/{topics.userslug}" class="pull-left">
|
||||
<img class="img-rounded user-img" src="{topics.picture}" title="{topics.username}" />
|
||||
</a>
|
||||
|
||||
<h3>
|
||||
<a href="{relative_path}/topic/{topics.slug}">
|
||||
<span class="topic-title">
|
||||
<strong>
|
||||
<i class="fa {topics.pin-icon}"></i>
|
||||
<i class="fa {topics.lock-icon}"></i>
|
||||
</strong>
|
||||
{topics.title}
|
||||
</span>
|
||||
</a>
|
||||
</h3>
|
||||
|
||||
<small>
|
||||
<span class="topic-stats">
|
||||
posts
|
||||
<strong class="human-readable-number" title="{topics.postcount}">{topics.postcount}</strong>
|
||||
</span>
|
||||
|
|
||||
<span class="topic-stats">
|
||||
views
|
||||
<strong class="human-readable-number" title="{topics.viewcount}">{topics.viewcount}</strong>
|
||||
</span>
|
||||
|
|
||||
<span>
|
||||
posted in
|
||||
<a href="{relative_path}/category/{topics.categorySlug}">
|
||||
<i class="fa {topics.categoryIcon}"></i> {topics.categoryName}
|
||||
</a>
|
||||
<span class="timeago" title="{topics.relativeTime}"></span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="pull-right">
|
||||
<!-- IF topics.unreplied -->
|
||||
No one has replied
|
||||
<!-- ELSE -->
|
||||
<a href="{relative_path}/user/{topics.teaser_userslug}">
|
||||
<img class="teaser-pic" src="{topics.teaser_userpicture}" title="{topics.teaser_username}"/>
|
||||
</a>
|
||||
<a href="{relative_path}/topic/{topics.slug}#{topics.teaser_pid}">
|
||||
replied
|
||||
</a>
|
||||
<span class="timeago" title="{topics.teaser_timestamp}"></span>
|
||||
<!-- ENDIF topics.unreplied -->
|
||||
</span>
|
||||
</small>
|
||||
</div>
|
||||
</li>
|
||||
<!-- END topics -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -15,9 +15,11 @@
|
||||
<div class="alert alert-warning hide" id="new-topics-alert"></div>
|
||||
</a>
|
||||
|
||||
<div class="alert alert-warning hide {no_topics_message}" id="category-no-topics">
|
||||
<!-- IF !topics.length -->
|
||||
<div class="alert alert-warning" id="category-no-topics">
|
||||
<strong>There are no recent topics.</strong>
|
||||
</div>
|
||||
<!-- ENDIF !topics.length -->
|
||||
|
||||
<div class="category row">
|
||||
<div class="col-md-12">
|
||||
|
||||
@@ -258,6 +258,20 @@ var path = require('path'),
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/popular/:set?', function (req, res, next) {
|
||||
var uid = (req.user) ? req.user.uid : 0;
|
||||
var set = 'topics:' + req.params.set;
|
||||
if(!req.params.set) {
|
||||
set = 'topics:posts';
|
||||
}
|
||||
topics.getTopicsFromSet(uid, set, 0, 19, function(err, data) {
|
||||
if(err) {
|
||||
return next(err);
|
||||
}
|
||||
res.json(data);
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/unread', function (req, res, next) {
|
||||
var uid = (req.user) ? req.user.uid : 0;
|
||||
topics.getUnreadTopics(uid, 0, 19, function (err, data) {
|
||||
|
||||
@@ -273,8 +273,20 @@ SocketTopics.loadMoreUnreadTopics = function(socket, data, callback) {
|
||||
topics.getUnreadTopics(socket.uid, start, end, callback);
|
||||
};
|
||||
|
||||
SocketTopics.loadMoreFromSet = function(socket, data, callback) {
|
||||
if(!data || !data.after || !data.set) {
|
||||
return callback(new Error('invalid data'));
|
||||
}
|
||||
|
||||
var start = parseInt(data.after, 10),
|
||||
end = start + 9;
|
||||
|
||||
topics.getTopicsFromSet(socket.uid, data.set, start, end, callback);
|
||||
};
|
||||
|
||||
|
||||
SocketTopics.getPageCount = function(socket, tid, callback) {
|
||||
topics.getPageCount(tid, callback);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = SocketTopics;
|
||||
102
src/topics.js
102
src/topics.js
@@ -415,6 +415,42 @@ var async = require('async'),
|
||||
});
|
||||
}
|
||||
|
||||
function getTopics(set, uid, tids, callback) {
|
||||
var latestTopics = {
|
||||
'topics': []
|
||||
};
|
||||
|
||||
if (!tids || !tids.length) {
|
||||
return callback(null, latestTopics);
|
||||
}
|
||||
|
||||
async.filter(tids, function(tid, next) {
|
||||
threadTools.privileges(tid, uid, function(err, privileges) {
|
||||
next(!err && privileges.read);
|
||||
});
|
||||
}, function(tids) {
|
||||
Topics.getTopicsByTids(tids, 0, uid, function(err, topicData) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if(!topicData || !topicData.length) {
|
||||
return callback(null, latestTopics);
|
||||
}
|
||||
|
||||
db.sortedSetRevRank(set, topicData[topicData.length - 1].tid, function(err, rank) {
|
||||
if(err) {
|
||||
return calllback(err);
|
||||
}
|
||||
|
||||
latestTopics.nextStart = parseInt(rank, 10) + 1;
|
||||
latestTopics.topics = topicData;
|
||||
callback(null, latestTopics);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Topics.getLatestTopics = function(current_user, start, end, term, callback) {
|
||||
|
||||
var timestamp = Date.now();
|
||||
@@ -436,38 +472,17 @@ var async = require('async'),
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var latestTopics = {
|
||||
'no_topics_message': 'hidden',
|
||||
'topics': []
|
||||
};
|
||||
getTopics('topics:recent', current_user, tids, callback);
|
||||
});
|
||||
}
|
||||
|
||||
if (!tids || !tids.length) {
|
||||
latestTopics.no_topics_message = 'show';
|
||||
return callback(null, latestTopics);
|
||||
Topics.getTopicsFromSet = function(uid, set, start, end, callback) {
|
||||
db.getSortedSetRevRange(set, start, end, function(err, tids) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
async.filter(tids, function(tid, next) {
|
||||
threadTools.privileges(tid, current_user, function(err, privileges) {
|
||||
next(!err && privileges.read);
|
||||
});
|
||||
}, function(tids) {
|
||||
Topics.getTopicsByTids(tids, 0, current_user, function(err, topicData) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if(!topicData || !topicData.length) {
|
||||
latestTopics.no_topics_message = 'show';
|
||||
return callback(null, latestTopics);
|
||||
}
|
||||
|
||||
db.sortedSetRevRank('topics:recent', topicData[topicData.length - 1].tid, function(err, rank) {
|
||||
latestTopics.nextStart = parseInt(rank,10) + 1;
|
||||
latestTopics.topics = topicData;
|
||||
callback(null, latestTopics);
|
||||
});
|
||||
});
|
||||
});
|
||||
getTopics(set, uid, tids, callback);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1075,15 +1090,30 @@ var async = require('async'),
|
||||
}
|
||||
|
||||
Topics.increasePostCount = function(tid, callback) {
|
||||
db.incrObjectField('topic:' + tid, 'postcount', callback);
|
||||
db.incrObjectField('topic:' + tid, 'postcount', function(err, value) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
db.sortedSetAdd('topics:posts', value, tid, callback);
|
||||
});
|
||||
}
|
||||
|
||||
Topics.decreasePostCount = function(tid, callback) {
|
||||
db.decrObjectField('topic:' + tid, 'postcount', callback);
|
||||
db.decrObjectField('topic:' + tid, 'postcount', function(err, value) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
db.sortedSetAdd('topics:posts', value, tid, callback);
|
||||
});
|
||||
}
|
||||
|
||||
Topics.increaseViewCount = function(tid, callback) {
|
||||
db.incrObjectField('topic:' + tid, 'viewcount', callback);
|
||||
db.incrObjectField('topic:' + tid, 'viewcount', function(err, value) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
db.sortedSetAdd('topics:views', value, tid, callback);
|
||||
});
|
||||
}
|
||||
|
||||
Topics.isLocked = function(tid, callback) {
|
||||
@@ -1143,6 +1173,8 @@ var async = require('async'),
|
||||
Topics.delete = function(tid) {
|
||||
Topics.setTopicField(tid, 'deleted', 1);
|
||||
db.sortedSetRemove('topics:recent', tid);
|
||||
db.sortedSetRemove('topics:posts', tid);
|
||||
db.sortedSetRemove('topics:views', tid);
|
||||
|
||||
Topics.getTopicField(tid, 'cid', function(err, cid) {
|
||||
feed.updateCategory(cid);
|
||||
@@ -1152,8 +1184,10 @@ var async = require('async'),
|
||||
|
||||
Topics.restore = function(tid) {
|
||||
Topics.setTopicField(tid, 'deleted', 0);
|
||||
Topics.getTopicField(tid, 'lastposttime', function(err, lastposttime) {
|
||||
db.sortedSetAdd('topics:recent', lastposttime, tid);
|
||||
Topics.getTopicFields(tid, ['lastposttime', 'postcount', 'viewcount'], function(err, topicData) {
|
||||
db.sortedSetAdd('topics:recent', topicData.lastposttime, tid);
|
||||
db.sortedSetAdd('topics:posts', topicData.postcount, tid);
|
||||
db.sortedSetAdd('topics:views', topicData.viewcount, tid);
|
||||
});
|
||||
|
||||
Topics.getTopicField(tid, 'cid', function(err, cid) {
|
||||
|
||||
@@ -19,7 +19,7 @@ var db = require('./database'),
|
||||
|
||||
Upgrade.check = function(callback) {
|
||||
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema
|
||||
var latestSchema = new Date(2014, 0, 30, 15, 0).getTime();
|
||||
var latestSchema = new Date(2014, 0, 30, 16, 0).getTime();
|
||||
|
||||
db.get('schemaDate', function(err, value) {
|
||||
if (parseInt(value, 10) >= latestSchema) {
|
||||
@@ -429,6 +429,53 @@ Upgrade.upgrade = function(callback) {
|
||||
winston.info('[2014/1/30] Fixing language settings -- skipped');
|
||||
next();
|
||||
}
|
||||
},
|
||||
function(next) {
|
||||
function updateTopic(tid, next) {
|
||||
Topics.getTopicFields(tid, ['postcount', 'viewcount'], function(err, topicData) {
|
||||
if(err) {
|
||||
next(err);
|
||||
}
|
||||
|
||||
if(topicData) {
|
||||
if(!topicData.postcount) {
|
||||
topicData.postcount = 0;
|
||||
}
|
||||
|
||||
if(!topicData.viewcount) {
|
||||
topicData.viewcount = 0;
|
||||
}
|
||||
|
||||
db.sortedSetAdd('topics:posts', topicData.postcount, tid);
|
||||
db.sortedSetAdd('topics:views', topicData.viewcount, tid);
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
thisSchemaDate = new Date(2014, 0, 30, 16, 0).getTime();
|
||||
if (schemaDate < thisSchemaDate) {
|
||||
updatesMade = true;
|
||||
|
||||
|
||||
|
||||
winston.info('[2014/1/30] Adding new topic sets');
|
||||
db.getSortedSetRange('topics:recent', 0, -1, function(err, tids) {
|
||||
if(err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
async.each(tids, updateTopic, function(err) {
|
||||
next(err);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
} else {
|
||||
winston.info('[2014/1/30] Adding new topic sets -- skipped');
|
||||
next();
|
||||
}
|
||||
}
|
||||
// Add new schema updates here
|
||||
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 17!!!
|
||||
|
||||
@@ -430,7 +430,7 @@ module.exports.server = server;
|
||||
|
||||
// Basic Routes (entirely client-side parsed, goal is to move the rest of the crap in this file into this one section)
|
||||
(function () {
|
||||
var routes = ['login', 'register', 'account', 'recent', '403', '404', '500'],
|
||||
var routes = ['login', 'register', 'account', 'recent', 'popular', '403', '404', '500'],
|
||||
loginRequired = ['unread', 'notifications'];
|
||||
|
||||
async.each(routes.concat(loginRequired), function(route, next) {
|
||||
@@ -868,6 +868,16 @@ module.exports.server = server;
|
||||
|
||||
});
|
||||
|
||||
app.get('/popular/:term?', function (req, res) {
|
||||
app.build_header({
|
||||
req: req,
|
||||
res: res
|
||||
}, function (err, header) {
|
||||
res.send(header + app.create_route('popular/' + req.params.term, null, 'popular') + templates.footer);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
app.get('/outgoing', function (req, res) {
|
||||
if (!req.query.url) {
|
||||
return res.redirect('/404');
|
||||
|
||||
Reference in New Issue
Block a user