Merge branch 'master' of github.com:designcreateplay/NodeBB

v1.18.x
Julian Lam 11 years ago
commit a137fb76ed

@ -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"
}

@ -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>

@ -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;

@ -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');

Loading…
Cancel
Save