diff --git a/loader.js b/loader.js index 3bb103d417..2effb4ffa0 100644 --- a/loader.js +++ b/loader.js @@ -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(); }, diff --git a/nodebb b/nodebb index 107d96259e..d33baeba04 100755 --- a/nodebb +++ b/nodebb @@ -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. diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 8681ceec1b..47a6a0b2a0 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -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) { diff --git a/public/src/app.js b/public/src/app.js index 17415d392d..621fd0f44c 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -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; diff --git a/public/src/forum/category.js b/public/src/forum/category.js index 1a27392a4d..68d3df5b7b 100644 --- a/public/src/forum/category.js +++ b/public/src/forum/category.js @@ -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; }); \ No newline at end of file diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 1f3c58a24b..84eafc8621 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -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) { diff --git a/public/templates/admin/users.tpl b/public/templates/admin/users.tpl index dd178658a2..6a8fdacfd4 100644 --- a/public/templates/admin/users.tpl +++ b/public/templates/admin/users.tpl @@ -20,9 +20,7 @@