From 865edb70c2eb49ba667d98b0e207b3f30d56ec60 Mon Sep 17 00:00:00 2001 From: Julian Lam <julian@designcreateplay.com> Date: Mon, 30 Sep 2013 16:28:22 -0400 Subject: [PATCH 01/29] added meta description to topics, closes #362 --- src/webserver.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/webserver.js b/src/webserver.js index 0b07f23f43..c19cee772c 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -23,7 +23,8 @@ var express = require('express'), feed = require('./feed'), plugins = require('./plugins'), nconf = require('nconf'), - winston = require('winston'); + winston = require('winston'), + validator = require('validator'); (function (app) { var templates = null, @@ -321,6 +322,9 @@ var express = require('express'), metaTags: [{ name: "title", content: topicData.topic_name + }, { + name: "description", + content: validator.sanitize(topicData.main_posts[0].content.substr(0, 255)).escape().replace('\n', '') }, { property: 'og:title', content: topicData.topic_name + ' | ' + (meta.config.title || 'NodeBB') From 249c45dfe27f0d21bb718ce0b9463ab2f2255ef5 Mon Sep 17 00:00:00 2001 From: Julian Lam <julian@designcreateplay.com> Date: Mon, 30 Sep 2013 16:30:11 -0400 Subject: [PATCH 02/29] 0.0.7 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e0b3bf5aff..ab168e0d0b 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPLv3 or later", "description": "NodeBB Forum", - "version": "0.0.6", + "version": "0.0.7", "homepage": "http://www.nodebb.org", "repository": { "type": "git", @@ -42,7 +42,7 @@ "validator": "~1.5.1" }, "optionalDependencies": { - "hiredis" : "~0.1.15" + "hiredis": "~0.1.15" }, "bugs": { "url": "https://github.com/designcreateplay/NodeBB/issues" From 181220621e0a9ee541ad08a8a9cb9f558a44c467 Mon Sep 17 00:00:00 2001 From: Julian Lam <julian@designcreateplay.com> Date: Mon, 30 Sep 2013 17:01:39 -0400 Subject: [PATCH 03/29] fixed issue with server crashing on post --- src/plugins.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins.js b/src/plugins.js index 645c90952f..0aff3ce2fb 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -185,7 +185,7 @@ var fs = require('fs'), } else { // Otherwise, this hook contains no methods var returnVal = (Array.isArray(args) ? args[0] : args); - if (callback) callback(err, returnVal); + if (callback) callback(null, returnVal); } }, isActive: function(id, callback) { From 7a919fbac4b869abd60fd4a97ededa0a46a3e4aa Mon Sep 17 00:00:00 2001 From: Julian Lam <julian@designcreateplay.com> Date: Mon, 30 Sep 2013 17:05:22 -0400 Subject: [PATCH 04/29] dropping down to 0.0.6 for re-release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ab168e0d0b..ef1726477b 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPLv3 or later", "description": "NodeBB Forum", - "version": "0.0.7", + "version": "0.0.6", "homepage": "http://www.nodebb.org", "repository": { "type": "git", From 48a7c48f7b0739ae9fd926e0cd55dff1eb5b3d86 Mon Sep 17 00:00:00 2001 From: Julian Lam <julian@designcreateplay.com> Date: Mon, 30 Sep 2013 17:05:28 -0400 Subject: [PATCH 05/29] 0.0.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ef1726477b..ab168e0d0b 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPLv3 or later", "description": "NodeBB Forum", - "version": "0.0.6", + "version": "0.0.7", "homepage": "http://www.nodebb.org", "repository": { "type": "git", From d7953eb779ef47bdb269a53309d5ec36d4387042 Mon Sep 17 00:00:00 2001 From: Julian Lam <julian@designcreateplay.com> Date: Mon, 30 Sep 2013 17:22:39 -0400 Subject: [PATCH 06/29] updated screenshots for v0.0.7 --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f1f90f2a98..2d3bab3918 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,14 @@ **NodeBB** is a robust Node.js driven forum built on a redis database. It is powered by web sockets, and is compatible down to IE8. * [NodeBB Homepage](http://www.nodebb.org/ "NodeBB") +* [Demo & Meta Discussion](http://try.nodebb.org) +* [Join us on IRC](https://kiwiirc.com/client/irc.freenode.net/nodebb) - #nodebb on Freenode * [Follow on Twitter](http://www.twitter.com/NodeBB/ "NodeBB Twitter") * [Like us on Facebook](http://www.facebook.com/NodeBB/ "NodeBB Facebook") -* [Join us on IRC](https://kiwiirc.com/client/irc.freenode.net/nodebb) - #nodebb on Freenode - + - + ## How can I follow along/contribute? From 59c9bdb3a52b668ec10ed06f0228b7bbd9471d47 Mon Sep 17 00:00:00 2001 From: Julian Lam <julian.lam@gmail.com> Date: Tue, 1 Oct 2013 11:17:57 -0400 Subject: [PATCH 07/29] updated contributor list --- package.json | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index e0b3bf5aff..c7bd713f8e 100644 --- a/package.json +++ b/package.json @@ -53,15 +53,22 @@ "contributors": [ { "name": "Andrew Rodrigues", - "email": "andrew@designcreateplay.com" + "email": "andrew@designcreateplay.com", + "url": "https://github.com/psychobunny" }, { "name": "Julian Lam", - "email": "julian@designcreateplay.com" + "email": "julian@designcreateplay.com", + "url": "https://github.com/julianlam" }, { "name": "Barış Soner Uşaklı", - "email": "baris@designcreateplay.com" + "email": "baris@designcreateplay.com", + "url": "https://github.com/barisusakli" + }, + { + "name": "Andrew Darqui", + "url": "https://github.com/adarqui" }, { "name": "Damian Bushong", @@ -70,6 +77,10 @@ { "name": "Matt Smith", "url": "https://github.com/soimafreak" + }, + { + "name": "Quinton Marchi", + "url": "https://github.com/iamcardinal" } ] } From 9613ea901895ee11f76f2b7d01ef2814ed3953fd Mon Sep 17 00:00:00 2001 From: Julian Lam <julian.lam@gmail.com> Date: Tue, 1 Oct 2013 11:54:00 -0400 Subject: [PATCH 08/29] reverted change where post title was sanitized on saving (which didn't seem to work), now sanitizing post title on output --- src/postTools.js | 4 ++-- src/posts.js | 6 +++--- src/topics.js | 15 ++++++++------- src/webserver.js | 5 +++-- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/postTools.js b/src/postTools.js index 8f41608391..9f989866cd 100644 --- a/src/postTools.js +++ b/src/postTools.js @@ -5,6 +5,7 @@ var RDB = require('./redis.js'), user = require('./user.js'), async = require('async'), nconf = require('nconf'), + validator = require('validator'), utils = require('../public/src/utils'), plugins = require('./plugins'), @@ -92,10 +93,9 @@ var RDB = require('./redis.js'), ], function(err, results) { io.sockets.in('topic_' + results[0].tid).emit('event:post_edited', { pid: pid, - title: title, + title: validator.sanitize(title).escape(), isMainPost: results[0].isMainPost, content: results[1] - }); }); }; diff --git a/src/posts.js b/src/posts.js index 957d2790b9..411610ee5e 100644 --- a/src/posts.js +++ b/src/posts.js @@ -264,9 +264,9 @@ var RDB = require('./redis.js'), var socketData = { posts: [postData] }; - io.sockets. in ('topic_' + tid).emit('event:new_post', socketData); - io.sockets. in ('recent_posts').emit('event:new_post', socketData); - io.sockets. in ('user/' + uid).emit('event:new_post', socketData); + io.sockets.in('topic_' + tid).emit('event:new_post', socketData); + io.sockets.in('recent_posts').emit('event:new_post', socketData); + io.sockets.in('user/' + uid).emit('event:new_post', socketData); }); callback(null, 'Reply successful'); diff --git a/src/topics.js b/src/topics.js index 54d303bdbf..30d9b5c9bf 100644 --- a/src/topics.js +++ b/src/topics.js @@ -15,15 +15,17 @@ schema = require('./schema.js'), topicSearch = reds.createSearch('nodebbtopicsearch'), validator = require('validator'); - (function(Topics) { Topics.getTopicData = function(tid, callback) { RDB.hgetall('topic:' + tid, function(err, data) { - if (err === null) + if (err === null) { + data.title = validator.sanitize(data.title).escape(); + callback(data); - else + } else { console.log(err); + } }); } @@ -658,7 +660,6 @@ schema = require('./schema.js'), var slug = tid + '/' + utils.slugify(title); var timestamp = Date.now(); - title = validator.sanitize(title).escape(); RDB.hmset('topic:' + tid, { 'tid': tid, 'uid': uid, @@ -698,9 +699,9 @@ schema = require('./schema.js'), // 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); - io.sockets. in ('user/' + uid).emit('event:new_post', { + io.sockets.in('category_' + category_id).emit('event:new_topic', topicData); + io.sockets.in('recent_posts').emit('event:new_topic', topicData); + io.sockets.in('user/' + uid).emit('event:new_post', { posts: postData }); }); diff --git a/src/webserver.js b/src/webserver.js index c19cee772c..a134a4ac58 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -309,7 +309,8 @@ var express = require('express'), }, function (topicData, next) { var lastMod = 0, - timestamp; + timestamp, + sanitize = validator.sanitize; for (var x = 0, numPosts = topicData.posts.length; x < numPosts; x++) { timestamp = parseInt(topicData.posts[x].timestamp, 10); @@ -324,7 +325,7 @@ var express = require('express'), content: topicData.topic_name }, { name: "description", - content: validator.sanitize(topicData.main_posts[0].content.substr(0, 255)).escape().replace('\n', '') + content: sanitize(topicData.main_posts[0].content.substr(0, 255)).escape().replace('\n', '') }, { property: 'og:title', content: topicData.topic_name + ' | ' + (meta.config.title || 'NodeBB') From 22c73f3c12aaf37ee46e2c1e88d8cae1cc2c0b0d Mon Sep 17 00:00:00 2001 From: psychobunny <rodrigues.andrew@gmail.com> Date: Tue, 1 Oct 2013 12:07:58 -0400 Subject: [PATCH 09/29] closes #345 --- public/src/ajaxify.js | 7 +++++-- public/templates/admin/settings.tpl | 6 +++++- src/routes/api.js | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 497823e3c7..4c6b83991a 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -127,8 +127,11 @@ var ajaxify = {}; } } else if (window.location.pathname !== '/outgoing') { // External Link - ajaxify.go('outgoing?url=' + encodeURIComponent(this.href)); - e.preventDefault(); + + if (config.useOutgoingLinksPage == true) { + ajaxify.go('outgoing?url=' + encodeURIComponent(this.href)); + e.preventDefault(); + } } } }); diff --git a/public/templates/admin/settings.tpl b/public/templates/admin/settings.tpl index 68fbacd632..ecc51cd730 100644 --- a/public/templates/admin/settings.tpl +++ b/public/templates/admin/settings.tpl @@ -70,7 +70,11 @@ <strong>Post Delay</strong><br /> <input type="text" class="form-control" value="10000" data-field="postDelay"><br /> <strong>Minimum Title Length</strong><br /> <input type="text" class="form-control" value="3" data-field="minimumTitleLength"><br /> <strong>Minimum Post Length</strong><br /> <input type="text" class="form-control" value="8" data-field="minimumPostLength"><br /> - + <div class="checkbox"> + <label> + <input type="checkbox" data-field="useOutgoingLinksPage"> <strong>Use Outgoing Links Warning Page</strong> + </label> + </div> </div> </form> diff --git a/src/routes/api.js b/src/routes/api.js index 40b19aec91..d201a31c93 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -28,6 +28,7 @@ var user = require('./../user.js'), config.minimumUsernameLength = meta.config.minimumUsernameLength; config.maximumUsernameLength = meta.config.maximumUsernameLength; config.minimumPasswordLength = meta.config.minimumPasswordLength; + config.useOutgoingLinksPage = meta.config.useOutgoingLinksPage; res.json(200, config); }); From 1c32acf7b6209ac19258a65263898ceb10208b52 Mon Sep 17 00:00:00 2001 From: Baris Soner Usakli <barisusakli@gmail.com> Date: Tue, 1 Oct 2013 14:17:24 -0400 Subject: [PATCH 10/29] removed WITHSCORES from getLatestTopics, how was this working at all? --- src/topics.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/topics.js b/src/topics.js index 30d9b5c9bf..2e88ebf16c 100644 --- a/src/topics.js +++ b/src/topics.js @@ -20,7 +20,8 @@ schema = require('./schema.js'), Topics.getTopicData = function(tid, callback) { RDB.hgetall('topic:' + tid, function(err, data) { if (err === null) { - data.title = validator.sanitize(data.title).escape(); + if(data) + data.title = validator.sanitize(data.title).escape(); callback(data); } else { @@ -97,7 +98,7 @@ schema = require('./schema.js'), var timestamp = Date.now(); - var args = ['topics:recent', '+inf', timestamp - 86400000, 'WITHSCORES', 'LIMIT', start, end - start + 1]; + var args = ['topics:recent', '+inf', timestamp - 86400000, 'LIMIT', start, end - start + 1]; RDB.zrevrangebyscore(args, function(err, tids) { From 90b4d688f8ce267bedf459251e88c8c18d5a03c1 Mon Sep 17 00:00:00 2001 From: Minami <cardinal@iamcardinal.com> Date: Tue, 1 Oct 2013 22:14:16 -0500 Subject: [PATCH 11/29] Testing adding of Meta Tags --- public/templates/admin/settings.tpl | 2 ++ src/install.js | 8 ++++---- src/webserver.js | 3 +++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/public/templates/admin/settings.tpl b/public/templates/admin/settings.tpl index 68fbacd632..a872497faf 100644 --- a/public/templates/admin/settings.tpl +++ b/public/templates/admin/settings.tpl @@ -8,6 +8,8 @@ <input class="form-control" type="text" placeholder="Your Community Name" data-field="title" /><br /> <label>Site Description</label> <input type="text" class="form-control" placeholder="A short description about your community" data-field="description" /><br /> + <label>Site Keywords</label> + <input type="text" class="form-control" placeholder="Keywords describing your community, comma-seperated" data-field="keywords" /><br /> <label>Imgur Client ID</label> <input type="text" class="form-control" placeholder="Imgur ClientID for image uploads" data-field="imgurClientID" /><br /> <label>Maximum User Image Size</label> diff --git a/src/install.js b/src/install.js index 4f60f6203d..fe0b5169d1 100644 --- a/src/install.js +++ b/src/install.js @@ -41,10 +41,10 @@ var async = require('async'), name: 'redis:password', description: 'Password of your Redis database' }, { - name: 'bind_address', - description: 'IP or Hostname to bind to', - 'default': '0.0.0.0' - }], + name: 'bind_address', + description: 'IP or Hostname to bind to', + 'default': '0.0.0.0' + }], setup: function (callback) { async.series([ function (next) { diff --git a/src/webserver.js b/src/webserver.js index ee87e0fa16..0a5374cdf5 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -54,6 +54,9 @@ var express = require('express'), }, { property: 'og:site_name', content: meta.config.title || 'NodeBB' + }, { + property: 'og:keywords', + content: meta.config['keywords'] || '' }], metaString = utils.buildMetaTags(defaultMetaTags.concat(options.metaTags || [])), templateValues = { From eb022220f4597a0d242e1ae6a991839c47065b64 Mon Sep 17 00:00:00 2001 From: Quinton Marchi <cardinal@iamcardinal.com> Date: Wed, 2 Oct 2013 14:22:56 -0400 Subject: [PATCH 12/29] Final Edit for keywords --- src/webserver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webserver.js b/src/webserver.js index 0a5374cdf5..371e64c53e 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -55,7 +55,7 @@ var express = require('express'), property: 'og:site_name', content: meta.config.title || 'NodeBB' }, { - property: 'og:keywords', + property: 'keywords', content: meta.config['keywords'] || '' }], metaString = utils.buildMetaTags(defaultMetaTags.concat(options.metaTags || [])), From d177e71b46fe4b92c1b5699f5a68be5bba9eb174 Mon Sep 17 00:00:00 2001 From: Quinton Marchi <cardinal@iamcardinal.com> Date: Wed, 2 Oct 2013 14:31:41 -0400 Subject: [PATCH 13/29] Fixes double search, closes #370 Haven't tested it but I can't see any problems. --- public/templates/header.tpl | 3 --- 1 file changed, 3 deletions(-) diff --git a/public/templates/header.tpl b/public/templates/header.tpl index c151a5bd58..8eb3bba4d6 100644 --- a/public/templates/header.tpl +++ b/public/templates/header.tpl @@ -50,9 +50,6 @@ <li class="visible-xs"> <a href="/search">[[global:header.search]]</a> </li> - <li class="visible-xs"> - <a href="/search">Search</a> - </li> <li> <a href="/"></a> </li> From 994791add6ea539748af759739629f67ed5e7502 Mon Sep 17 00:00:00 2001 From: Quinton Marchi <cardinal@iamcardinal.com> Date: Wed, 2 Oct 2013 17:48:27 -0400 Subject: [PATCH 14/29] Touches on postbox Adds border-radius. Compatible with: Firefox, Webkit-based, and IE9+. --- public/themes/vanilla/modules/postWindow.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/public/themes/vanilla/modules/postWindow.less b/public/themes/vanilla/modules/postWindow.less index 5f97d9cbe7..54db9b44a1 100644 --- a/public/themes/vanilla/modules/postWindow.less +++ b/public/themes/vanilla/modules/postWindow.less @@ -10,6 +10,9 @@ height: 100%; background: rgba(64, 64, 64, 0.6); visibility: visible; + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; .btn-toolbar { &.formatting-bar { From 948949c5710a96ffc2cafe8adcc739d76addee52 Mon Sep 17 00:00:00 2001 From: Julian Lam <julian@designcreateplay.com> Date: Thu, 3 Oct 2013 11:34:15 -0400 Subject: [PATCH 15/29] closed #375 - now asking socket.io to connect to "current page" instead of hardcoded url, removed api_url and "socket" section from public config --- public/src/app.js | 2 +- public/templates/admin/testing/categories.tpl | 10 +++++----- src/install.js | 4 ---- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/public/src/app.js b/public/src/app.js index 5b9918afed..94108cd895 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -17,7 +17,7 @@ var socket, socket.socket.connect(); }, 200); } else { - socket = io.connect(config.socket.address); + socket = io.connect(RELATIVE_PATH); var reconnecting = false, reconnectEl, reconnectTimer; diff --git a/public/templates/admin/testing/categories.tpl b/public/templates/admin/testing/categories.tpl index 1b2709d1fb..37a784d550 100644 --- a/public/templates/admin/testing/categories.tpl +++ b/public/templates/admin/testing/categories.tpl @@ -9,25 +9,25 @@ jQuery(document).ready(function () { QUnit.init(); asyncTest( "Loading Categories", function() { - + jQuery.get(RELATIVE_PATH + '/api/home', function(data) { ok( data.categories.length > 0, JSON.stringify(data.categories) ); - + start(); - + for (var i = 0, ii = data.categories.length; i < ii; i++) { var category = data.categories[i], slug = 'category/' + category.slug; asyncTest( "Loading Category '" + category.name + "' located at " + slug, function() { - jQuery.get(config.api_url + slug, function(data) { + jQuery.get(RELATIVE_PATH + '/api/' + slug, function(data) { ok( data.category_name, JSON.stringify(data) ); //todo: check this against data.categories start(); }); }); } }); - }); + }); QUnit.start(); }); diff --git a/src/install.js b/src/install.js index 84eb798f2c..d84682ebc7 100644 --- a/src/install.js +++ b/src/install.js @@ -81,10 +81,6 @@ var async = require('async'), protocol = urlObject.protocol, server_conf = config, client_conf = { - socket: { - address: protocol + '//' + host + (config.use_port ? ':' + config.port : '') - }, - api_url: protocol + '//' + host + (config.use_port ? ':' + config.port : '') + relative_path + '/api/', relative_path: relative_path }; From b49c7b8609f2f01f9f5dbda6a315ab180abf9dc2 Mon Sep 17 00:00:00 2001 From: Julian Lam <julian@designcreateplay.com> Date: Thu, 3 Oct 2013 11:47:40 -0400 Subject: [PATCH 16/29] added user-scalable=no to header meta tag (in lieu of fastclick lib) closes #376 - reopen if necessary. --- src/webserver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webserver.js b/src/webserver.js index 5d76dc3fce..585d6566bc 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -46,7 +46,7 @@ var express = require('express'), app.build_header = function (options, callback) { var defaultMetaTags = [{ name: 'viewport', - content: 'width=device-width, initial-scale=1.0' + content: 'width=device-width, initial-scale=1.0, user-scalable=no' }, { name: 'content-type', content: 'text/html; charset=UTF-8' From 038e04dee6ec223f72ab73bd54f7464ab45aba01 Mon Sep 17 00:00:00 2001 From: Julian Lam <julian@designcreateplay.com> Date: Thu, 3 Oct 2013 15:04:25 -0400 Subject: [PATCH 17/29] revamped client side scripts so that they are loaded using Require.js instead. --- public/src/ajaxify.js | 3 + public/src/forum/account.js | 135 +-- public/src/forum/accountedit.js | 436 ++++----- public/src/forum/accountheader.js | 43 +- public/src/forum/accountsettings.js | 34 +- public/src/forum/admin/categories.js | 241 ++--- public/src/forum/admin/footer.js | 155 +--- public/src/forum/admin/groups.js | 352 +++---- public/src/forum/admin/index.js | 39 +- public/src/forum/admin/plugins.js | 13 +- public/src/forum/admin/settings.js | 81 ++ public/src/forum/admin/themes.js | 179 ++-- public/src/forum/admin/topics.js | 254 +++--- public/src/forum/admin/users.js | 284 +++--- public/src/forum/category.js | 166 ++-- public/src/forum/favourites.js | 14 +- public/src/forum/followers.js | 26 +- public/src/forum/following.js | 18 +- public/src/forum/login.js | 116 +-- public/src/forum/recent.js | 89 +- public/src/forum/register.js | 277 +++--- public/src/forum/reset.js | 78 +- public/src/forum/reset_code.js | 110 +-- public/src/forum/search.js | 8 +- public/src/forum/topic.js | 1208 +++++++++++++------------ public/src/forum/unread.js | 213 ++--- public/src/forum/users.js | 10 +- public/templates/account.tpl | 5 +- public/templates/accountedit.tpl | 6 - public/templates/accountsettings.tpl | 3 - public/templates/admin/categories.tpl | 2 - public/templates/admin/facebook.tpl | 9 +- public/templates/admin/footer.tpl | 2 +- public/templates/admin/gplus.tpl | 9 +- public/templates/admin/groups.tpl | 2 - public/templates/admin/header.tpl | 5 +- public/templates/admin/index.tpl | 2 - public/templates/admin/motd.tpl | 9 +- public/templates/admin/plugins.tpl | 2 - public/templates/admin/settings.tpl | 9 +- public/templates/admin/themes.tpl | 8 +- public/templates/admin/topics.tpl | 2 - public/templates/admin/twitter.tpl | 9 +- public/templates/admin/users.tpl | 3 - public/templates/category.tpl | 4 +- public/templates/favourites.tpl | 3 - public/templates/followers.tpl | 3 - public/templates/following.tpl | 3 - public/templates/footer.tpl | 2 +- public/templates/header.tpl | 8 +- public/templates/login.tpl | 2 - public/templates/recent.tpl | 2 - public/templates/register.tpl | 2 - public/templates/reset.tpl | 2 - public/templates/reset_code.tpl | 3 - public/templates/search.tpl | 2 - public/templates/topic.tpl | 4 - public/templates/unread.tpl | 2 - public/templates/users.tpl | 2 - src/webserver.js | 24 +- 60 files changed, 2389 insertions(+), 2348 deletions(-) create mode 100644 public/src/forum/admin/settings.js diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 4c6b83991a..12ede65135 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -76,6 +76,9 @@ var ajaxify = {}; templates.flush(); templates.load_template(function () { exec_body_scripts(content); + require(['forum/' + tpl_url], function(script) { + if (script) script.init(); + }); if (callback) { callback(); diff --git a/public/src/forum/account.js b/public/src/forum/account.js index 45d5813ae6..aea4cf764e 100644 --- a/public/src/forum/account.js +++ b/public/src/forum/account.js @@ -1,85 +1,92 @@ -(function() { - var yourid = templates.get('yourid'), - theirid = templates.get('theirid'), - isFollowing = templates.get('isFollowing'); +define(['forum/accountheader'], function(header) { + var Account = {}; - $(document).ready(function() { - var username = $('.account-username a').html(); - app.enter_room('user/' + theirid); + Account.init = function() { + header.init(); - app.addCommasToNumbers(); + var yourid = templates.get('yourid'), + theirid = templates.get('theirid'), + isFollowing = templates.get('isFollowing'); - var followBtn = $('#follow-btn'); - var unfollowBtn = $('#unfollow-btn'); + $(document).ready(function() { + var username = $('.account-username a').html(); + app.enter_room('user/' + theirid); - if (yourid !== theirid) { - if (isFollowing) { - followBtn.hide(); - unfollowBtn.show(); - } else { - followBtn.show(); - unfollowBtn.hide(); - } - } else { - followBtn.hide(); - unfollowBtn.hide(); - } + app.addCommasToNumbers(); - followBtn.on('click', function() { - socket.emit('api:user.follow', { - uid: theirid - }, function(success) { - if (success) { + var followBtn = $('#follow-btn'); + var unfollowBtn = $('#unfollow-btn'); + + if (yourid !== theirid) { + if (isFollowing) { followBtn.hide(); unfollowBtn.show(); - app.alertSuccess('You are now following ' + username + '!'); } else { - app.alertError('There was an error following' + username + '!'); - } - }); - return false; - }); - - unfollowBtn.on('click', function() { - socket.emit('api:user.unfollow', { - uid: theirid - }, function(success) { - if (success) { followBtn.show(); unfollowBtn.hide(); - app.alertSuccess('You are no longer following ' + username + '!'); - } else { - app.alertError('There was an error unfollowing ' + username + '!'); } + } else { + followBtn.hide(); + unfollowBtn.hide(); + } + + followBtn.on('click', function() { + socket.emit('api:user.follow', { + uid: theirid + }, function(success) { + if (success) { + followBtn.hide(); + unfollowBtn.show(); + app.alertSuccess('You are now following ' + username + '!'); + } else { + app.alertError('There was an error following' + username + '!'); + } + }); + return false; }); - return false; - }); - $('.user-recent-posts .topic-row').on('click', function() { - ajaxify.go($(this).attr('topic-url')); - }); + unfollowBtn.on('click', function() { + socket.emit('api:user.unfollow', { + uid: theirid + }, function(success) { + if (success) { + followBtn.show(); + unfollowBtn.hide(); + app.alertSuccess('You are no longer following ' + username + '!'); + } else { + app.alertError('There was an error unfollowing ' + username + '!'); + } + }); + return false; + }); - var onlineStatus = $('.account-online-status'); + $('.user-recent-posts .topic-row').on('click', function() { + ajaxify.go($(this).attr('topic-url')); + }); - function handleUserOnline(data) { - if (data.online) { - onlineStatus.find('span span').text('online'); - onlineStatus.find('i').attr('class', 'icon-circle'); - } else { - onlineStatus.find('span span').text('offline'); - onlineStatus.find('i').attr('class', 'icon-circle-blank'); - } - } + socket.on('api:user.isOnline', Account.handleUserOnline); - socket.on('api:user.isOnline', handleUserOnline); + socket.emit('api:user.isOnline', theirid, Account.handleUserOnline); - socket.emit('api:user.isOnline', theirid, handleUserOnline); + socket.on('event:new_post', function(data) { + var html = templates.prepare(templates['account'].blocks['posts']).parse(data); + $('.user-recent-posts').prepend(html); + }); - socket.on('event:new_post', function(data) { - var html = templates.prepare(templates['account'].blocks['posts']).parse(data); - $('.user-recent-posts').prepend(html); }); + }; - }); + Account.handleUserOnline = function(data) { + var onlineStatus = $('.account-online-status'); + + if (data.online) { + onlineStatus.find('span span').text('online'); + onlineStatus.find('i').attr('class', 'icon-circle'); + } else { + onlineStatus.find('span span').text('offline'); + onlineStatus.find('i').attr('class', 'icon-circle-blank'); + } + }; -}()); \ No newline at end of file + return Account; +}); \ No newline at end of file diff --git a/public/src/forum/accountedit.js b/public/src/forum/accountedit.js index 25c6018e91..7771562454 100644 --- a/public/src/forum/accountedit.js +++ b/public/src/forum/accountedit.js @@ -1,88 +1,258 @@ -var gravatarPicture = templates.get('gravatarpicture'); -var uploadedPicture = templates.get('uploadedpicture'); +define(['forum/accountheader'], function(header) { + var AccountEdit = {}; -$(document).ready(function() { + AccountEdit.init = function() { + header.init(); + var gravatarPicture = templates.get('gravatarpicture'); + var uploadedPicture = templates.get('uploadedpicture'); + $('#uploadForm').submit(function() { + AccountEdit.status('uploading the file ...'); - $('#uploadForm').submit(function() { - status('uploading the file ...'); + $('#upload-progress-bar').css('width', '0%'); + $('#upload-progress-box').show(); + $('#upload-progress-box').removeClass('hide'); - $('#upload-progress-bar').css('width', '0%'); - $('#upload-progress-box').show(); - $('#upload-progress-box').removeClass('hide'); + if (!$('#userPhotoInput').val()) { + AccountEdit.error('select an image to upload!'); + return false; + } + + $(this).find('#imageUploadCsrf').val($('#csrf_token').val()); - if (!$('#userPhotoInput').val()) { - error('select an image to upload!'); - return false; - } - $(this).find('#imageUploadCsrf').val($('#csrf_token').val()); + $(this).ajaxSubmit({ + error: function(xhr) { + AccountEdit.error('Error: ' + xhr.status); + }, - $(this).ajaxSubmit({ + uploadProgress: function(event, position, total, percent) { + console.log(percent); + $('#upload-progress-bar').css('width', percent + '%'); + }, - error: function(xhr) { - error('Error: ' + xhr.status); - }, - uploadProgress: function(event, position, total, percent) { - console.log(percent); - $('#upload-progress-bar').css('width', percent + '%'); - }, + success: function(response) { + if (response.error) { + AccountEdit.error(response.error); + return; + } + var imageUrlOnServer = response.path; - success: function(response) { - if (response.error) { - error(response.error); - return; + $('#user-current-picture').attr('src', imageUrlOnServer); + $('#user-uploaded-picture').attr('src', imageUrlOnServer); + + uploadedPicture = imageUrlOnServer; + + setTimeout(function() { + AccountEdit.hideAlerts(); + $('#upload-picture-modal').modal('hide'); + }, 750); + + socket.emit('api:updateHeader', { + fields: ['username', 'picture', 'userslug'] + }); + AccountEdit.success('File uploaded successfully!'); } + }); - var imageUrlOnServer = response.path; + return false; + }); - $('#user-current-picture').attr('src', imageUrlOnServer); - $('#user-uploaded-picture').attr('src', imageUrlOnServer); + var selectedImageType = ''; + + $('#submitBtn').on('click', function() { + + var userData = { + uid: $('#inputUID').val(), + email: $('#inputEmail').val(), + fullname: $('#inputFullname').val(), + website: $('#inputWebsite').val(), + birthday: $('#inputBirthday').val(), + location: $('#inputLocation').val(), + signature: $('#inputSignature').val() + }; + + socket.emit('api:user.updateProfile', userData, function(err, data) { + if (data.success) { + app.alertSuccess('Your profile has been updated successfully!'); + if (data.picture) { + $('#user-current-picture').attr('src', data.picture); + $('#user_label img').attr('src', data.picture); + } + if (data.gravatarpicture) { + $('#user-gravatar-picture').attr('src', data.gravatarpicture); + gravatarPicture = data.gravatarpicture; + } + } else { + app.alertError('There was an error updating your profile! ' + err.error); + } + }); + return false; + }); + + $('#changePictureBtn').on('click', function() { + selectedImageType = ''; + AccountEdit.updateImages(); - uploadedPicture = imageUrlOnServer; + $('#change-picture-modal').modal('show'); + $('#change-picture-modal').removeClass('hide'); - setTimeout(function() { - hideAlerts(); - $('#upload-picture-modal').modal('hide'); - }, 750); + return false; + }); + + $('#gravatar-box').on('click', function() { + $('#gravatar-box .icon-ok').show(); + $('#uploaded-box .icon-ok').hide(); + selectedImageType = 'gravatar'; + }); - socket.emit('api:updateHeader', { - fields: ['username', 'picture', 'userslug'] - }); - success('File uploaded successfully!'); + $('#uploaded-box').on('click', function() { + $('#gravatar-box .icon-ok').hide(); + $('#uploaded-box .icon-ok').show(); + selectedImageType = 'uploaded'; + }); + + $('#savePictureChangesBtn').on('click', function() { + $('#change-picture-modal').modal('hide'); + + if (selectedImageType) { + AccountEdit.changeUserPicture(selectedImageType); + + if (selectedImageType == 'gravatar') + $('#user-current-picture').attr('src', gravatarPicture); + else if (selectedImageType == 'uploaded') + $('#user-current-picture').attr('src', uploadedPicture); } + + }); + + $('#upload-picture-modal').on('hide', function() { + $('#userPhotoInput').val(''); + }); + + $('#uploadPictureBtn').on('click', function() { + + $('#change-picture-modal').modal('hide'); + $('#upload-picture-modal').modal('show'); + $('#upload-picture-modal').removeClass('hide'); + + AccountEdit.hideAlerts(); + + return false; + }); + + $('#pictureUploadSubmitBtn').on('click', function() { + $('#uploadForm').submit(); }); - return false; - }); + (function handlePasswordChange() { + var currentPassword = $('#inputCurrentPassword'); + var password_notify = $('#password-notify'); + var password_confirm_notify = $('#password-confirm-notify'); + var password = $('#inputNewPassword'); + var password_confirm = $('#inputNewPasswordAgain'); + var passwordvalid = false; + var passwordsmatch = false; + + + function onPasswordChanged() { + passwordvalid = utils.isPasswordValid(password.val()); + if (password.val().length < config.minimumPasswordLength) { + password_notify.html('Password too short'); + password_notify.attr('class', 'alert alert-danger'); + password_notify.removeClass('hide'); + } else if (!passwordvalid) { + password_notify.html('Invalid password'); + password_notify.attr('class', 'alert alert-danger'); + password_notify.removeClass('hide'); + } else { + password_notify.html('OK!'); + password_notify.attr('class', 'alert alert-success'); + password_notify.removeClass('hide'); + } + + onPasswordConfirmChanged(); + } + + function onPasswordConfirmChanged() { + if (password_notify.hasClass('alert-danger') || !password_confirm.val()) { + password_confirm_notify.addClass('hide'); + return; + } + if (password.val() !== password_confirm.val()) { + password_confirm_notify.html('Passwords must match!'); + password_confirm_notify.attr('class', 'alert alert-danger'); + password_confirm_notify.removeClass('hide'); + passwordsmatch = false; + } else { + password_confirm_notify.html('OK!'); + password_confirm_notify.attr('class', 'alert alert-success'); + password_confirm_notify.removeClass('hide'); + passwordsmatch = true; + } + } + + password.on('blur', onPasswordChanged); + password_confirm.on('blur', onPasswordConfirmChanged); - function hideAlerts() { + $('#changePasswordBtn').on('click', function() { + + if (passwordvalid && passwordsmatch && currentPassword.val()) { + socket.emit('api:user.changePassword', { + 'currentPassword': currentPassword.val(), + 'newPassword': password.val() + }, function(err) { + + currentPassword.val(''); + password.val(''); + password_confirm.val(''); + password_notify.addClass('hide'); + password_confirm_notify.addClass('hide'); + passwordsmatch = false; + passwordvalid = false; + + if (err) { + app.alertError(err.error); + return; + } + + app.alertSuccess('Your password is updated!'); + + }); + } + return false; + }); + + }()); + }; + + AccountEdit.hideAlerts = function() { $('#alert-status').addClass('hide'); $('#alert-success').addClass('hide'); $('#alert-error').addClass('hide'); $('#upload-progress-box').addClass('hide'); } - function status(message) { - hideAlerts(); + AccountEdit.status = function(message) { + AccountEdit.hideAlerts(); $('#alert-status').text(message).removeClass('hide'); } - function success(message) { - hideAlerts(); + AccountEdit.success = function(message) { + AccountEdit.hideAlerts(); $('#alert-success').text(message).removeClass('hide'); } - function error(message) { - hideAlerts(); + AccountEdit.error = function(message) { + AccountEdit.hideAlerts(); $('#alert-error').text(message).removeClass('hide'); } - function changeUserPicture(type) { + AccountEdit.changeUserPicture = function(type) { var userData = { type: type }; @@ -94,40 +264,10 @@ $(document).ready(function() { }); } - var selectedImageType = ''; - - $('#submitBtn').on('click', function() { - - var userData = { - uid: $('#inputUID').val(), - email: $('#inputEmail').val(), - fullname: $('#inputFullname').val(), - website: $('#inputWebsite').val(), - birthday: $('#inputBirthday').val(), - location: $('#inputLocation').val(), - signature: $('#inputSignature').val() - }; - - socket.emit('api:user.updateProfile', userData, function(err, data) { - if (data.success) { - app.alertSuccess('Your profile has been updated successfully!'); - if (data.picture) { - $('#user-current-picture').attr('src', data.picture); - $('#user_label img').attr('src', data.picture); - } - if (data.gravatarpicture) { - $('#user-gravatar-picture').attr('src', data.gravatarpicture); - gravatarPicture = data.gravatarpicture; - } - } else { - app.alertError('There was an error updating your profile! ' + err.error); - } - }); - return false; - }); - - function updateImages() { + AccountEdit.updateImages = function() { var currentPicture = $('#user-current-picture').attr('src'); + var gravatarPicture = templates.get('gravatarpicture'); + var uploadedPicture = templates.get('uploadedpicture'); if (gravatarPicture) { $('#user-gravatar-picture').attr('src', gravatarPicture); @@ -153,139 +293,5 @@ $(document).ready(function() { $('#uploaded-box .icon-ok').hide(); } - - $('#changePictureBtn').on('click', function() { - selectedImageType = ''; - updateImages(); - - $('#change-picture-modal').modal('show'); - $('#change-picture-modal').removeClass('hide'); - - return false; - }); - - $('#gravatar-box').on('click', function() { - $('#gravatar-box .icon-ok').show(); - $('#uploaded-box .icon-ok').hide(); - selectedImageType = 'gravatar'; - }); - - $('#uploaded-box').on('click', function() { - $('#gravatar-box .icon-ok').hide(); - $('#uploaded-box .icon-ok').show(); - selectedImageType = 'uploaded'; - }); - - $('#savePictureChangesBtn').on('click', function() { - $('#change-picture-modal').modal('hide'); - - if (selectedImageType) { - changeUserPicture(selectedImageType); - - if (selectedImageType == 'gravatar') - $('#user-current-picture').attr('src', gravatarPicture); - else if (selectedImageType == 'uploaded') - $('#user-current-picture').attr('src', uploadedPicture); - } - - }); - - $('#upload-picture-modal').on('hide', function() { - $('#userPhotoInput').val(''); - }); - - $('#uploadPictureBtn').on('click', function() { - - $('#change-picture-modal').modal('hide'); - $('#upload-picture-modal').modal('show'); - $('#upload-picture-modal').removeClass('hide'); - - hideAlerts(); - - return false; - }); - - $('#pictureUploadSubmitBtn').on('click', function() { - $('#uploadForm').submit(); - }); - - (function handlePasswordChange() { - var currentPassword = $('#inputCurrentPassword'); - var password_notify = $('#password-notify'); - var password_confirm_notify = $('#password-confirm-notify'); - var password = $('#inputNewPassword'); - var password_confirm = $('#inputNewPasswordAgain'); - var passwordvalid = false; - var passwordsmatch = false; - - - function onPasswordChanged() { - passwordvalid = utils.isPasswordValid(password.val()); - if (password.val().length < config.minimumPasswordLength) { - password_notify.html('Password too short'); - password_notify.attr('class', 'alert alert-danger'); - password_notify.removeClass('hide'); - } else if (!passwordvalid) { - password_notify.html('Invalid password'); - password_notify.attr('class', 'alert alert-danger'); - password_notify.removeClass('hide'); - } else { - password_notify.html('OK!'); - password_notify.attr('class', 'alert alert-success'); - password_notify.removeClass('hide'); - } - - onPasswordConfirmChanged(); - } - - function onPasswordConfirmChanged() { - if (password_notify.hasClass('alert-danger') || !password_confirm.val()) { - password_confirm_notify.addClass('hide'); - return; - } - if (password.val() !== password_confirm.val()) { - password_confirm_notify.html('Passwords must match!'); - password_confirm_notify.attr('class', 'alert alert-danger'); - password_confirm_notify.removeClass('hide'); - passwordsmatch = false; - } else { - password_confirm_notify.html('OK!'); - password_confirm_notify.attr('class', 'alert alert-success'); - password_confirm_notify.removeClass('hide'); - passwordsmatch = true; - } - } - - password.on('blur', onPasswordChanged); - password_confirm.on('blur', onPasswordConfirmChanged); - - $('#changePasswordBtn').on('click', function() { - - if (passwordvalid && passwordsmatch && currentPassword.val()) { - socket.emit('api:user.changePassword', { - 'currentPassword': currentPassword.val(), - 'newPassword': password.val() - }, function(err) { - - currentPassword.val(''); - password.val(''); - password_confirm.val(''); - password_notify.addClass('hide'); - password_confirm_notify.addClass('hide'); - passwordsmatch = false; - passwordvalid = false; - - if (err) { - app.alertError(err.error); - return; - } - - app.alertSuccess('Your password is updated!'); - - }); - } - return false; - }); - - }()); + return AccountEdit; }); \ No newline at end of file diff --git a/public/src/forum/accountheader.js b/public/src/forum/accountheader.js index 15bb2db614..d865a83b1b 100644 --- a/public/src/forum/accountheader.js +++ b/public/src/forum/accountheader.js @@ -1,24 +1,11 @@ -(function() { - var yourid = templates.get('yourid'), - theirid = templates.get('theirid'); +define(function() { + var AccountHeader = {}; + AccountHeader.init = function() { + var yourid = templates.get('yourid'), + theirid = templates.get('theirid'); - function createMenu() { - var userslug = $('.account-username-box').attr('data-userslug'); - var links = $('<div class="account-sub-links inline-block pull-right">\ - <span id="settingsLink" class="pull-right"><a href="/user/' + userslug + '/settings">settings</a></span>\ - <span id="favouritesLink" class="pull-right"><a href="/user/' + userslug + '/favourites">favourites</a></span>\ - <span class="pull-right"><a href="/user/' + userslug + '/followers">followers</a></span>\ - <span class="pull-right"><a href="/user/' + userslug + '/following">following</a></span>\ - <span id="editLink" class="pull-right"><a href="/user/' + userslug + '/edit">edit</a></span>\ - </div>'); - - $('.account-username-box').append(links); - } - - $(document).ready(function() { - - createMenu(); + AccountHeader.createMenu(); var editLink = $('#editLink'); var settingsLink = $('#settingsLink'); @@ -37,6 +24,20 @@ return false; } }); - }); + } + + AccountHeader.createMenu = function() { + var userslug = $('.account-username-box').attr('data-userslug'); + var links = $('<div class="account-sub-links inline-block pull-right">\ + <span id="settingsLink" class="pull-right"><a href="/user/' + userslug + '/settings">settings</a></span>\ + <span id="favouritesLink" class="pull-right"><a href="/user/' + userslug + '/favourites">favourites</a></span>\ + <span class="pull-right"><a href="/user/' + userslug + '/followers">followers</a></span>\ + <span class="pull-right"><a href="/user/' + userslug + '/following">following</a></span>\ + <span id="editLink" class="pull-right"><a href="/user/' + userslug + '/edit">edit</a></span>\ + </div>'); + + $('.account-username-box').append(links); + } -}()); \ No newline at end of file + return AccountHeader; +}); \ No newline at end of file diff --git a/public/src/forum/accountsettings.js b/public/src/forum/accountsettings.js index d121ecbe85..6f6d6edcbb 100644 --- a/public/src/forum/accountsettings.js +++ b/public/src/forum/accountsettings.js @@ -1,19 +1,25 @@ -$(document).ready(function() { +define(['forum/accountheader'], function(header) { + var AccountSettings = {}; - $('#submitBtn').on('click', function() { + AccountSettings.init = function() { + header.init(); - var settings = { - showemail: $('#showemailCheckBox').is(':checked') ? 1 : 0 - }; + $('#submitBtn').on('click', function() { - socket.emit('api:user.saveSettings', settings, function(success) { - if (success) { - app.alertSuccess('Settings saved!'); - } else { - app.alertError('There was an error saving settings!'); - } + var settings = { + showemail: $('#showemailCheckBox').is(':checked') ? 1 : 0 + }; + + socket.emit('api:user.saveSettings', settings, function(success) { + if (success) { + app.alertSuccess('Settings saved!'); + } else { + app.alertError('There was an error saving settings!'); + } + }); + return false; }); - return false; - }); + }; -}); \ No newline at end of file + return AccountSettings; +}); diff --git a/public/src/forum/admin/categories.js b/public/src/forum/admin/categories.js index cb7ddbd39e..4568e7ceae 100644 --- a/public/src/forum/admin/categories.js +++ b/public/src/forum/admin/categories.js @@ -1,139 +1,144 @@ -var modified_categories = {}; +define(function() { + var Categories = {}; -function modified(el) { - var cid = $(el).parents('li').attr('data-cid'); + Categories.init = function() { + var modified_categories = {}; - modified_categories[cid] = modified_categories[cid] || {}; - modified_categories[cid][$(el).attr('data-name')] = $(el).val(); -} + function modified(el) { + var cid = $(el).parents('li').attr('data-cid'); -function save() { - socket.emit('api:admin.categories.update', modified_categories); - modified_categories = {}; -} - -function select_icon(el) { - var selected = el.attr('class').replace(' icon-2x', ''); - jQuery('#icons .selected').removeClass('selected'); - if (selected) - jQuery('#icons .' + selected).parent().addClass('selected'); - - - bootbox.confirm('<h2>Select an icon.</h2>' + document.getElementById('icons').innerHTML, function(confirm) { - if (confirm) { - var iconClass = jQuery('.bootbox .selected').children(':first').attr('class'); - el.attr('class', iconClass + ' icon-2x'); - el.val(iconClass); - - modified(el); + modified_categories[cid] = modified_categories[cid] || {}; + modified_categories[cid][$(el).attr('data-name')] = $(el).val(); } - }); - setTimeout(function() { //bootbox was rewritten for BS3 and I had to add this timeout for the previous code to work. TODO: to look into - jQuery('.bootbox .col-md-3').on('click', function() { - jQuery('.bootbox .selected').removeClass('selected'); - jQuery(this).addClass('selected'); - }); - }, 500); -} - - -function update_blockclass(el) { - el.parentNode.parentNode.className = 'entry-row ' + el.value; -} - -jQuery('#entry-container').sortable(); -jQuery('.blockclass').each(function() { - jQuery(this).val(this.getAttribute('data-value')); -}); - - -//DRY Failure. this needs to go into an ajaxify onready style fn. Currently is copy pasted into every single function so after ACP is off the ground fix asap -(function() { - function showCreateCategoryModal() { - $('#new-category-modal').modal(); - } - - function createNewCategory() { - var category = { - name: $('#inputName').val(), - description: $('#inputDescription').val(), - icon: $('#new-category-modal i').attr('value'), - blockclass: $('#inputBlockclass').val() - }; - - socket.emit('api:admin.categories.create', category, function(err, data) { - if (!err) { - app.alert({ - alert_id: 'category_created', - title: 'Created', - message: 'Category successfully created!', - type: 'success', - timeout: 2000 - }); + function save() { + socket.emit('api:admin.categories.update', modified_categories); + modified_categories = {}; + } - var html = templates.prepare(templates['admin/categories'].blocks['categories']).parse({ - categories: [data] - }); - $('#entry-container').append(html); + function select_icon(el) { + var selected = el.attr('class').replace(' icon-2x', ''); + jQuery('#icons .selected').removeClass('selected'); + if (selected) + jQuery('#icons .' + selected).parent().addClass('selected'); - $('#new-category-modal').modal('hide'); - } - }); - } - jQuery('document').ready(function() { - var url = window.location.href, - parts = url.split('/'), - active = parts[parts.length - 1]; + bootbox.confirm('<h2>Select an icon.</h2>' + document.getElementById('icons').innerHTML, function(confirm) { + if (confirm) { + var iconClass = jQuery('.bootbox .selected').children(':first').attr('class'); + el.attr('class', iconClass + ' icon-2x'); + el.val(iconClass); - 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; - } - }); + modified(el); + } + }); - jQuery('#save').on('click', save); - jQuery('#addNew').on('click', showCreateCategoryModal); - jQuery('#create-category-btn').on('click', createNewCategory); + setTimeout(function() { //bootbox was rewritten for BS3 and I had to add this timeout for the previous code to work. TODO: to look into + jQuery('.bootbox .col-md-3').on('click', function() { + jQuery('.bootbox .selected').removeClass('selected'); + jQuery(this).addClass('selected'); + }); + }, 500); + } - jQuery('#entry-container').on('click', '.icon', function(ev) { - select_icon($(this).find('i')); - }); - jQuery('.blockclass').on('change', function(ev) { - update_blockclass(ev.target); - }); + function update_blockclass(el) { + el.parentNode.parentNode.className = 'entry-row ' + el.value; + } - jQuery('.category_name, .category_description, .blockclass').on('change', function(ev) { - modified(ev.target); + jQuery('#entry-container').sortable(); + jQuery('.blockclass').each(function() { + jQuery(this).val(this.getAttribute('data-value')); }); - jQuery('.entry-row button').each(function(index, element) { - var disabled = $(element).attr('data-disabled'); - if (disabled == "0" || disabled == "") - $(element).html('Disable'); - else - $(element).html('Enable'); - }); + //DRY Failure. this needs to go into an ajaxify onready style fn. Currently is copy pasted into every single function so after ACP is off the ground fix asap + function showCreateCategoryModal() { + $('#new-category-modal').modal(); + } - jQuery('.entry-row button').on('click', function(ev) { - var btn = jQuery(this); - var categoryRow = btn.parents('li'); - var cid = categoryRow.attr('data-cid'); + function createNewCategory() { + var category = { + name: $('#inputName').val(), + description: $('#inputDescription').val(), + icon: $('#new-category-modal i').attr('value'), + blockclass: $('#inputBlockclass').val() + }; + + socket.emit('api:admin.categories.create', category, function(err, data) { + if (!err) { + app.alert({ + alert_id: 'category_created', + title: 'Created', + message: 'Category successfully created!', + type: 'success', + timeout: 2000 + }); + + var html = templates.prepare(templates['admin/categories'].blocks['categories']).parse({ + categories: [data] + }); + $('#entry-container').append(html); + + $('#new-category-modal').modal('hide'); + } + }); + } - var disabled = btn.html() == "Disable" ? "1" : "0"; - categoryRow.remove(); - modified_categories[cid] = modified_categories[cid] || {}; - modified_categories[cid]['disabled'] = disabled; + jQuery('document').ready(function() { + var url = window.location.href, + parts = url.split('/'), + active = parts[parts.length - 1]; + + 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; + } + }); + + jQuery('#save').on('click', save); + jQuery('#addNew').on('click', showCreateCategoryModal); + jQuery('#create-category-btn').on('click', createNewCategory); + + jQuery('#entry-container').on('click', '.icon', function(ev) { + select_icon($(this).find('i')); + }); + + jQuery('.blockclass').on('change', function(ev) { + update_blockclass(ev.target); + }); + + jQuery('.category_name, .category_description, .blockclass').on('change', function(ev) { + modified(ev.target); + }); + + jQuery('.entry-row button').each(function(index, element) { + var disabled = $(element).attr('data-disabled'); + if (disabled == "0" || disabled == "") + $(element).html('Disable'); + else + $(element).html('Enable'); + + }); + + jQuery('.entry-row button').on('click', function(ev) { + var btn = jQuery(this); + var categoryRow = btn.parents('li'); + var cid = categoryRow.attr('data-cid'); + + var disabled = btn.html() == "Disable" ? "1" : "0"; + categoryRow.remove(); + modified_categories[cid] = modified_categories[cid] || {}; + modified_categories[cid]['disabled'] = disabled; + + save(); + return false; + }); - save(); - return false; }); + }; - }); - -}()); \ No newline at end of file + return Categories; +}); \ No newline at end of file diff --git a/public/src/forum/admin/footer.js b/public/src/forum/admin/footer.js index ee9062af9d..22990fcf7b 100644 --- a/public/src/forum/admin/footer.js +++ b/public/src/forum/admin/footer.js @@ -1,121 +1,44 @@ -var nodebb_admin = (function(nodebb_admin) { - - nodebb_admin.config = undefined; - - nodebb_admin.prepare = function() { - // Come back in 500ms if the config isn't ready yet - if (nodebb_admin.config === undefined) { - setTimeout(function() { - nodebb_admin.prepare(); - }, 500); - return; - } - - // Populate the fields on the page from the config - var fields = document.querySelectorAll('#content [data-field]'), - numFields = fields.length, - saveBtn = document.getElementById('save'), - x, key, inputType; - for (x = 0; x < numFields; x++) { - key = fields[x].getAttribute('data-field'); - inputType = fields[x].getAttribute('type'); - if (fields[x].nodeName === 'INPUT') { - if (nodebb_admin.config[key]) { - switch (inputType) { - case 'text': - case 'textarea': - case 'number': - fields[x].value = nodebb_admin.config[key]; - break; - - case 'checkbox': - fields[x].checked = nodebb_admin.config[key] === '1' ? true : false; - break; - } - } - } else if (fields[x].nodeName === 'TEXTAREA') { - if (nodebb_admin.config[key]) fields[x].value = nodebb_admin.config[key]; +jQuery('document').ready(function() { + // On menu click, change "active" state + var menuEl = document.querySelector('.sidebar-nav'), + liEls = menuEl.querySelectorAll('li') + parentEl = null; + + menuEl.addEventListener('click', function(e) { + parentEl = e.target.parentNode; + if (parentEl.nodeName === 'LI') { + for (var x = 0, numLis = liEls.length; x < numLis; x++) { + if (liEls[x] !== parentEl) jQuery(liEls[x]).removeClass('active'); + else jQuery(parentEl).addClass('active'); } } + }, false); +}); - saveBtn.addEventListener('click', function(e) { - var key, value; - e.preventDefault(); - - for (x = 0; x < numFields; x++) { - key = fields[x].getAttribute('data-field'); - if (fields[x].nodeName === 'INPUT') { - inputType = fields[x].getAttribute('type'); - switch (inputType) { - case 'text': - case 'number': - value = fields[x].value; - break; - - case 'checkbox': - value = fields[x].checked ? '1' : '0'; - break; - } - } else if (fields[x].nodeName === 'TEXTAREA') { - value = fields[x].value; - } - - socket.emit('api:config.set', { - key: key, - value: value - }); - } +socket.once('api:config.get', function(config) { + require(['forum/admin/settings'], function(Settings) { + Settings.config = config; + }); +}); + +socket.emit('api:config.get'); + +socket.on('api:config.set', function(data) { + if (data.status === 'ok') { + app.alert({ + alert_id: 'config_status', + timeout: 2500, + title: 'Changes Saved', + message: 'Your changes to the NodeBB configuration have been saved.', + type: 'success' + }); + } else { + app.alert({ + alert_id: 'config_status', + timeout: 2500, + title: 'Changes Not Saved', + message: 'NodeBB encountered a problem saving your changes', + type: 'danger' }); } - - nodebb_admin.remove = function(key) { - socket.emit('api:config.remove', key); - } - - - jQuery('document').ready(function() { - // On menu click, change "active" state - var menuEl = document.querySelector('.sidebar-nav'), - liEls = menuEl.querySelectorAll('li') - parentEl = null; - - menuEl.addEventListener('click', function(e) { - parentEl = e.target.parentNode; - if (parentEl.nodeName === 'LI') { - for (var x = 0, numLis = liEls.length; x < numLis; x++) { - if (liEls[x] !== parentEl) jQuery(liEls[x]).removeClass('active'); - else jQuery(parentEl).addClass('active'); - } - } - }, false); - }); - - socket.once('api:config.get', function(config) { - nodebb_admin.config = config; - }); - - socket.emit('api:config.get'); - - socket.on('api:config.set', function(data) { - if (data.status === 'ok') { - app.alert({ - alert_id: 'config_status', - timeout: 2500, - title: 'Changes Saved', - message: 'Your changes to the NodeBB configuration have been saved.', - type: 'success' - }); - } else { - app.alert({ - alert_id: 'config_status', - timeout: 2500, - title: 'Changes Not Saved', - message: 'NodeBB encountered a problem saving your changes', - type: 'danger' - }); - } - }); - - return nodebb_admin; - -}(nodebb_admin || {})); \ No newline at end of file +}); \ No newline at end of file diff --git a/public/src/forum/admin/groups.js b/public/src/forum/admin/groups.js index c9dda987fe..80737b44b9 100644 --- a/public/src/forum/admin/groups.js +++ b/public/src/forum/admin/groups.js @@ -1,194 +1,200 @@ -$(document).ready(function() { - var createEl = document.getElementById('create'), - createModal = $('#create-modal'), - createSubmitBtn = document.getElementById('create-modal-go'), - createNameEl = $('#create-group-name'), - detailsModal = $('#group-details-modal'), - detailsSearch = detailsModal.find('#group-details-search'), - searchResults = detailsModal.find('#group-details-search-results'), - groupMembersEl = detailsModal.find('ul.current_members'), - detailsModalSave = detailsModal.find('.btn-primary'), - searchDelay = undefined, - listEl = $('#groups-list'); - - createEl.addEventListener('click', function() { - createModal.modal('show'); - setTimeout(function() { - createNameEl.focus(); - }, 250); - }, false); - - createSubmitBtn.addEventListener('click', function() { - var submitObj = { - name: createNameEl.val(), - description: $('#create-group-desc').val() - }, - errorEl = $('#create-modal-error'), - errorText; - - socket.emit('api:groups.create', submitObj, function(err, data) { - if (err) { - switch (err) { - case 'group-exists': - errorText = '<strong>Please choose another name</strong><p>There seems to be a group with this name already.</p>'; - break; - case 'name-too-short': - errorText = '<strong>Please specify a grou name</strong><p>A group name is required for administrative purposes.</p>'; - break; - default: - errorText = '<strong>Uh-Oh</strong><p>There was a problem creating your group. Please try again later!</p>'; - break; +define(function() { + var Groups = {}; + + Groups.init = function() { + var createEl = document.getElementById('create'), + createModal = $('#create-modal'), + createSubmitBtn = document.getElementById('create-modal-go'), + createNameEl = $('#create-group-name'), + detailsModal = $('#group-details-modal'), + detailsSearch = detailsModal.find('#group-details-search'), + searchResults = detailsModal.find('#group-details-search-results'), + groupMembersEl = detailsModal.find('ul.current_members'), + detailsModalSave = detailsModal.find('.btn-primary'), + searchDelay = undefined, + listEl = $('#groups-list'); + + createEl.addEventListener('click', function() { + createModal.modal('show'); + setTimeout(function() { + createNameEl.focus(); + }, 250); + }, false); + + createSubmitBtn.addEventListener('click', function() { + var submitObj = { + name: createNameEl.val(), + description: $('#create-group-desc').val() + }, + errorEl = $('#create-modal-error'), + errorText; + + socket.emit('api:groups.create', submitObj, function(err, data) { + if (err) { + switch (err) { + case 'group-exists': + errorText = '<strong>Please choose another name</strong><p>There seems to be a group with this name already.</p>'; + break; + case 'name-too-short': + errorText = '<strong>Please specify a grou name</strong><p>A group name is required for administrative purposes.</p>'; + break; + default: + errorText = '<strong>Uh-Oh</strong><p>There was a problem creating your group. Please try again later!</p>'; + break; + } + + errorEl.html(errorText).removeClass('hide'); + } else { + createModal.modal('hide'); + errorEl.addClass('hide'); + createNameEl.val(''); + ajaxify.go('admin/groups'); } + }); + }); - errorEl.html(errorText).removeClass('hide'); - } else { - createModal.modal('hide'); - errorEl.addClass('hide'); - createNameEl.val(''); - ajaxify.go('admin/groups'); + listEl.on('click', 'button[data-action]', function() { + var action = this.getAttribute('data-action'), + gid = $(this).parents('li[data-gid]').attr('data-gid'); + + switch (action) { + case 'delete': + bootbox.confirm('Are you sure you wish to delete this group?', function(confirm) { + if (confirm) { + socket.emit('api:groups.delete', gid, function(err, data) { + if (data === 'OK') ajaxify.go('admin/groups'); + }); + } + }); + break; + case 'members': + socket.emit('api:groups.get', gid, function(err, groupObj) { + var formEl = detailsModal.find('form'), + nameEl = formEl.find('#change-group-name'), + descEl = formEl.find('#change-group-desc'), + memberIcon = document.createElement('li'), + numMembers = groupObj.members.length, + membersFrag = document.createDocumentFragment(), + memberIconImg, x; + + + nameEl.val(groupObj.name); + descEl.val(groupObj.description); + + // Member list + memberIcon.innerHTML = '<img /><span></span>'; + memberIconImg = memberIcon.querySelector('img'); + memberIconLabel = memberIcon.querySelector('span'); + if (numMembers > 0) { + for (x = 0; x < numMembers; x++) { + memberIconImg.src = groupObj.members[x].picture; + memberIconLabel.innerHTML = groupObj.members[x].username; + memberIcon.setAttribute('data-uid', groupObj.members[x].uid); + membersFrag.appendChild(memberIcon.cloneNode(true)); + } + groupMembersEl.html(''); + groupMembersEl[0].appendChild(membersFrag); + } + + detailsModal.attr('data-gid', groupObj.gid); + detailsModal.modal('show'); + }); + break; } }); - }); - - listEl.on('click', 'button[data-action]', function() { - var action = this.getAttribute('data-action'), - gid = $(this).parents('li[data-gid]').attr('data-gid'); - - switch (action) { - case 'delete': - bootbox.confirm('Are you sure you wish to delete this group?', function(confirm) { - if (confirm) { - socket.emit('api:groups.delete', gid, function(err, data) { - if (data === 'OK') ajaxify.go('admin/groups'); - }); - } - }); - break; - case 'members': - socket.emit('api:groups.get', gid, function(err, groupObj) { - var formEl = detailsModal.find('form'), - nameEl = formEl.find('#change-group-name'), - descEl = formEl.find('#change-group-desc'), - memberIcon = document.createElement('li'), - numMembers = groupObj.members.length, - membersFrag = document.createDocumentFragment(), - memberIconImg, x; - - - nameEl.val(groupObj.name); - descEl.val(groupObj.description); - - // Member list - memberIcon.innerHTML = '<img /><span></span>'; - memberIconImg = memberIcon.querySelector('img'); - memberIconLabel = memberIcon.querySelector('span'); - if (numMembers > 0) { - for (x = 0; x < numMembers; x++) { - memberIconImg.src = groupObj.members[x].picture; - memberIconLabel.innerHTML = groupObj.members[x].username; - memberIcon.setAttribute('data-uid', groupObj.members[x].uid); - membersFrag.appendChild(memberIcon.cloneNode(true)); + + detailsSearch.on('keyup', function() { + var searchEl = this; + + if (searchDelay) clearTimeout(searchDelay); + + searchDelay = setTimeout(function() { + var searchText = searchEl.value, + resultsEl = document.getElementById('group-details-search-results'), + foundUser = document.createElement('li'), + foundUserImg, foundUserLabel; + + foundUser.innerHTML = '<img /><span></span>'; + foundUserImg = foundUser.getElementsByTagName('img')[0]; + foundUserLabel = foundUser.getElementsByTagName('span')[0]; + + socket.emit('api:admin.user.search', searchText, function(err, results) { + if (!err && results && results.length > 0) { + var numResults = results.length, + resultsSlug = document.createDocumentFragment(), + x; + if (numResults > 4) numResults = 4; + for (x = 0; x < numResults; x++) { + foundUserImg.src = results[x].picture; + foundUserLabel.innerHTML = results[x].username; + foundUser.setAttribute('title', results[x].username); + foundUser.setAttribute('data-uid', results[x].uid); + resultsSlug.appendChild(foundUser.cloneNode(true)); } - groupMembersEl.html(''); - groupMembersEl[0].appendChild(membersFrag); - } - detailsModal.attr('data-gid', groupObj.gid); - detailsModal.modal('show'); + resultsEl.innerHTML = ''; + resultsEl.appendChild(resultsSlug); + } else resultsEl.innerHTML = '<li>No Users Found</li>'; }); - break; - } - }); - - detailsSearch.on('keyup', function() { - var searchEl = this; - - if (searchDelay) clearTimeout(searchDelay); - - searchDelay = setTimeout(function() { - var searchText = searchEl.value, - resultsEl = document.getElementById('group-details-search-results'), - foundUser = document.createElement('li'), - foundUserImg, foundUserLabel; - - foundUser.innerHTML = '<img /><span></span>'; - foundUserImg = foundUser.getElementsByTagName('img')[0]; - foundUserLabel = foundUser.getElementsByTagName('span')[0]; - - socket.emit('api:admin.user.search', searchText, function(err, results) { - if (!err && results && results.length > 0) { - var numResults = results.length, - resultsSlug = document.createDocumentFragment(), - x; - if (numResults > 4) numResults = 4; - for (x = 0; x < numResults; x++) { - foundUserImg.src = results[x].picture; - foundUserLabel.innerHTML = results[x].username; - foundUser.setAttribute('title', results[x].username); - foundUser.setAttribute('data-uid', results[x].uid); - resultsSlug.appendChild(foundUser.cloneNode(true)); - } + }, 200); + }); - resultsEl.innerHTML = ''; - resultsEl.appendChild(resultsSlug); - } else resultsEl.innerHTML = '<li>No Users Found</li>'; - }); - }, 200); - }); + searchResults.on('click', 'li[data-uid]', function() { + var userLabel = this, + uid = parseInt(this.getAttribute('data-uid')), + gid = detailsModal.attr('data-gid'), + members = []; - searchResults.on('click', 'li[data-uid]', function() { - var userLabel = this, - uid = parseInt(this.getAttribute('data-uid')), - gid = detailsModal.attr('data-gid'), - members = []; + groupMembersEl.find('li[data-uid]').each(function() { + members.push(parseInt(this.getAttribute('data-uid'))); + }); - groupMembersEl.find('li[data-uid]').each(function() { - members.push(parseInt(this.getAttribute('data-uid'))); + if (members.indexOf(uid) === -1) { + socket.emit('api:groups.join', { + gid: gid, + uid: uid + }, function(err, data) { + if (!err) { + groupMembersEl.append(userLabel.cloneNode(true)); + } + }); + } }); - if (members.indexOf(uid) === -1) { - socket.emit('api:groups.join', { + groupMembersEl.on('click', 'li[data-uid]', function() { + var uid = this.getAttribute('data-uid'), + gid = detailsModal.attr('data-gid'); + + socket.emit('api:groups.leave', { gid: gid, uid: uid }, function(err, data) { if (!err) { - groupMembersEl.append(userLabel.cloneNode(true)); + groupMembersEl.find('li[data-uid="' + uid + '"]').remove(); } }); - } - }); - - groupMembersEl.on('click', 'li[data-uid]', function() { - var uid = this.getAttribute('data-uid'), - gid = detailsModal.attr('data-gid'); - - socket.emit('api:groups.leave', { - gid: gid, - uid: uid - }, function(err, data) { - if (!err) { - groupMembersEl.find('li[data-uid="' + uid + '"]').remove(); - } }); - }); - - detailsModalSave.on('click', function() { - var formEl = detailsModal.find('form'), - nameEl = formEl.find('#change-group-name'), - descEl = formEl.find('#change-group-desc'), - gid = detailsModal.attr('data-gid'); - - socket.emit('api:groups.update', { - gid: gid, - values: { - name: nameEl.val(), - description: descEl.val() - } - }, function(err) { - if (!err) { - detailsModal.modal('hide'); - ajaxify.go('admin/groups'); - } + + detailsModalSave.on('click', function() { + var formEl = detailsModal.find('form'), + nameEl = formEl.find('#change-group-name'), + descEl = formEl.find('#change-group-desc'), + gid = detailsModal.attr('data-gid'); + + socket.emit('api:groups.update', { + gid: gid, + values: { + name: nameEl.val(), + description: descEl.val() + } + }, function(err) { + if (!err) { + detailsModal.modal('hide'); + ajaxify.go('admin/groups'); + } + }); }); - }); + }; + + return Groups; }); \ No newline at end of file diff --git a/public/src/forum/admin/index.js b/public/src/forum/admin/index.js index 66133c6ac2..4b7008a541 100644 --- a/public/src/forum/admin/index.js +++ b/public/src/forum/admin/index.js @@ -1,25 +1,28 @@ +define(function() { + var Admin = {}; -(function() { + Admin.init = function() { + ajaxify.register_events(['api:get_all_rooms']); + socket.on('api:get_all_rooms', function(data) { - ajaxify.register_events(['api:get_all_rooms']); - socket.on('api:get_all_rooms', function(data) { + var active_users = document.getElementById('active_users'), + total = 0; + active_users.innerHTML = ''; - var active_users = document.getElementById('active_users'), - total = 0; - active_users.innerHTML = ''; - - for (var room in data) { - if (room !== '') { - var count = data[room].length; - total += count; - active_users.innerHTML = active_users.innerHTML + "<div class='alert alert-success'><strong>" + room + "</strong> " + count + " active user" + (count > 1 ? "s" : "") + "</div>"; + for (var room in data) { + if (room !== '') { + var count = data[room].length; + total += count; + active_users.innerHTML = active_users.innerHTML + "<div class='alert alert-success'><strong>" + room + "</strong> " + count + " active user" + (count > 1 ? "s" : "") + "</div>"; + } } - } - document.getElementById('connections').innerHTML = total; - }); + document.getElementById('connections').innerHTML = total; + }); - app.enter_room('admin'); - socket.emit('api:get_all_rooms'); + app.enter_room('admin'); + socket.emit('api:get_all_rooms'); + }; -}()); \ No newline at end of file + return Admin; +}); diff --git a/public/src/forum/admin/plugins.js b/public/src/forum/admin/plugins.js index 297fc6eb3c..daa3e04eb2 100644 --- a/public/src/forum/admin/plugins.js +++ b/public/src/forum/admin/plugins.js @@ -1,7 +1,5 @@ -var nodebb_admin = nodebb_admin || {}; - -(function() { - var plugins = { +define(function() { + var Plugins = { init: function() { var pluginsList = $('.plugins'), numPlugins = pluginsList[0].querySelectorAll('li').length, @@ -31,8 +29,5 @@ var nodebb_admin = nodebb_admin || {}; } }; - jQuery(document).ready(function() { - nodebb_admin.plugins = plugins; - nodebb_admin.plugins.init(); - }); -})(); \ No newline at end of file + return Plugins; +}); \ No newline at end of file diff --git a/public/src/forum/admin/settings.js b/public/src/forum/admin/settings.js new file mode 100644 index 0000000000..75f1a78c83 --- /dev/null +++ b/public/src/forum/admin/settings.js @@ -0,0 +1,81 @@ +define(function() { + var Settings = {}; + + Settings.config = {}; + + Settings.init = function() { + Settings.prepare(); + }; + + Settings.prepare = function() { + // Come back in 500ms if the config isn't ready yet + if (Settings.config === undefined) { + setTimeout(function() { + Settings.prepare(); + }, 500); + return; + } + + // Populate the fields on the page from the config + var fields = document.querySelectorAll('#content [data-field]'), + numFields = fields.length, + saveBtn = document.getElementById('save'), + x, key, inputType; + for (x = 0; x < numFields; x++) { + key = fields[x].getAttribute('data-field'); + inputType = fields[x].getAttribute('type'); + if (fields[x].nodeName === 'INPUT') { + if (Settings.config[key]) { + switch (inputType) { + case 'text': + case 'textarea': + case 'number': + fields[x].value = Settings.config[key]; + break; + + case 'checkbox': + fields[x].checked = Settings.config[key] === '1' ? true : false; + break; + } + } + } else if (fields[x].nodeName === 'TEXTAREA') { + if (Settings.config[key]) fields[x].value = Settings.config[key]; + } + } + + saveBtn.addEventListener('click', function(e) { + var key, value; + e.preventDefault(); + + for (x = 0; x < numFields; x++) { + key = fields[x].getAttribute('data-field'); + if (fields[x].nodeName === 'INPUT') { + inputType = fields[x].getAttribute('type'); + switch (inputType) { + case 'text': + case 'number': + value = fields[x].value; + break; + + case 'checkbox': + value = fields[x].checked ? '1' : '0'; + break; + } + } else if (fields[x].nodeName === 'TEXTAREA') { + value = fields[x].value; + } + + socket.emit('api:config.set', { + key: key, + value: value + }); + } + }); + }; + + Settings.remove = function(key) { + socket.emit('api:config.remove', key); + }; + + return Settings; +}); \ No newline at end of file diff --git a/public/src/forum/admin/themes.js b/public/src/forum/admin/themes.js index 05440189cb..1b4f0f8e4d 100644 --- a/public/src/forum/admin/themes.js +++ b/public/src/forum/admin/themes.js @@ -1,8 +1,91 @@ -var nodebb_admin = (function(nodebb_admin) { +define(function() { + var Themes = {}; - var themes = {}; + Themes.init = function() { + var scriptEl = document.createElement('script'); + scriptEl.src = 'http://api.bootswatch.com/3/?callback=bootswatchListener'; + document.body.appendChild(scriptEl); - themes.render = function(bootswatch) { + var bootstrapThemeContainer = document.querySelector('#bootstrap_themes'), + installedThemeContainer = document.querySelector('#installed_themes'), + themeEvent = function(e) { + if (e.target.hasAttribute('data-action')) { + switch (e.target.getAttribute('data-action')) { + case 'preview': + var cssSrc = $(e.target).parents('li').attr('data-css'), + cssEl = document.getElementById('base-theme'); + + cssEl.href = cssSrc; + break; + case 'use': + var parentEl = $(e.target).parents('li'), + cssSrc = parentEl.attr('data-css'), + cssName = parentEl.attr('data-theme'); + socket.emit('api:config.set', { + key: 'theme:id', + value: 'bootswatch:' + cssName + }); + socket.emit('api:config.set', { + key: 'theme:src', + value: cssSrc + }); + break; + } + } + }; + bootstrapThemeContainer.addEventListener('click', themeEvent); + installedThemeContainer.addEventListener('click', themeEvent); + + var revertEl = document.getElementById('revert_theme'); + revertEl.addEventListener('click', function() { + bootbox.confirm('Are you sure you wish to remove the custom theme and restore the NodeBB default theme?', function(confirm) { + if (confirm) { + require(['forum/admin/settings'], function(Settings) { + Settings.remove('theme:id'); + Settings.remove('theme:src'); + }); + } + }); + }, false); + + // Installed Themes + socket.emit('api:admin.themes.getInstalled', function(themes) { + var instListEl = document.getElementById('installed_themes'), + themeFrag = document.createDocumentFragment(), + liEl = document.createElement('li'); + + if (themes.length > 0) { + for (var x = 0, numThemes = themes.length; x < numThemes; x++) { + liEl.setAttribute('data-theme', themes[x].id); + liEl.setAttribute('data-css', themes[x].src); + liEl.innerHTML = '<img src="' + themes[x].screenshot + '" />' + + '<div>' + + '<div class="pull-right">' + + '<button class="btn btn-primary" data-action="use">Use</button> ' + + '<button class="btn btn-default" data-action="preview">Preview</button>' + + '</div>' + + '<h4>' + themes[x].name + '</h4>' + + '<p>' + + themes[x].description + + (themes[x].url ? ' (<a href="' + themes[x].url + '">Homepage</a>)' : '') + + '</p>' + + '</div>' + + '<div class="clear">'; + themeFrag.appendChild(liEl.cloneNode(true)); + } + } else { + // No themes found + liEl.className = 'no-themes'; + liEl.innerHTML = 'No installed themes found'; + themeFrag.appendChild(liEl); + } + + instListEl.innerHTML = ''; + instListEl.appendChild(themeFrag); + }); + } + + Themes.render = function(bootswatch) { var themeFrag = document.createDocumentFragment(), themeEl = document.createElement('li'), themeContainer = document.querySelector('#bootstrap_themes'), @@ -28,91 +111,5 @@ var nodebb_admin = (function(nodebb_admin) { themeContainer.appendChild(themeFrag); } - nodebb_admin.themes = themes; - - return nodebb_admin; - -}(nodebb_admin || {})); - - -(function() { - var scriptEl = document.createElement('script'); - scriptEl.src = 'http://api.bootswatch.com/3/?callback=nodebb_admin.themes.render'; - document.body.appendChild(scriptEl); - - var bootstrapThemeContainer = document.querySelector('#bootstrap_themes'), - installedThemeContainer = document.querySelector('#installed_themes'), - themeEvent = function(e) { - if (e.target.hasAttribute('data-action')) { - switch (e.target.getAttribute('data-action')) { - case 'preview': - var cssSrc = $(e.target).parents('li').attr('data-css'), - cssEl = document.getElementById('base-theme'); - - cssEl.href = cssSrc; - break; - case 'use': - var parentEl = $(e.target).parents('li'), - cssSrc = parentEl.attr('data-css'), - cssName = parentEl.attr('data-theme'); - socket.emit('api:config.set', { - key: 'theme:id', - value: 'bootswatch:' + cssName - }); - socket.emit('api:config.set', { - key: 'theme:src', - value: cssSrc - }); - break; - } - } - }; - bootstrapThemeContainer.addEventListener('click', themeEvent); - installedThemeContainer.addEventListener('click', themeEvent); - - var revertEl = document.getElementById('revert_theme'); - revertEl.addEventListener('click', function() { - bootbox.confirm('Are you sure you wish to remove the custom theme and restore the NodeBB default theme?', function(confirm) { - if (confirm) { - nodebb_admin.remove('theme:id'); - nodebb_admin.remove('theme:src'); - } - }); - }, false); - - // Installed Themes - socket.emit('api:admin.themes.getInstalled', function(themes) { - var instListEl = document.getElementById('installed_themes'), - themeFrag = document.createDocumentFragment(), - liEl = document.createElement('li'); - - if (themes.length > 0) { - for (var x = 0, numThemes = themes.length; x < numThemes; x++) { - liEl.setAttribute('data-theme', themes[x].id); - liEl.setAttribute('data-css', themes[x].src); - liEl.innerHTML = '<img src="' + themes[x].screenshot + '" />' + - '<div>' + - '<div class="pull-right">' + - '<button class="btn btn-primary" data-action="use">Use</button> ' + - '<button class="btn btn-default" data-action="preview">Preview</button>' + - '</div>' + - '<h4>' + themes[x].name + '</h4>' + - '<p>' + - themes[x].description + - (themes[x].url ? ' (<a href="' + themes[x].url + '">Homepage</a>)' : '') + - '</p>' + - '</div>' + - '<div class="clear">'; - themeFrag.appendChild(liEl.cloneNode(true)); - } - } else { - // No themes found - liEl.className = 'no-themes'; - liEl.innerHTML = 'No installed themes found'; - themeFrag.appendChild(liEl); - } - - instListEl.innerHTML = ''; - instListEl.appendChild(themeFrag); - }); -})(); \ No newline at end of file + return Themes; +}); \ No newline at end of file diff --git a/public/src/forum/admin/topics.js b/public/src/forum/admin/topics.js index 040197df82..8960bed25d 100644 --- a/public/src/forum/admin/topics.js +++ b/public/src/forum/admin/topics.js @@ -1,127 +1,133 @@ -$(document).ready(function() { - var topicsListEl = document.querySelector('.topics'), - loadMoreEl = document.getElementById('topics_loadmore'); - - $(topicsListEl).on('click', '[data-action]', function() { - var $this = $(this), - action = this.getAttribute('data-action'), - tid = $this.parents('[data-tid]').attr('data-tid'); - - switch (action) { - case 'pin': - if (!$this.hasClass('active')) socket.emit('api:topic.pin', { - tid: tid +define(function() { + var Topics = {}; + + Topics.init = function() { + var topicsListEl = document.querySelector('.topics'), + loadMoreEl = document.getElementById('topics_loadmore'); + + $(topicsListEl).on('click', '[data-action]', function() { + var $this = $(this), + action = this.getAttribute('data-action'), + tid = $this.parents('[data-tid]').attr('data-tid'); + + switch (action) { + case 'pin': + if (!$this.hasClass('active')) socket.emit('api:topic.pin', { + tid: tid + }); + else socket.emit('api:topic.unpin', { + tid: tid + }); + break; + case 'lock': + if (!$this.hasClass('active')) socket.emit('api:topic.lock', { + tid: tid + }); + else socket.emit('api:topic.unlock', { + tid: tid + }); + break; + case 'delete': + if (!$this.hasClass('active')) socket.emit('api:topic.delete', { + tid: tid + }); + else socket.emit('api:topic.restore', { + tid: tid + }); + break; + } + }); + + loadMoreEl.addEventListener('click', function() { + if (this.className.indexOf('disabled') === -1) { + var topics = document.querySelectorAll('.topics li[data-tid]'), + lastTid = parseInt(topics[topics.length - 1].getAttribute('data-tid')); + + this.innerHTML = '<i class="icon-refresh icon-spin"></i> Retrieving topics'; + socket.emit('api:admin.topics.getMore', { + limit: 10, + after: lastTid + }, function(topics) { + var btnEl = document.getElementById('topics_loadmore'); + + topics = JSON.parse(topics); + if (topics.length > 0) { + var html = templates.prepare(templates['admin/topics'].blocks['topics']).parse({ + topics: topics + }), + topicsListEl = document.querySelector('.topics'); + + topicsListEl.innerHTML += html; + btnEl.innerHTML = 'Load More Topics'; + } else { + // Exhausted all topics + btnEl.className += ' disabled'; + btnEl.innerHTML = 'No more topics'; + } }); - else socket.emit('api:topic.unpin', { - tid: tid - }); - break; - case 'lock': - if (!$this.hasClass('active')) socket.emit('api:topic.lock', { - tid: tid - }); - else socket.emit('api:topic.unlock', { - tid: tid - }); - break; - case 'delete': - if (!$this.hasClass('active')) socket.emit('api:topic.delete', { - tid: tid - }); - else socket.emit('api:topic.restore', { - tid: tid - }); - break; + } + }, false); + + // Resolve proper button state for all topics + var topicEls = topicsListEl.querySelectorAll('li'), + numTopics = topicEls.length; + for (var x = 0; x < numTopics; x++) { + if (topicEls[x].getAttribute('data-pinned') === '1') topicEls[x].querySelector('[data-action="pin"]').className += ' active'; + if (topicEls[x].getAttribute('data-locked') === '1') topicEls[x].querySelector('[data-action="lock"]').className += ' active'; + if (topicEls[x].getAttribute('data-deleted') === '1') topicEls[x].querySelector('[data-action="delete"]').className += ' active'; + topicEls[x].removeAttribute('data-pinned'); + topicEls[x].removeAttribute('data-locked'); + topicEls[x].removeAttribute('data-deleted'); } - }); - - loadMoreEl.addEventListener('click', function() { - if (this.className.indexOf('disabled') === -1) { - var topics = document.querySelectorAll('.topics li[data-tid]'), - lastTid = parseInt(topics[topics.length - 1].getAttribute('data-tid')); - - this.innerHTML = '<i class="icon-refresh icon-spin"></i> Retrieving topics'; - socket.emit('api:admin.topics.getMore', { - limit: 10, - after: lastTid - }, function(topics) { - var btnEl = document.getElementById('topics_loadmore'); - - topics = JSON.parse(topics); - if (topics.length > 0) { - var html = templates.prepare(templates['admin/topics'].blocks['topics']).parse({ - topics: topics - }), - topicsListEl = document.querySelector('.topics'); - - topicsListEl.innerHTML += html; - btnEl.innerHTML = 'Load More Topics'; - } else { - // Exhausted all topics - btnEl.className += ' disabled'; - btnEl.innerHTML = 'No more topics'; - } - }); - } - }, false); - - // Resolve proper button state for all topics - var topicEls = topicsListEl.querySelectorAll('li'), - numTopics = topicEls.length; - for (var x = 0; x < numTopics; x++) { - if (topicEls[x].getAttribute('data-pinned') === '1') topicEls[x].querySelector('[data-action="pin"]').className += ' active'; - if (topicEls[x].getAttribute('data-locked') === '1') topicEls[x].querySelector('[data-action="lock"]').className += ' active'; - if (topicEls[x].getAttribute('data-deleted') === '1') topicEls[x].querySelector('[data-action="delete"]').className += ' active'; - topicEls[x].removeAttribute('data-pinned'); - topicEls[x].removeAttribute('data-locked'); - topicEls[x].removeAttribute('data-deleted'); - } -}); - -socket.on('api:topic.pin', function(response) { - if (response.status === 'ok') { - var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="pin"]'); - - $(btnEl).addClass('active'); - } -}); - -socket.on('api:topic.unpin', function(response) { - if (response.status === 'ok') { - var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="pin"]'); - - $(btnEl).removeClass('active'); - } -}); - -socket.on('api:topic.lock', function(response) { - if (response.status === 'ok') { - var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="lock"]'); - - $(btnEl).addClass('active'); - } -}); - -socket.on('api:topic.unlock', function(response) { - if (response.status === 'ok') { - var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="lock"]'); - - $(btnEl).removeClass('active'); - } -}); - -socket.on('api:topic.delete', function(response) { - if (response.status === 'ok') { - var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="delete"]'); - - $(btnEl).addClass('active'); - } -}); - -socket.on('api:topic.restore', function(response) { - if (response.status === 'ok') { - var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="delete"]'); - - $(btnEl).removeClass('active'); - } + + socket.on('api:topic.pin', function(response) { + if (response.status === 'ok') { + var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="pin"]'); + + $(btnEl).addClass('active'); + } + }); + + socket.on('api:topic.unpin', function(response) { + if (response.status === 'ok') { + var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="pin"]'); + + $(btnEl).removeClass('active'); + } + }); + + socket.on('api:topic.lock', function(response) { + if (response.status === 'ok') { + var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="lock"]'); + + $(btnEl).addClass('active'); + } + }); + + socket.on('api:topic.unlock', function(response) { + if (response.status === 'ok') { + var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="lock"]'); + + $(btnEl).removeClass('active'); + } + }); + + socket.on('api:topic.delete', function(response) { + if (response.status === 'ok') { + var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="delete"]'); + + $(btnEl).addClass('active'); + } + }); + + socket.on('api:topic.restore', function(response) { + if (response.status === 'ok') { + var btnEl = document.querySelector('li[data-tid="' + response.tid + '"] button[data-action="delete"]'); + + $(btnEl).removeClass('active'); + } + }); + }; + + return Topics; }); \ No newline at end of file diff --git a/public/src/forum/admin/users.js b/public/src/forum/admin/users.js index 4f9ba9dc88..6d41fb10b3 100644 --- a/public/src/forum/admin/users.js +++ b/public/src/forum/admin/users.js @@ -1,170 +1,174 @@ -(function() { - - var yourid = templates.get('yourid'); - - function isUserAdmin(element) { - var parent = $(element).parents('.users-box'); - return (parent.attr('data-admin') !== "0"); - } - - function isUserBanned(element) { - var parent = $(element).parents('.users-box'); - return (parent.attr('data-banned') !== "" && parent.attr('data-banned') !== "0"); - } - - function getUID(element) { - var parent = $(element).parents('.users-box'); - return parent.attr('data-uid'); - } - - function updateUserButtons() { - jQuery('.ban-btn').each(function(index, element) { - var banBtn = $(element); - var uid = getUID(banBtn); - if (isUserAdmin(banBtn) || uid === yourid) - banBtn.addClass('disabled'); - else if (isUserBanned(banBtn)) - banBtn.addClass('btn-warning'); - else - banBtn.removeClass('btn-warning'); +define(function() { + var Users = {}; - }); - } + Users.init = function() { + var yourid = templates.get('yourid'); - function initUsers() { + function isUserAdmin(element) { + var parent = $(element).parents('.users-box'); + return (parent.attr('data-admin') !== "0"); + } - updateUserButtons(); + function isUserBanned(element) { + var parent = $(element).parents('.users-box'); + return (parent.attr('data-banned') !== "" && parent.attr('data-banned') !== "0"); + } - $('#users-container').on('click', '.ban-btn', function() { - var banBtn = $(this); - var isAdmin = isUserAdmin(banBtn); - var isBanned = isUserBanned(banBtn); - var parent = banBtn.parents('.users-box'); - var uid = getUID(banBtn); + function getUID(element) { + var parent = $(element).parents('.users-box'); + return parent.attr('data-uid'); + } - if (!isAdmin) { - if (isBanned) { - socket.emit('api:admin.user.unbanUser', uid); + function updateUserButtons() { + jQuery('.ban-btn').each(function(index, element) { + var banBtn = $(element); + var uid = getUID(banBtn); + if (isUserAdmin(banBtn) || uid === yourid) + banBtn.addClass('disabled'); + else if (isUserBanned(banBtn)) + banBtn.addClass('btn-warning'); + else banBtn.removeClass('btn-warning'); - parent.attr('data-banned', 0); - } else { - bootbox.confirm('Do you really want to ban "' + parent.attr('data-username') + '"?', function(confirm) { - if (confirm) { - socket.emit('api:admin.user.banUser', uid); - banBtn.addClass('btn-warning'); - parent.attr('data-banned', 1); - } - }); - } - } - - return false; - }); - } + }); + } - jQuery('document').ready(function() { + function initUsers() { - var timeoutId = 0, - loadingMoreUsers = false; + updateUserButtons(); - var url = window.location.href, - parts = url.split('/'), - active = parts[parts.length - 1]; + $('#users-container').on('click', '.ban-btn', function() { + var banBtn = $(this); + var isAdmin = isUserAdmin(banBtn); + var isBanned = isUserBanned(banBtn); + var parent = banBtn.parents('.users-box'); + var uid = getUID(banBtn); + + if (!isAdmin) { + if (isBanned) { + socket.emit('api:admin.user.unbanUser', uid); + banBtn.removeClass('btn-warning'); + parent.attr('data-banned', 0); + } else { + bootbox.confirm('Do you really want to ban "' + parent.attr('data-username') + '"?', function(confirm) { + if (confirm) { + socket.emit('api:admin.user.banUser', uid); + banBtn.addClass('btn-warning'); + parent.attr('data-banned', 1); + } + }); + } + } - 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; - } - }); + }); + } - jQuery('#search-user').on('keyup', function() { - if (timeoutId !== 0) { - clearTimeout(timeoutId); - timeoutId = 0; - } - timeoutId = setTimeout(function() { - var username = $('#search-user').val(); + jQuery('document').ready(function() { - jQuery('.icon-spinner').removeClass('none'); - socket.emit('api:admin.user.search', username); + var timeoutId = 0, + loadingMoreUsers = false; - }, 250); - }); + var url = window.location.href, + parts = url.split('/'), + active = parts[parts.length - 1]; - initUsers(); - - socket.removeAllListeners('api:admin.user.search'); - - socket.on('api:admin.user.search', function(data) { - var html = templates.prepare(templates['admin/users'].blocks['users']).parse({ - users: data - }), - userListEl = document.querySelector('.users'); - - userListEl.innerHTML = html; - jQuery('.icon-spinner').addClass('none'); - - if (data && data.length === 0) { - $('#user-notfound-notify').html('User not found!') - .show() - .addClass('label-danger') - .removeClass('label-success'); - } else { - $('#user-notfound-notify').html(data.length + ' user' + (data.length > 1 ? 's' : '') + ' found!') - .show() - .addClass('label-success') - .removeClass('label-danger'); - } + 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; + } + }); + + jQuery('#search-user').on('keyup', function() { + if (timeoutId !== 0) { + clearTimeout(timeoutId); + timeoutId = 0; + } + + timeoutId = setTimeout(function() { + var username = $('#search-user').val(); + + jQuery('.icon-spinner').removeClass('none'); + socket.emit('api:admin.user.search', username); + + }, 250); + }); initUsers(); - }); - function onUsersLoaded(users) { - var html = templates.prepare(templates['admin/users'].blocks['users']).parse({ - users: users + socket.removeAllListeners('api:admin.user.search'); + + socket.on('api:admin.user.search', function(data) { + var html = templates.prepare(templates['admin/users'].blocks['users']).parse({ + users: data + }), + userListEl = document.querySelector('.users'); + + userListEl.innerHTML = html; + jQuery('.icon-spinner').addClass('none'); + + if (data && data.length === 0) { + $('#user-notfound-notify').html('User not found!') + .show() + .addClass('label-danger') + .removeClass('label-success'); + } else { + $('#user-notfound-notify').html(data.length + ' user' + (data.length > 1 ? 's' : '') + ' found!') + .show() + .addClass('label-success') + .removeClass('label-danger'); + } + + initUsers(); }); - $('#users-container').append(html); - updateUserButtons(); - } - function loadMoreUsers() { - var set = ''; - if (active === 'latest') { - set = 'users:joindate'; - } else if (active === 'sort-posts') { - set = 'users:postcount'; - } else if (active === 'sort-reputation') { - set = 'users:reputation'; + function onUsersLoaded(users) { + var html = templates.prepare(templates['admin/users'].blocks['users']).parse({ + users: users + }); + $('#users-container').append(html); + updateUserButtons(); } - if (set) { - loadingMoreUsers = true; - socket.emit('api:users.loadMore', { - set: set, - after: $('#users-container').children().length - }, function(data) { - if (data.users.length) { - onUsersLoaded(data.users); - } - loadingMoreUsers = false; - }); + function loadMoreUsers() { + var set = ''; + if (active === 'latest') { + set = 'users:joindate'; + } else if (active === 'sort-posts') { + set = 'users:postcount'; + } else if (active === 'sort-reputation') { + set = 'users:reputation'; + } + + if (set) { + loadingMoreUsers = true; + socket.emit('api:users.loadMore', { + set: set, + after: $('#users-container').children().length + }, function(data) { + if (data.users.length) { + onUsersLoaded(data.users); + } + loadingMoreUsers = false; + }); + } } - } - $('#load-more-users-btn').on('click', loadMoreUsers); + $('#load-more-users-btn').on('click', loadMoreUsers); - $(window).off('scroll').on('scroll', function() { - var bottom = ($(document).height() - $(window).height()) * 0.9; + $(window).off('scroll').on('scroll', function() { + var bottom = ($(document).height() - $(window).height()) * 0.9; - if ($(window).scrollTop() > bottom && !loadingMoreUsers) { - loadMoreUsers(); - } - }); + if ($(window).scrollTop() > bottom && !loadingMoreUsers) { + loadMoreUsers(); + } + }); - }); + }); + }; -}()); \ No newline at end of file + return Users; +}); \ No newline at end of file diff --git a/public/src/forum/category.js b/public/src/forum/category.js index b2bc60a07f..ab16a32369 100644 --- a/public/src/forum/category.js +++ b/public/src/forum/category.js @@ -1,41 +1,86 @@ -(function () { - var cid = templates.get('category_id'), - room = 'category_' + cid, - twitterEl = document.getElementById('twitter-intent'), - facebookEl = document.getElementById('facebook-share'), - googleEl = document.getElementById('google-share'), - twitter_url = templates.get('twitter-intent-url'), - facebook_url = templates.get('facebook-share-url'), - google_url = templates.get('google-share-url'), - loadingMoreTopics = false; - - app.enter_room(room); - - twitterEl.addEventListener('click', function () { - window.open(twitter_url, '_blank', 'width=550,height=420,scrollbars=no,status=no'); - return false; - }, false); - facebookEl.addEventListener('click', function () { - window.open(facebook_url, '_blank', 'width=626,height=436,scrollbars=no,status=no'); - return false; - }, false); - googleEl.addEventListener('click', function () { - window.open(google_url, '_blank', 'width=500,height=570,scrollbars=no,status=no'); - return false; - }, false); - - var new_post = document.getElementById('new_post'); - new_post.onclick = function () { - require(['composer'], function (cmp) { - cmp.push(0, cid); +define(function () { + var Category = {}; + + Category.init = function() { + var cid = templates.get('category_id'), + room = 'category_' + cid, + twitterEl = document.getElementById('twitter-intent'), + facebookEl = document.getElementById('facebook-share'), + googleEl = document.getElementById('google-share'), + twitter_url = templates.get('twitter-intent-url'), + facebook_url = templates.get('facebook-share-url'), + google_url = templates.get('google-share-url'), + loadingMoreTopics = false; + + app.enter_room(room); + + twitterEl.addEventListener('click', function () { + window.open(twitter_url, '_blank', 'width=550,height=420,scrollbars=no,status=no'); + return false; + }, false); + facebookEl.addEventListener('click', function () { + window.open(facebook_url, '_blank', 'width=626,height=436,scrollbars=no,status=no'); + return false; + }, false); + googleEl.addEventListener('click', function () { + window.open(google_url, '_blank', 'width=500,height=570,scrollbars=no,status=no'); + return false; + }, false); + + var new_post = document.getElementById('new_post'); + new_post.onclick = function () { + require(['composer'], function (cmp) { + cmp.push(0, cid); + }); + } + + ajaxify.register_events([ + 'event:new_topic' + ]); + + socket.on('event:new_topic', Category.onNewTopic); + + socket.emit('api:categories.getRecentReplies', cid); + socket.on('api:categories.getRecentReplies', function (posts) { + if (!posts || posts.length === 0) { + return; + } + + var recent_replies = document.getElementById('category_recent_replies'); + + recent_replies.innerHTML = ''; + + var frag = document.createDocumentFragment(), + li = document.createElement('li'); + for (var i = 0, numPosts = posts.length; i < numPosts; i++) { + + li.setAttribute('data-pid', posts[i].pid); + + + li.innerHTML = '<a href="/user/' + posts[i].userslug + '"><img title="' + posts[i].username + '" style="width: 48px; height: 48px; /*temporary*/" class="img-rounded" src="' + posts[i].picture + '" class="" /></a>' + + '<a href="/topic/' + posts[i].topicSlug + '#' + posts[i].pid + '">' + + '<p>' + + posts[i].content + + '</p>' + + '<p class="meta"><strong>' + posts[i].username + '</strong></span> -<span class="timeago" title="' + posts[i].relativeTime + '"></span></p>' + + '</a>'; + + frag.appendChild(li.cloneNode(true)); + recent_replies.appendChild(frag); + } + $('#category_recent_replies span.timeago').timeago(); }); - } - ajaxify.register_events([ - 'event:new_topic' - ]); + $(window).off('scroll').on('scroll', function (ev) { + var bottom = ($(document).height() - $(window).height()) * 0.9; - function onNewTopic(data) { + if ($(window).scrollTop() > bottom && !loadingMoreTopics) { + Category.loadMoreTopics(cid); + } + }); + }; + + Category.onNewTopic = function(data) { var html = templates.prepare(templates['category'].blocks['topics']).parse({ topics: [data] }), @@ -64,40 +109,7 @@ $('#topics-container span.timeago').timeago(); } - socket.on('event:new_topic', onNewTopic); - - socket.emit('api:categories.getRecentReplies', cid); - socket.on('api:categories.getRecentReplies', function (posts) { - if (!posts || posts.length === 0) { - return; - } - - var recent_replies = document.getElementById('category_recent_replies'); - - recent_replies.innerHTML = ''; - - var frag = document.createDocumentFragment(), - li = document.createElement('li'); - for (var i = 0, numPosts = posts.length; i < numPosts; i++) { - - li.setAttribute('data-pid', posts[i].pid); - - - li.innerHTML = '<a href="/user/' + posts[i].userslug + '"><img title="' + posts[i].username + '" style="width: 48px; height: 48px; /*temporary*/" class="img-rounded" src="' + posts[i].picture + '" class="" /></a>' + - '<a href="/topic/' + posts[i].topicSlug + '#' + posts[i].pid + '">' + - '<p>' + - posts[i].content + - '</p>' + - '<p class="meta"><strong>' + posts[i].username + '</strong></span> -<span class="timeago" title="' + posts[i].relativeTime + '"></span></p>' + - '</a>'; - - frag.appendChild(li.cloneNode(true)); - recent_replies.appendChild(frag); - } - $('#category_recent_replies span.timeago').timeago(); - }); - - function onTopicsLoaded(topics) { + Category.onTopicsLoaded = function(topics) { var html = templates.prepare(templates['category'].blocks['topics']).parse({ topics: topics @@ -113,26 +125,18 @@ } - function loadMoreTopics(cid) { + Category.loadMoreTopics = function(cid) { loadingMoreTopics = true; socket.emit('api:category.loadMore', { cid: cid, after: $('#topics-container').children().length }, function (data) { if (data.topics.length) { - onTopicsLoaded(data.topics); + Category.onTopicsLoaded(data.topics); } loadingMoreTopics = false; }); } - $(window).off('scroll').on('scroll', function (ev) { - var bottom = ($(document).height() - $(window).height()) * 0.9; - - if ($(window).scrollTop() > bottom && !loadingMoreTopics) { - loadMoreTopics(cid); - } - }); - - -})(); \ No newline at end of file + return Category; +}); \ No newline at end of file diff --git a/public/src/forum/favourites.js b/public/src/forum/favourites.js index cff01ab271..20b77b4d41 100644 --- a/public/src/forum/favourites.js +++ b/public/src/forum/favourites.js @@ -1,7 +1,13 @@ -(function() { - $(document).ready(function() { +define(['forum/accountheader'], function(header) { + var AccountHeader = {}; + + AccountHeader.init = function() { + header.init(); + $('.user-favourite-posts .topic-row').on('click', function() { ajaxify.go($(this).attr('topic-url')); }); - }); -}()); \ No newline at end of file + }; + + return AccountHeader; +}); \ No newline at end of file diff --git a/public/src/forum/followers.js b/public/src/forum/followers.js index 0fcb464f0b..ee955ff615 100644 --- a/public/src/forum/followers.js +++ b/public/src/forum/followers.js @@ -1,18 +1,20 @@ -(function() { +define(['forum/accountheader'], function(header) { + var Followers = {}; - var yourid = templates.get('yourid'), - theirid = templates.get('theirid'), - followersCount = templates.get('followersCount'); + Followers.init = function() { + header.init(); - $(document).ready(function() { + var yourid = templates.get('yourid'), + theirid = templates.get('theirid'), + followersCount = templates.get('followersCount'); - if (parseInt(followersCount, 10) === 0) { - $('#no-followers-notice').removeClass('hide'); - } - app.addCommasToNumbers(); - - }); + if (parseInt(followersCount, 10) === 0) { + $('#no-followers-notice').removeClass('hide'); + } + app.addCommasToNumbers(); + }; -}()); \ No newline at end of file + return Followers; +}); \ No newline at end of file diff --git a/public/src/forum/following.js b/public/src/forum/following.js index cd31d25466..7e1c2cde4c 100644 --- a/public/src/forum/following.js +++ b/public/src/forum/following.js @@ -1,10 +1,12 @@ -(function() { +define(['forum/accountheader'], function(header) { + var Following = {}; - var yourid = templates.get('yourid'), - theirid = templates.get('theirid'), - followingCount = templates.get('followingCount'); + Following.init = function() { + header.init(); - $(document).ready(function() { + var yourid = templates.get('yourid'), + theirid = templates.get('theirid'), + followingCount = templates.get('followingCount'); if (parseInt(followingCount, 10) === 0) { $('#no-following-notice').removeClass('hide'); @@ -34,7 +36,7 @@ } app.addCommasToNumbers(); - }); + }; - -}()); \ No newline at end of file + return Following; +}); \ No newline at end of file diff --git a/public/src/forum/login.js b/public/src/forum/login.js index b99465668a..ed4e0753f6 100644 --- a/public/src/forum/login.js +++ b/public/src/forum/login.js @@ -1,60 +1,66 @@ -(function() { - // Alternate Logins - var altLoginEl = document.querySelector('.alt-logins'); - altLoginEl.addEventListener('click', function(e) { - var target; - switch (e.target.nodeName) { - case 'LI': - target = e.target; - break; - case 'I': - target = e.target.parentNode; - break; - } - if (target) { - document.location.href = target.getAttribute('data-url'); - } - }); - - $('#login').on('click', function() { - var loginData = { - 'username': $('#username').val(), - 'password': $('#password').val(), - '_csrf': $('#csrf-token').val() - }; - - $.ajax({ - type: "POST", - url: RELATIVE_PATH + '/login', - data: loginData, - success: function(data, textStatus, jqXHR) { - if (!data.success) { +define(function() { + var Login = {}; + + Login.init = function() { + // Alternate Logins + var altLoginEl = document.querySelector('.alt-logins'); + altLoginEl.addEventListener('click', function(e) { + var target; + switch (e.target.nodeName) { + case 'LI': + target = e.target; + break; + case 'I': + target = e.target.parentNode; + break; + } + if (target) { + document.location.href = target.getAttribute('data-url'); + } + }); + + $('#login').on('click', function() { + var loginData = { + 'username': $('#username').val(), + 'password': $('#password').val(), + '_csrf': $('#csrf-token').val() + }; + + $.ajax({ + type: "POST", + url: RELATIVE_PATH + '/login', + data: loginData, + success: function(data, textStatus, jqXHR) { + if (!data.success) { + $('#login-error-notify').show(); + } else { + $('#login-error-notify').hide(); + if(app.previousUrl.indexOf('/reset/') != -1) + window.location.replace(RELATIVE_PATH + "/?loggedin"); + else + window.location.replace(app.previousUrl + "?loggedin"); + + app.loadConfig(); + } + }, + error: function(data, textStatus, jqXHR) { $('#login-error-notify').show(); - } else { - $('#login-error-notify').hide(); - if(app.previousUrl.indexOf('/reset/') != -1) - window.location.replace(RELATIVE_PATH + "/?loggedin"); - else - window.location.replace(app.previousUrl + "?loggedin"); - - app.loadConfig(); - } - }, - error: function(data, textStatus, jqXHR) { - $('#login-error-notify').show(); - }, - dataType: 'json', - async: true, - timeout: 2000 + }, + dataType: 'json', + async: true, + timeout: 2000 + }); + + return false; }); - return false; - }); + $('#login-error-notify button').on('click', function() { + $('#login-error-notify').hide(); + return false; + }); - $('#login-error-notify button').on('click', function() { - $('#login-error-notify').hide(); - return false; - }); + document.querySelector('#content input').focus(); + }; - document.querySelector('#content input').focus(); -}()); \ No newline at end of file + return Login; +}); \ No newline at end of file diff --git a/public/src/forum/recent.js b/public/src/forum/recent.js index f9b1fe228c..5fed07107e 100644 --- a/public/src/forum/recent.js +++ b/public/src/forum/recent.js @@ -1,40 +1,56 @@ -(function() { - var loadingMoreTopics = false; +define(function() { + var Recent = {}; - app.enter_room('recent_posts'); + Recent.newTopicCount = 0; + Recent.newPostCount = 0; + Recent.loadingMoreTopics = false; - ajaxify.register_events([ - 'event:new_topic', - 'event:new_post' - ]); + Recent.init = function() { + app.enter_room('recent_posts'); - var newTopicCount = 0, - newPostCount = 0; + ajaxify.register_events([ + 'event:new_topic', + 'event:new_post' + ]); - $('#new-topics-alert').on('click', function() { - $(this).hide(); - }); + $('#new-topics-alert').on('click', function() { + $(this).hide(); + }); + + socket.on('event:new_topic', function(data) { + + ++Recent.newTopicCount; + Recent.updateAlertText(); - socket.on('event:new_topic', function(data) { + }); + + socket.on('event:new_post', function(data) { + ++Recent.newPostCount; + Recent.updateAlertText(); + }); - ++newTopicCount; - updateAlertText(); + $(window).off('scroll').on('scroll', function() { + var bottom = ($(document).height() - $(window).height()) * 0.9; - }); + if ($(window).scrollTop() > bottom && !Recent.loadingMoreTopics) { + Recent.loadMoreTopics(); + } + }); + }; - function updateAlertText() { + Recent.updateAlertText = function() { var text = ''; - if (newTopicCount > 1) - text = 'There are ' + newTopicCount + ' new topics'; - else if (newTopicCount === 1) + if (Recent.newTopicCount > 1) + text = 'There are ' + Recent.newTopicCount + ' new topics'; + else if (Recent.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) + if (Recent.newPostCount > 1) + text += ' and ' + Recent.newPostCount + ' new posts.'; + else if (Recent.newPostCount === 1) text += ' and 1 new post.'; else text += ' and no new posts.'; @@ -44,12 +60,7 @@ $('#new-topics-alert').html(text).fadeIn('slow'); } - socket.on('event:new_post', function(data) { - ++newPostCount; - updateAlertText(); - }); - - function onTopicsLoaded(topics) { + Recent.onTopicsLoaded = function(topics) { var html = templates.prepare(templates['recent'].blocks['topics']).parse({ topics: topics @@ -61,25 +72,17 @@ container.append(html); } - function loadMoreTopics() { - loadingMoreTopics = true; + Recent.loadMoreTopics = function() { + Recent.loadingMoreTopics = true; socket.emit('api:topics.loadMoreRecentTopics', { after: $('#topics-container').children().length }, function(data) { if (data.topics && data.topics.length) { - onTopicsLoaded(data.topics); + Recent.onTopicsLoaded(data.topics); } - loadingMoreTopics = false; + Recent.loadingMoreTopics = false; }); } - $(window).off('scroll').on('scroll', function() { - var bottom = ($(document).height() - $(window).height()) * 0.9; - - if ($(window).scrollTop() > bottom && !loadingMoreTopics) { - loadMoreTopics(); - } - }); - - -})(); \ No newline at end of file + return Recent; +}); diff --git a/public/src/forum/register.js b/public/src/forum/register.js index e485f4960f..fc7cf26b2a 100644 --- a/public/src/forum/register.js +++ b/public/src/forum/register.js @@ -1,154 +1,159 @@ -(function() { - var username = $('#username'), - password = $('#password'), - password_confirm = $('#password-confirm'), - register = $('#register'), - emailEl = $('#email'), - username_notify = $('#username-notify'), - email_notify = $('#email-notify'), - password_notify = $('#password-notify'), - password_confirm_notify = $('#password-confirm-notify'), - validationError = false, - successIcon = '<i class="icon icon-ok"></i>'; - - $('#referrer').val(app.previousUrl); - - function showError(element, msg) { - element.html(msg); - element.parent() - .removeClass('alert-success') - .addClass('alert-danger'); - element.show(); - validationError = true; - } - - function showSuccess(element, msg) { - element.html(msg); - element.parent() - .removeClass('alert-danger') - .addClass('alert-success'); - element.show(); - } - - function validateEmail() { - if (!emailEl.val()) { +define(function() { + var Register = {}; + + Register.init = function() { + var username = $('#username'), + password = $('#password'), + password_confirm = $('#password-confirm'), + register = $('#register'), + emailEl = $('#email'), + username_notify = $('#username-notify'), + email_notify = $('#email-notify'), + password_notify = $('#password-notify'), + password_confirm_notify = $('#password-confirm-notify'), + validationError = false, + successIcon = '<i class="icon icon-ok"></i>'; + + $('#referrer').val(app.previousUrl); + + function showError(element, msg) { + element.html(msg); + element.parent() + .removeClass('alert-success') + .addClass('alert-danger'); + element.show(); validationError = true; - return; } - if (!utils.isEmailValid(emailEl.val())) { - showError(email_notify, 'Invalid email address.'); - } else - socket.emit('user.email.exists', { - email: emailEl.val() - }); - } - - emailEl.on('blur', function() { - validateEmail(); - }); - - function validateUsername() { - if (!username.val()) { - validationError = true; - return; - } - - if (username.val().length < config.minimumUsernameLength) { - showError(username_notify, 'Username too short!'); - } else if (username.val().length > config.maximumUsernameLength) { - showError(username_notify, 'Username too long!'); - } else if (!utils.isUserNameValid(username.val())) { - showError(username_notify, 'Invalid username!'); - } else { - socket.emit('user.exists', { - username: username.val() - }); - } - } - - username.on('keyup', function() { - jQuery('#yourUsername').html(this.value.length > 0 ? this.value : 'username'); - }); - username.on('blur', function() { - validateUsername(); - }); - - function validatePassword() { - if (!password.val()) { - validationError = true; - return; - } - - if (password.val().length < config.minimumPasswordLength) { - showError(password_notify, 'Password too short!'); - } else if (!utils.isPasswordValid(password.val())) { - showError(password_notify, 'Invalid password!'); - } else { - showSuccess(password_notify, successIcon); + function showSuccess(element, msg) { + element.html(msg); + element.parent() + .removeClass('alert-danger') + .addClass('alert-success'); + element.show(); } - if (password.val() !== password_confirm.val() && password_confirm.val() !== '') { - showError(password_confirm_notify, 'Passwords must match!'); + function validateEmail() { + if (!emailEl.val()) { + validationError = true; + return; + } + + if (!utils.isEmailValid(emailEl.val())) { + showError(email_notify, 'Invalid email address.'); + } else + socket.emit('user.email.exists', { + email: emailEl.val() + }); } - } - - $(password).on('blur', function() { - validatePassword(); - }); - function validatePasswordConfirm() { - if (!password.val() || password_notify.hasClass('alert-error')) { - return; + emailEl.on('blur', function() { + validateEmail(); + }); + + function validateUsername() { + if (!username.val()) { + validationError = true; + return; + } + + if (username.val().length < config.minimumUsernameLength) { + showError(username_notify, 'Username too short!'); + } else if (username.val().length > config.maximumUsernameLength) { + showError(username_notify, 'Username too long!'); + } else if (!utils.isUserNameValid(username.val())) { + showError(username_notify, 'Invalid username!'); + } else { + socket.emit('user.exists', { + username: username.val() + }); + } } - if (password.val() !== password_confirm.val()) { - showError(password_confirm_notify, 'Passwords must match!'); - } else { - showSuccess(password_confirm_notify, successIcon); + username.on('keyup', function() { + jQuery('#yourUsername').html(this.value.length > 0 ? this.value : 'username'); + }); + username.on('blur', function() { + validateUsername(); + }); + + function validatePassword() { + if (!password.val()) { + validationError = true; + return; + } + + if (password.val().length < config.minimumPasswordLength) { + showError(password_notify, 'Password too short!'); + } else if (!utils.isPasswordValid(password.val())) { + showError(password_notify, 'Invalid password!'); + } else { + showSuccess(password_notify, successIcon); + } + + if (password.val() !== password_confirm.val() && password_confirm.val() !== '') { + showError(password_confirm_notify, 'Passwords must match!'); + } } - } - $(password_confirm).on('blur', function() { - validatePasswordConfirm(); - }); + $(password).on('blur', function() { + validatePassword(); + }); - ajaxify.register_events(['user.exists', 'user.email.exists']); + function validatePasswordConfirm() { + if (!password.val() || password_notify.hasClass('alert-error')) { + return; + } - socket.on('user.exists', function(data) { - if (data.exists === true) { - showError(username_notify, 'Username already taken!'); - } else { - showSuccess(username_notify, successIcon); + if (password.val() !== password_confirm.val()) { + showError(password_confirm_notify, 'Passwords must match!'); + } else { + showSuccess(password_confirm_notify, successIcon); + } } - }); - socket.on('user.email.exists', function(data) { - if (data.exists === true) { - showError(email_notify, 'Email address already taken!'); - } else { - showSuccess(email_notify, successIcon); + $(password_confirm).on('blur', function() { + validatePasswordConfirm(); + }); + + ajaxify.register_events(['user.exists', 'user.email.exists']); + + socket.on('user.exists', function(data) { + if (data.exists === true) { + showError(username_notify, 'Username already taken!'); + } else { + showSuccess(username_notify, successIcon); + } + }); + + socket.on('user.email.exists', function(data) { + if (data.exists === true) { + showError(email_notify, 'Email address already taken!'); + } else { + showSuccess(email_notify, successIcon); + } + }); + + // Alternate Logins + $('.alt-logins li').on('click', function(e) { + document.location.href = $(this).attr('data-url'); + }); + + function validateForm() { + validationError = false; + + validateEmail(); + validateUsername(); + validatePassword(); + validatePasswordConfirm(); + + return validationError; } - }); - - // Alternate Logins - $('.alt-logins li').on('click', function(e) { - document.location.href = $(this).attr('data-url'); - }); - - function validateForm() { - validationError = false; - - validateEmail(); - validateUsername(); - validatePassword(); - validatePasswordConfirm(); - - return validationError; - } - register.on('click', function(e) { - if (validateForm()) e.preventDefault(); - }); + register.on('click', function(e) { + if (validateForm()) e.preventDefault(); + }); + }; -}()); \ No newline at end of file + return Register; +}); \ No newline at end of file diff --git a/public/src/forum/reset.js b/public/src/forum/reset.js index 366d382356..150b282fe0 100644 --- a/public/src/forum/reset.js +++ b/public/src/forum/reset.js @@ -1,41 +1,47 @@ -(function() { - var inputEl = document.getElementById('email'), - errorEl = document.getElementById('error'), - errorTextEl = errorEl.querySelector('p'); +define(function() { + var ResetPassword = {}; - document.getElementById('reset').onclick = function() { - if (inputEl.value.length > 0 && inputEl.value.indexOf('@') !== -1) { - socket.emit('user:reset.send', { - email: inputEl.value - }); - } else { - jQuery('#success').hide(); - jQuery(errorEl).show(); - errorTextEl.innerHTML = 'Please enter a valid email'; - } - }; + ResetPassword.init = function() { + var inputEl = document.getElementById('email'), + errorEl = document.getElementById('error'), + errorTextEl = errorEl.querySelector('p'); + + document.getElementById('reset').onclick = function() { + if (inputEl.value.length > 0 && inputEl.value.indexOf('@') !== -1) { + socket.emit('user:reset.send', { + email: inputEl.value + }); + } else { + jQuery('#success').hide(); + jQuery(errorEl).show(); + errorTextEl.innerHTML = 'Please enter a valid email'; + } + }; - ajaxify.register_events(['user.send_reset']); + ajaxify.register_events(['user.send_reset']); - socket.on('user.send_reset', function(data) { - var submitEl = document.getElementById('reset'); + socket.on('user.send_reset', function(data) { + var submitEl = document.getElementById('reset'); - if (data.status === 'ok') { - jQuery('#error').hide(); - jQuery('#success').show(); - jQuery('#success p').html('An email has been dispatched to "' + data.email + '" with instructions on setting a new password.'); - inputEl.value = ''; - } else { - jQuery('#success').hide(); - jQuery(errorEl).show(); - switch (data.message) { - case 'invalid-email': - errorTextEl.innerHTML = 'The email you put in (<span>' + data.email + '</span>) is not registered with us. Please try again.'; - break; - case 'send-failed': - errorTextEl.innerHTML = 'There was a problem sending the reset code. Please try again later.'; - break; + if (data.status === 'ok') { + jQuery('#error').hide(); + jQuery('#success').show(); + jQuery('#success p').html('An email has been dispatched to "' + data.email + '" with instructions on setting a new password.'); + inputEl.value = ''; + } else { + jQuery('#success').hide(); + jQuery(errorEl).show(); + switch (data.message) { + case 'invalid-email': + errorTextEl.innerHTML = 'The email you put in (<span>' + data.email + '</span>) is not registered with us. Please try again.'; + break; + case 'send-failed': + errorTextEl.innerHTML = 'There was a problem sending the reset code. Please try again later.'; + break; + } } - } - }); -}()); \ No newline at end of file + }); + }; + + return ResetPassword; +}); \ No newline at end of file diff --git a/public/src/forum/reset_code.js b/public/src/forum/reset_code.js index 527b0c7bf6..f36ff00836 100644 --- a/public/src/forum/reset_code.js +++ b/public/src/forum/reset_code.js @@ -1,52 +1,58 @@ -(function() { - var reset_code = templates.get('reset_code'); - - var resetEl = document.getElementById('reset'), - password = document.getElementById('password'), - repeat = document.getElementById('repeat'), - noticeEl = document.getElementById('notice'); - - resetEl.addEventListener('click', function() { - if (password.value.length < 6) { - $('#error').hide(); - noticeEl.querySelector('strong').innerHTML = 'Invalid Password'; - noticeEl.querySelector('p').innerHTML = 'The password entered is too short, please pick a different password.'; - noticeEl.style.display = 'block'; - } else if (password.value !== repeat.value) { - $('#error').hide(); - noticeEl.querySelector('strong').innerHTML = 'Invalid Password'; - noticeEl.querySelector('p').innerHTML = 'The two passwords you\'ve entered do not match.'; - noticeEl.style.display = 'block'; - } else { - socket.emit('user:reset.commit', { - code: reset_code, - password: password.value - }); - } - }, false); - - // Enable the form if the code is valid - socket.emit('user:reset.valid', { - code: reset_code - }); - - - ajaxify.register_events(['user:reset.valid', 'user:reset.commit']); - socket.on('user:reset.valid', function(data) { - if ( !! data.valid) resetEl.disabled = false; - else { - var formEl = document.getElementById('reset-form'); - // Show error message - $('#error').show(); - formEl.parentNode.removeChild(formEl); - } - }) - - socket.on('user:reset.commit', function(data) { - if (data.status === 'ok') { - $('#error').hide(); - $('#notice').hide(); - $('#success').show(); - } - }); -}()); \ No newline at end of file +define(function() { + var ResetCode = {}; + + ResetCode.init = function() { + var reset_code = templates.get('reset_code'); + + var resetEl = document.getElementById('reset'), + password = document.getElementById('password'), + repeat = document.getElementById('repeat'), + noticeEl = document.getElementById('notice'); + + resetEl.addEventListener('click', function() { + if (password.value.length < 6) { + $('#error').hide(); + noticeEl.querySelector('strong').innerHTML = 'Invalid Password'; + noticeEl.querySelector('p').innerHTML = 'The password entered is too short, please pick a different password.'; + noticeEl.style.display = 'block'; + } else if (password.value !== repeat.value) { + $('#error').hide(); + noticeEl.querySelector('strong').innerHTML = 'Invalid Password'; + noticeEl.querySelector('p').innerHTML = 'The two passwords you\'ve entered do not match.'; + noticeEl.style.display = 'block'; + } else { + socket.emit('user:reset.commit', { + code: reset_code, + password: password.value + }); + } + }, false); + + // Enable the form if the code is valid + socket.emit('user:reset.valid', { + code: reset_code + }); + + + ajaxify.register_events(['user:reset.valid', 'user:reset.commit']); + socket.on('user:reset.valid', function(data) { + if ( !! data.valid) resetEl.disabled = false; + else { + var formEl = document.getElementById('reset-form'); + // Show error message + $('#error').show(); + formEl.parentNode.removeChild(formEl); + } + }) + + socket.on('user:reset.commit', function(data) { + if (data.status === 'ok') { + $('#error').hide(); + $('#notice').hide(); + $('#success').show(); + } + }); + }; + + return ResetCode; +}); \ No newline at end of file diff --git a/public/src/forum/search.js b/public/src/forum/search.js index f7238ef8c3..619f2676e5 100644 --- a/public/src/forum/search.js +++ b/public/src/forum/search.js @@ -1,6 +1,7 @@ -(function() { +define(function() { + var Search = {}; - $(document).ready(function() { + Search.init = function() { var searchQuery = $('#topics-container').attr('data-search-query'); $('.search-result-text').each(function() { @@ -21,4 +22,5 @@ }); }); -})(); \ No newline at end of file + return Search; +}); \ No newline at end of file diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 159fb970bc..7e10e1c762 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -1,716 +1,722 @@ -(function() { - var expose_tools = templates.get('expose_tools'), - tid = templates.get('topic_id'), - postListEl = document.getElementById('post-container'), - editBtns = document.querySelectorAll('#post-container .post-buttons .edit, #post-container .post-buttons .edit i'), - thread_state = { - locked: templates.get('locked'), - deleted: templates.get('deleted'), - pinned: templates.get('pinned') - }, - topic_name = templates.get('topic_name'); +define(function() { + var Topic = {}; + Topic.init = function() { + var expose_tools = templates.get('expose_tools'), + tid = templates.get('topic_id'), + postListEl = document.getElementById('post-container'), + editBtns = document.querySelectorAll('#post-container .post-buttons .edit, #post-container .post-buttons .edit i'), + thread_state = { + locked: templates.get('locked'), + deleted: templates.get('deleted'), + pinned: templates.get('pinned') + }, + topic_name = templates.get('topic_name'); - jQuery('document').ready(function() { - app.addCommasToNumbers(); + jQuery('document').ready(function() { - var room = 'topic_' + tid, - adminTools = document.getElementById('thread-tools'); + app.addCommasToNumbers(); - app.enter_room(room); + var room = 'topic_' + tid, + adminTools = document.getElementById('thread-tools'); - // Resetting thread state - if (thread_state.locked === '1') set_locked_state(true); - if (thread_state.deleted === '1') set_delete_state(true); - if (thread_state.pinned === '1') set_pinned_state(true); + app.enter_room(room); - if (expose_tools === '1') { - var moveThreadModal = $('#move_thread_modal'); + // Resetting thread state + if (thread_state.locked === '1') set_locked_state(true); + if (thread_state.deleted === '1') set_delete_state(true); + if (thread_state.pinned === '1') set_pinned_state(true); - adminTools.style.visibility = 'inherit'; + if (expose_tools === '1') { + var moveThreadModal = $('#move_thread_modal'); - // Add events to the thread tools - $('#delete_thread').on('click', function(e) { - if (thread_state.deleted !== '1') { - bootbox.confirm('Are you sure you want to delete this thread?', function(confirm) { - if (confirm) socket.emit('api:topic.delete', { + adminTools.style.visibility = 'inherit'; + + // Add events to the thread tools + $('#delete_thread').on('click', function(e) { + if (thread_state.deleted !== '1') { + bootbox.confirm('Are you sure you want to delete this thread?', function(confirm) { + if (confirm) socket.emit('api:topic.delete', { + tid: tid + }); + }); + } else { + bootbox.confirm('Are you sure you want to restore this thread?', function(confirm) { + if (confirm) socket.emit('api:topic.restore', { + tid: tid + }); + }); + } + return false; + }); + + $('#lock_thread').on('click', function(e) { + if (thread_state.locked !== '1') { + socket.emit('api:topic.lock', { tid: tid }); - }); - } else { - bootbox.confirm('Are you sure you want to restore this thread?', function(confirm) { - if (confirm) socket.emit('api:topic.restore', { + } else { + socket.emit('api:topic.unlock', { tid: tid }); - }); - } - return false; - }); - - $('#lock_thread').on('click', function(e) { - if (thread_state.locked !== '1') { - socket.emit('api:topic.lock', { - tid: tid - }); - } else { - socket.emit('api:topic.unlock', { - tid: tid - }); - } - return false; - }); + } + return false; + }); - $('#pin_thread').on('click', function(e) { - if (thread_state.pinned !== '1') { - socket.emit('api:topic.pin', { - tid: tid - }); - } else { - socket.emit('api:topic.unpin', { - tid: tid - }); - } - return false; - }); + $('#pin_thread').on('click', function(e) { + if (thread_state.pinned !== '1') { + socket.emit('api:topic.pin', { + tid: tid + }); + } else { + socket.emit('api:topic.unpin', { + tid: tid + }); + } + return false; + }); - $('#move_thread').on('click', function(e) { - moveThreadModal.modal('show'); - return false; - }); + $('#move_thread').on('click', function(e) { + moveThreadModal.modal('show'); + return false; + }); - moveThreadModal.on('shown.bs.modal', function() { - - var loadingEl = document.getElementById('categories-loading'); - if (loadingEl) { - socket.once('api:categories.get', function(data) { - // Render categories - var categoriesFrag = document.createDocumentFragment(), - categoryEl = document.createElement('li'), - numCategories = data.categories.length, - modalBody = moveThreadModal.find('.modal-body'), - categoriesEl = modalBody[0].getElementsByTagName('ul')[0], - confirmDiv = document.getElementById('move-confirm'), - confirmCat = confirmDiv.getElementsByTagName('span')[0], - commitEl = document.getElementById('move_thread_commit'), - cancelEl = document.getElementById('move_thread_cancel'), - x, info, targetCid, targetCatLabel; - - categoriesEl.className = 'category-list'; - for (x = 0; x < numCategories; x++) { - info = data.categories[x]; - categoryEl.className = info.blockclass; - categoryEl.innerHTML = '<i class="' + info.icon + '"></i> ' + info.name; - categoryEl.setAttribute('data-cid', info.cid); - categoriesFrag.appendChild(categoryEl.cloneNode(true)); - } - categoriesEl.appendChild(categoriesFrag); - modalBody[0].removeChild(loadingEl); - - categoriesEl.addEventListener('click', function(e) { - if (e.target.nodeName === 'LI') { - confirmCat.innerHTML = e.target.innerHTML; - confirmDiv.style.display = 'block'; - targetCid = e.target.getAttribute('data-cid'); - targetCatLabel = e.target.innerHTML; - commitEl.disabled = false; - } - }, false); - - commitEl.addEventListener('click', function() { - if (!commitEl.disabled && targetCid) { - commitEl.disabled = true; - $(cancelEl).fadeOut(250); - $(moveThreadModal).find('.modal-header button').fadeOut(250); - commitEl.innerHTML = 'Moving <i class="icon-spin icon-refresh"></i>'; - - socket.once('api:topic.move', function(data) { - moveThreadModal.modal('hide'); - if (data.status === 'ok') { - app.alert({ - 'alert_id': 'thread_move', - type: 'success', - title: 'Topic Successfully Moved', - message: 'This topic has been successfully moved to ' + targetCatLabel, - timeout: 5000 - }); - } else { - app.alert({ - 'alert_id': 'thread_move', - type: 'danger', - title: 'Unable to Move Topic', - message: 'This topic could not be moved to ' + targetCatLabel + '.<br />Please try again later', - timeout: 5000 - }); - } - }); - socket.emit('api:topic.move', { - tid: tid, - cid: targetCid - }); + moveThreadModal.on('shown.bs.modal', function() { + + var loadingEl = document.getElementById('categories-loading'); + if (loadingEl) { + socket.once('api:categories.get', function(data) { + // Render categories + var categoriesFrag = document.createDocumentFragment(), + categoryEl = document.createElement('li'), + numCategories = data.categories.length, + modalBody = moveThreadModal.find('.modal-body'), + categoriesEl = modalBody[0].getElementsByTagName('ul')[0], + confirmDiv = document.getElementById('move-confirm'), + confirmCat = confirmDiv.getElementsByTagName('span')[0], + commitEl = document.getElementById('move_thread_commit'), + cancelEl = document.getElementById('move_thread_cancel'), + x, info, targetCid, targetCatLabel; + + categoriesEl.className = 'category-list'; + for (x = 0; x < numCategories; x++) { + info = data.categories[x]; + categoryEl.className = info.blockclass; + categoryEl.innerHTML = '<i class="' + info.icon + '"></i> ' + info.name; + categoryEl.setAttribute('data-cid', info.cid); + categoriesFrag.appendChild(categoryEl.cloneNode(true)); } + categoriesEl.appendChild(categoriesFrag); + modalBody[0].removeChild(loadingEl); + + categoriesEl.addEventListener('click', function(e) { + if (e.target.nodeName === 'LI') { + confirmCat.innerHTML = e.target.innerHTML; + confirmDiv.style.display = 'block'; + targetCid = e.target.getAttribute('data-cid'); + targetCatLabel = e.target.innerHTML; + commitEl.disabled = false; + } + }, false); + + commitEl.addEventListener('click', function() { + if (!commitEl.disabled && targetCid) { + commitEl.disabled = true; + $(cancelEl).fadeOut(250); + $(moveThreadModal).find('.modal-header button').fadeOut(250); + commitEl.innerHTML = 'Moving <i class="icon-spin icon-refresh"></i>'; + + socket.once('api:topic.move', function(data) { + moveThreadModal.modal('hide'); + if (data.status === 'ok') { + app.alert({ + 'alert_id': 'thread_move', + type: 'success', + title: 'Topic Successfully Moved', + message: 'This topic has been successfully moved to ' + targetCatLabel, + timeout: 5000 + }); + } else { + app.alert({ + 'alert_id': 'thread_move', + type: 'danger', + title: 'Unable to Move Topic', + message: 'This topic could not be moved to ' + targetCatLabel + '.<br />Please try again later', + timeout: 5000 + }); + } + }); + socket.emit('api:topic.move', { + tid: tid, + cid: targetCid + }); + } + }); }); + socket.emit('api:categories.get'); + } + }); + } + + // Fix delete state for this thread's posts + var postEls = document.querySelectorAll('#post-container li[data-deleted]'); + for (var x = 0, numPosts = postEls.length; x < numPosts; x++) { + if (postEls[x].getAttribute('data-deleted') === '1') toggle_post_delete_state(postEls[x].getAttribute('data-pid')); + postEls[x].removeAttribute('data-deleted'); + } + + // Follow Thread State + var followEl = $('.main-post .follow'), + set_follow_state = function(state, quiet) { + if (state && !followEl.hasClass('btn-success')) { + followEl.addClass('btn-success'); + followEl[0].title = 'You are currently receiving updates to this topic'; + if (!quiet) { + app.alert({ + alert_id: 'topic_follow', + timeout: 2500, + title: 'Following Topic', + message: 'You will now be receiving notifications when somebody posts to this topic.', + type: 'success' + }); + } + } else if (!state && followEl.hasClass('btn-success')) { + followEl.removeClass('btn-success'); + followEl[0].title = 'Be notified of new replies in this topic'; + if (!quiet) { + app.alert({ + alert_id: 'topic_follow', + timeout: 2500, + title: 'Not Following Topic', + message: 'You will no longer receive notifications from this topic.', + type: 'success' + }); + } + } + }; + socket.on('api:topic.followCheck', function(state) { + set_follow_state(state, true); + }); + socket.on('api:topic.follow', function(data) { + if (data.status && data.status === 'ok') set_follow_state(data.follow); + else { + app.alert({ + type: 'danger', + alert_id: 'topic_follow', + title: 'Please Log In', + message: 'Please register or log in in order to subscribe to this topic', + timeout: 5000 }); - socket.emit('api:categories.get'); } }); - } - // Fix delete state for this thread's posts - var postEls = document.querySelectorAll('#post-container li[data-deleted]'); - for (var x = 0, numPosts = postEls.length; x < numPosts; x++) { - if (postEls[x].getAttribute('data-deleted') === '1') toggle_post_delete_state(postEls[x].getAttribute('data-pid')); - postEls[x].removeAttribute('data-deleted'); - } + socket.emit('api:topic.followCheck', tid); + if (followEl[0]) { + followEl[0].addEventListener('click', function() { + socket.emit('api:topic.follow', tid); + }, false); + } - // Follow Thread State - var followEl = $('.main-post .follow'), - set_follow_state = function(state, quiet) { - if (state && !followEl.hasClass('btn-success')) { - followEl.addClass('btn-success'); - followEl[0].title = 'You are currently receiving updates to this topic'; - if (!quiet) { - app.alert({ - alert_id: 'topic_follow', - timeout: 2500, - title: 'Following Topic', - message: 'You will now be receiving notifications when somebody posts to this topic.', - type: 'success' - }); - } - } else if (!state && followEl.hasClass('btn-success')) { - followEl.removeClass('btn-success'); - followEl[0].title = 'Be notified of new replies in this topic'; - if (!quiet) { - app.alert({ - alert_id: 'topic_follow', - timeout: 2500, - title: 'Not Following Topic', - message: 'You will no longer receive notifications from this topic.', - type: 'success' - }); - } - } - }; - socket.on('api:topic.followCheck', function(state) { - set_follow_state(state, true); - }); - socket.on('api:topic.follow', function(data) { - if (data.status && data.status === 'ok') set_follow_state(data.follow); - else { - app.alert({ - type: 'danger', - alert_id: 'topic_follow', - title: 'Please Log In', - message: 'Please register or log in in order to subscribe to this topic', - timeout: 5000 - }); + enableInfiniteLoading(); + + var bookmark = localStorage.getItem('topic:' + tid + ':bookmark'); + + if(bookmark) { + app.scrollToPost(parseInt(bookmark, 10)); } + + $('#post-container').on('click', '.deleted', function(ev) { + $(this).toggleClass('deleted-expanded'); + }); }); - socket.emit('api:topic.followCheck', tid); - if (followEl[0]) { - followEl[0].addEventListener('click', function() { - socket.emit('api:topic.follow', tid); - }, false); + function enableInfiniteLoading() { + $(window).off('scroll').on('scroll', function() { + var bottom = ($(document).height() - $(window).height()) * 0.9; + + if ($(window).scrollTop() > bottom && !app.infiniteLoaderActive && $('#post-container').children().length) { + app.loadMorePosts(tid); + } + }); } - enableInfiniteLoading(); + var reply_fn = function() { + var selectionText = '', + selection = window.getSelection() || document.getSelection(); - var bookmark = localStorage.getItem('topic:' + tid + ':bookmark'); + if ($(selection.baseNode).parents('.post-content').length > 0) { + var snippet = selection.toString(); + if (snippet.length > 0) selectionText = '> ' + snippet.replace(/\n/g, '\n> '); + } - if(bookmark) { - app.scrollToPost(parseInt(bookmark, 10)); - } + if (thread_state.locked !== '1') { + require(['composer'], function(cmp) { + cmp.push(tid, null, null, selectionText.length > 0 ? selectionText + '\n\n' : ''); + }); + } + }; + $('#post-container').on('click', '.post_reply', reply_fn); + $('#post_reply').on('click', reply_fn); - $('#post-container').on('click', '.deleted', function(ev) { - $(this).toggleClass('deleted-expanded'); + $('#post-container').on('click', '.quote', function() { + if (thread_state.locked !== '1') { + var pid = $(this).parents('li').attr('data-pid'); + + socket.once('api:posts.getRawPost', function(data) { + + quoted = '> ' + data.post.replace(/\n/g, '\n> ') + '\n\n'; + require(['composer'], function(cmp) { + cmp.push(tid, null, null, quoted); + }); + }); + socket.emit('api:posts.getRawPost', { + pid: pid + }); + } }); - }); - function enableInfiniteLoading() { - $(window).off('scroll').on('scroll', function() { - var bottom = ($(document).height() - $(window).height()) * 0.9; + $('#post-container').on('click', '.favourite', function() { + var pid = $(this).parents('li').attr('data-pid'); + var uid = $(this).parents('li').attr('data-uid'); - if ($(window).scrollTop() > bottom && !app.infiniteLoaderActive && $('#post-container').children().length) { - app.loadMorePosts(tid); + var element = $(this).find('i'); + if (element.attr('class') == 'icon-star-empty') { + socket.emit('api:posts.favourite', { + pid: pid, + room_id: app.current_room + }); + } else { + socket.emit('api:posts.unfavourite', { + pid: pid, + room_id: app.current_room + }); } }); - } - var reply_fn = function() { - var selectionText = '', - selection = window.getSelection() || document.getSelection(); + $('#post-container').on('click', '.link', function() { + var pid = $(this).parents('li').attr('data-pid'); + $('#post_' + pid + '_link').val(window.location.href + "#" + pid).stop(true, false).fadeIn().select(); + $('#post_' + pid + '_link').off('blur').on('blur', function() { + $(this).fadeOut(); + }); + }); - if ($(selection.baseNode).parents('.post-content').length > 0) { - var snippet = selection.toString(); - if (snippet.length > 0) selectionText = '> ' + snippet.replace(/\n/g, '\n> '); - } + $('#post-container').delegate('.edit', 'click', function(e) { + var pid = $(this).parents('li').attr('data-pid'), + main = $(this).parents('.main-post'); - if (thread_state.locked !== '1') { require(['composer'], function(cmp) { - cmp.push(tid, null, null, selectionText.length > 0 ? selectionText + '\n\n' : ''); + cmp.push(null, null, pid); }); - } - }; - $('#post-container').on('click', '.post_reply', reply_fn); - $('#post_reply').on('click', reply_fn); + }); - $('#post-container').on('click', '.quote', function() { - if (thread_state.locked !== '1') { - var pid = $(this).parents('li').attr('data-pid'); + $('#post-container').delegate('.delete', 'click', function(e) { + var pid = $(this).parents('li').attr('data-pid'), + postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]')), + deleteAction = !postEl.hasClass('deleted') ? true : false, + confirmDel = confirm((deleteAction ? 'Delete' : 'Restore') + ' this post?'); + + if (confirmDel) { + deleteAction ? + socket.emit('api:posts.delete', { + pid: pid + }) : + socket.emit('api:posts.restore', { + pid: pid + }); + } + }); - socket.once('api:posts.getRawPost', function(data) { + $('#post-container').on('click', '.chat', function(e) { + var username = $(this).parents('li.row').attr('data-username'); + var touid = $(this).parents('li.row').attr('data-uid'); - quoted = '> ' + data.post.replace(/\n/g, '\n> ') + '\n\n'; - require(['composer'], function(cmp) { - cmp.push(tid, null, null, quoted); - }); - }); - socket.emit('api:posts.getRawPost', { - pid: pid - }); - } - }); + if (username === app.username || !app.username) + return; - $('#post-container').on('click', '.favourite', function() { - var pid = $(this).parents('li').attr('data-pid'); - var uid = $(this).parents('li').attr('data-uid'); + app.openChat(username, touid); + }); - var element = $(this).find('i'); - if (element.attr('class') == 'icon-star-empty') { - socket.emit('api:posts.favourite', { - pid: pid, - room_id: app.current_room - }); - } else { - socket.emit('api:posts.unfavourite', { - pid: pid, - room_id: app.current_room - }); - } - }); + ajaxify.register_events([ + 'event:rep_up', 'event:rep_down', 'event:new_post', 'api:get_users_in_room', + 'event:topic_deleted', 'event:topic_restored', 'event:topic:locked', + 'event:topic_unlocked', 'event:topic_pinned', 'event:topic_unpinned', + 'event:topic_moved', 'event:post_edited', 'event:post_deleted', 'event:post_restored', + 'api:posts.favourite' + ]); - $('#post-container').on('click', '.link', function() { - var pid = $(this).parents('li').attr('data-pid'); - $('#post_' + pid + '_link').val(window.location.href + "#" + pid).stop(true, false).fadeIn().select(); - $('#post_' + pid + '_link').off('blur').on('blur', function() { - $(this).fadeOut(); + + socket.on('api:get_users_in_room', function(data) { + var activeEl = $('#thread_active_users'); + if (activeEl.length) + activeEl.html(data); + + app.populate_online_users(); }); - }); - $('#post-container').delegate('.edit', 'click', function(e) { - var pid = $(this).parents('li').attr('data-pid'), - main = $(this).parents('.main-post'); + socket.on('event:rep_up', function(data) { + adjust_rep(1, data.pid, data.uid); + }); - require(['composer'], function(cmp) { - cmp.push(null, null, pid); + socket.on('event:rep_down', function(data) { + adjust_rep(-1, data.pid, data.uid); }); - }); - $('#post-container').delegate('.delete', 'click', function(e) { - var pid = $(this).parents('li').attr('data-pid'), - postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]')), - deleteAction = !postEl.hasClass('deleted') ? true : false, - confirmDel = confirm((deleteAction ? 'Delete' : 'Restore') + ' this post?'); + socket.on('event:new_post', app.createNewPosts); - if (confirmDel) { - deleteAction ? - socket.emit('api:posts.delete', { - pid: pid - }) : - socket.emit('api:posts.restore', { - pid: pid - }); - } - }); + socket.on('event:topic_deleted', function(data) { + if (data.tid === tid && data.status === 'ok') { + set_locked_state(true); + set_delete_state(true); + } + }); - $('#post-container').on('click', '.chat', function(e) { - var username = $(this).parents('li.row').attr('data-username'); - var touid = $(this).parents('li.row').attr('data-uid'); + socket.on('event:topic_restored', function(data) { + if (data.tid === tid && data.status === 'ok') { + set_locked_state(false); + set_delete_state(false); + } + }); - if (username === app.username || !app.username) - return; + socket.on('event:topic_locked', function(data) { + if (data.tid === tid && data.status === 'ok') { + set_locked_state(true, 1); + } + }); - app.openChat(username, touid); - }); + socket.on('event:topic_unlocked', function(data) { + if (data.tid === tid && data.status === 'ok') { + set_locked_state(false, 1); + } + }); - ajaxify.register_events([ - 'event:rep_up', 'event:rep_down', 'event:new_post', 'api:get_users_in_room', - 'event:topic_deleted', 'event:topic_restored', 'event:topic:locked', - 'event:topic_unlocked', 'event:topic_pinned', 'event:topic_unpinned', - 'event:topic_moved', 'event:post_edited', 'event:post_deleted', 'event:post_restored', - 'api:posts.favourite' - ]); + socket.on('event:topic_pinned', function(data) { + if (data.tid === tid && data.status === 'ok') { + set_pinned_state(true, 1); + } + }); + socket.on('event:topic_unpinned', function(data) { + if (data.tid === tid && data.status === 'ok') { + set_pinned_state(false, 1); + } + }); - socket.on('api:get_users_in_room', function(data) { - var activeEl = $('#thread_active_users'); - if (activeEl.length) - activeEl.html(data); + socket.on('event:topic_moved', function(data) { + if (data && data.tid > 0) ajaxify.go('topic/' + data.tid); + }); - app.populate_online_users(); - }); + socket.on('event:post_edited', function(data) { + var editedPostEl = document.getElementById('content_' + data.pid); - socket.on('event:rep_up', function(data) { - adjust_rep(1, data.pid, data.uid); - }); + var editedPostTitle = $('#topic_title_' + data.pid); - socket.on('event:rep_down', function(data) { - adjust_rep(-1, data.pid, data.uid); - }); + if (editedPostTitle.length > 0) { + editedPostTitle.fadeOut(250, function() { + editedPostTitle.html(data.title); + editedPostTitle.fadeIn(250); + }); + } - socket.on('event:new_post', app.createNewPosts); + $(editedPostEl).fadeOut(250, function() { + this.innerHTML = data.content; + $(this).fadeIn(250); + }); - socket.on('event:topic_deleted', function(data) { - if (data.tid === tid && data.status === 'ok') { - set_locked_state(true); - set_delete_state(true); - } - }); + }); - socket.on('event:topic_restored', function(data) { - if (data.tid === tid && data.status === 'ok') { - set_locked_state(false); - set_delete_state(false); - } - }); + socket.on('api:posts.favourite', function(data) { + if (data.status === 'ok' && data.pid) { + var favEl = document.querySelector('.post_rep_' + data.pid).nextSibling; + if (favEl) { + favEl.className = 'icon-star'; + $(favEl).parent().addClass('btn-warning'); + } + } + }); - socket.on('event:topic_locked', function(data) { - if (data.tid === tid && data.status === 'ok') { - set_locked_state(true, 1); - } - }); + socket.on('api:posts.unfavourite', function(data) { + if (data.status === 'ok' && data.pid) { + var favEl = document.querySelector('.post_rep_' + data.pid).nextSibling; + if (favEl) { + favEl.className = 'icon-star-empty'; + $(favEl).parent().removeClass('btn-warning'); + } + } + }); - socket.on('event:topic_unlocked', function(data) { - if (data.tid === tid && data.status === 'ok') { - set_locked_state(false, 1); - } - }); + socket.on('event:post_deleted', function(data) { + if (data.pid) toggle_post_delete_state(data.pid, true); + }); - socket.on('event:topic_pinned', function(data) { - if (data.tid === tid && data.status === 'ok') { - set_pinned_state(true, 1); - } - }); + socket.on('event:post_restored', function(data) { + if (data.pid) toggle_post_delete_state(data.pid, true); + }); - socket.on('event:topic_unpinned', function(data) { - if (data.tid === tid && data.status === 'ok') { - set_pinned_state(false, 1); - } - }); + socket.on('api:post.privileges', function(privileges) { + if (privileges.editable) toggle_mod_tools(privileges.pid, true); + }); - socket.on('event:topic_moved', function(data) { - if (data && data.tid > 0) ajaxify.go('topic/' + data.tid); - }); + function adjust_rep(value, pid, uid) { + var post_rep = jQuery('.post_rep_' + pid), + user_rep = jQuery('.user_rep_' + uid); - socket.on('event:post_edited', function(data) { - var editedPostEl = document.getElementById('content_' + data.pid); + var ptotal = parseInt(post_rep.html(), 10), + utotal = parseInt(user_rep.html(), 10); - var editedPostTitle = $('#topic_title_' + data.pid); + ptotal += value; + utotal += value; - if (editedPostTitle.length > 0) { - editedPostTitle.fadeOut(250, function() { - editedPostTitle.html(data.title); - editedPostTitle.fadeIn(250); - }); + post_rep.html(ptotal + ' '); + user_rep.html(utotal + ' '); } - $(editedPostEl).fadeOut(250, function() { - this.innerHTML = data.content; - $(this).fadeIn(250); - }); + function set_locked_state(locked, alert) { + var threadReplyBtn = document.getElementById('post_reply'), + postReplyBtns = document.querySelectorAll('#post-container .post_reply'), + quoteBtns = document.querySelectorAll('#post-container .quote'), + editBtns = document.querySelectorAll('#post-container .edit'), + deleteBtns = document.querySelectorAll('#post-container .delete'), + numPosts = document.querySelectorAll('#post_container li[data-pid]').length, + lockThreadEl = document.getElementById('lock_thread'), + x; + + if (locked === true) { + lockThreadEl.innerHTML = '<i class="icon-unlock"></i> Unlock Thread'; + threadReplyBtn.disabled = true; + threadReplyBtn.innerHTML = 'Locked <i class="icon-lock"></i>'; + for (x = 0; x < numPosts; x++) { + postReplyBtns[x].innerHTML = 'Locked <i class="icon-lock"></i>'; + quoteBtns[x].style.display = 'none'; + editBtns[x].style.display = 'none'; + deleteBtns[x].style.display = 'none'; + } - }); + if (alert) { + app.alert({ + 'alert_id': 'thread_lock', + type: 'success', + title: 'Thread Locked', + message: 'Thread has been successfully locked', + timeout: 5000 + }); + } + + thread_state.locked = '1'; + } else { + lockThreadEl.innerHTML = '<i class="icon-lock"></i> Lock Thread'; + threadReplyBtn.disabled = false; + threadReplyBtn.innerHTML = 'Reply'; + for (x = 0; x < numPosts; x++) { + postReplyBtns[x].innerHTML = 'Reply <i class="icon-reply"></i>'; + quoteBtns[x].style.display = 'inline-block'; + editBtns[x].style.display = 'inline-block'; + deleteBtns[x].style.display = 'inline-block'; + } + + if (alert) { + app.alert({ + 'alert_id': 'thread_lock', + type: 'success', + title: 'Thread Unlocked', + message: 'Thread has been successfully unlocked', + timeout: 5000 + }); + } - socket.on('api:posts.favourite', function(data) { - if (data.status === 'ok' && data.pid) { - var favEl = document.querySelector('.post_rep_' + data.pid).nextSibling; - if (favEl) { - favEl.className = 'icon-star'; - $(favEl).parent().addClass('btn-warning'); + thread_state.locked = '0'; } } - }); - - socket.on('api:posts.unfavourite', function(data) { - if (data.status === 'ok' && data.pid) { - var favEl = document.querySelector('.post_rep_' + data.pid).nextSibling; - if (favEl) { - favEl.className = 'icon-star-empty'; - $(favEl).parent().removeClass('btn-warning'); + + function set_delete_state(deleted) { + var deleteThreadEl = document.getElementById('delete_thread'), + deleteTextEl = deleteThreadEl.getElementsByTagName('span')[0], + threadEl = $('#post-container'), + deleteNotice = document.getElementById('thread-deleted') || document.createElement('div'); + + if (deleted) { + deleteTextEl.innerHTML = '<i class="icon-comment"></i> Restore Thread'; + threadEl.addClass('deleted'); + + // Spawn a 'deleted' notice at the top of the page + deleteNotice.setAttribute('id', 'thread-deleted'); + deleteNotice.className = 'alert alert-warning'; + deleteNotice.innerHTML = 'This thread has been deleted. Only users with thread management privileges can see it.'; + threadEl.before(deleteNotice); + + thread_state.deleted = '1'; + } else { + deleteTextEl.innerHTML = '<i class="icon-trash"></i> Delete Thread'; + threadEl.removeClass('deleted'); + deleteNotice.parentNode.removeChild(deleteNotice); + + thread_state.deleted = '0'; } } - }); - - socket.on('event:post_deleted', function(data) { - if (data.pid) toggle_post_delete_state(data.pid, true); - }); - - socket.on('event:post_restored', function(data) { - if (data.pid) toggle_post_delete_state(data.pid, true); - }); - - socket.on('api:post.privileges', function(privileges) { - if (privileges.editable) toggle_mod_tools(privileges.pid, true); - }); - - function adjust_rep(value, pid, uid) { - var post_rep = jQuery('.post_rep_' + pid), - user_rep = jQuery('.user_rep_' + uid); - - var ptotal = parseInt(post_rep.html(), 10), - utotal = parseInt(user_rep.html(), 10); - - ptotal += value; - utotal += value; - - post_rep.html(ptotal + ' '); - user_rep.html(utotal + ' '); - } - - function set_locked_state(locked, alert) { - var threadReplyBtn = document.getElementById('post_reply'), - postReplyBtns = document.querySelectorAll('#post-container .post_reply'), - quoteBtns = document.querySelectorAll('#post-container .quote'), - editBtns = document.querySelectorAll('#post-container .edit'), - deleteBtns = document.querySelectorAll('#post-container .delete'), - numPosts = document.querySelectorAll('#post_container li[data-pid]').length, - lockThreadEl = document.getElementById('lock_thread'), - x; - - if (locked === true) { - lockThreadEl.innerHTML = '<i class="icon-unlock"></i> Unlock Thread'; - threadReplyBtn.disabled = true; - threadReplyBtn.innerHTML = 'Locked <i class="icon-lock"></i>'; - for (x = 0; x < numPosts; x++) { - postReplyBtns[x].innerHTML = 'Locked <i class="icon-lock"></i>'; - quoteBtns[x].style.display = 'none'; - editBtns[x].style.display = 'none'; - deleteBtns[x].style.display = 'none'; - } - if (alert) { - app.alert({ - 'alert_id': 'thread_lock', - type: 'success', - title: 'Thread Locked', - message: 'Thread has been successfully locked', - timeout: 5000 - }); - } + function set_pinned_state(pinned, alert) { + var pinEl = document.getElementById('pin_thread'); + + if (pinned) { + pinEl.innerHTML = '<i class="icon-pushpin"></i> Unpin Thread'; + if (alert) { + app.alert({ + 'alert_id': 'thread_pin', + type: 'success', + title: 'Thread Pinned', + message: 'Thread has been successfully pinned', + timeout: 5000 + }); + } - thread_state.locked = '1'; - } else { - lockThreadEl.innerHTML = '<i class="icon-lock"></i> Lock Thread'; - threadReplyBtn.disabled = false; - threadReplyBtn.innerHTML = 'Reply'; - for (x = 0; x < numPosts; x++) { - postReplyBtns[x].innerHTML = 'Reply <i class="icon-reply"></i>'; - quoteBtns[x].style.display = 'inline-block'; - editBtns[x].style.display = 'inline-block'; - deleteBtns[x].style.display = 'inline-block'; - } + thread_state.pinned = '1'; + } else { + pinEl.innerHTML = '<i class="icon-pushpin"></i> Pin Thread'; + if (alert) { + app.alert({ + 'alert_id': 'thread_pin', + type: 'success', + title: 'Thread Unpinned', + message: 'Thread has been successfully unpinned', + timeout: 5000 + }); + } - if (alert) { - app.alert({ - 'alert_id': 'thread_lock', - type: 'success', - title: 'Thread Unlocked', - message: 'Thread has been successfully unlocked', - timeout: 5000 - }); + thread_state.pinned = '0'; } - - thread_state.locked = '0'; } - } - - function set_delete_state(deleted) { - var deleteThreadEl = document.getElementById('delete_thread'), - deleteTextEl = deleteThreadEl.getElementsByTagName('span')[0], - threadEl = $('#post-container'), - deleteNotice = document.getElementById('thread-deleted') || document.createElement('div'); - - if (deleted) { - deleteTextEl.innerHTML = '<i class="icon-comment"></i> Restore Thread'; - threadEl.addClass('deleted'); - - // Spawn a 'deleted' notice at the top of the page - deleteNotice.setAttribute('id', 'thread-deleted'); - deleteNotice.className = 'alert alert-warning'; - deleteNotice.innerHTML = 'This thread has been deleted. Only users with thread management privileges can see it.'; - threadEl.before(deleteNotice); - - thread_state.deleted = '1'; - } else { - deleteTextEl.innerHTML = '<i class="icon-trash"></i> Delete Thread'; - threadEl.removeClass('deleted'); - deleteNotice.parentNode.removeChild(deleteNotice); - - thread_state.deleted = '0'; - } - } - - function set_pinned_state(pinned, alert) { - var pinEl = document.getElementById('pin_thread'); - - if (pinned) { - pinEl.innerHTML = '<i class="icon-pushpin"></i> Unpin Thread'; - if (alert) { - app.alert({ - 'alert_id': 'thread_pin', - type: 'success', - title: 'Thread Pinned', - message: 'Thread has been successfully pinned', - timeout: 5000 - }); - } - - thread_state.pinned = '1'; - } else { - pinEl.innerHTML = '<i class="icon-pushpin"></i> Pin Thread'; - if (alert) { - app.alert({ - 'alert_id': 'thread_pin', - type: 'success', - title: 'Thread Unpinned', - message: 'Thread has been successfully unpinned', - timeout: 5000 - }); - } - thread_state.pinned = '0'; - } - } + function toggle_post_delete_state(pid) { + var postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]')); - function toggle_post_delete_state(pid) { - var postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]')); + if (postEl[0]) { + quoteEl = $(postEl[0].querySelector('.quote')), + favEl = $(postEl[0].querySelector('.favourite')), + replyEl = $(postEl[0].querySelector('.post_reply')); - if (postEl[0]) { - quoteEl = $(postEl[0].querySelector('.quote')), - favEl = $(postEl[0].querySelector('.favourite')), - replyEl = $(postEl[0].querySelector('.post_reply')); + socket.once('api:post.privileges', function(privileges) { + if (privileges.editable) { + if (!postEl.hasClass('deleted')) { + toggle_post_tools(pid, false); + } else { + toggle_post_tools(pid, true); + } + } - socket.once('api:post.privileges', function(privileges) { - if (privileges.editable) { - if (!postEl.hasClass('deleted')) { - toggle_post_tools(pid, false); + if (privileges.view_deleted) { + postEl.toggleClass('deleted'); } else { - toggle_post_tools(pid, true); + postEl.toggleClass('none'); } - } - - if (privileges.view_deleted) { - postEl.toggleClass('deleted'); - } else { - postEl.toggleClass('none'); - } - }); - socket.emit('api:post.privileges', pid); + }); + socket.emit('api:post.privileges', pid); + } } - } - - function toggle_post_tools(pid, state) { - var postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]')), - quoteEl = $(postEl[0].querySelector('.quote')), - favEl = $(postEl[0].querySelector('.favourite')), - replyEl = $(postEl[0].querySelector('.post_reply')); - - if (state) { - quoteEl.removeClass('none'); - favEl.removeClass('none'); - replyEl.removeClass('none'); - } else { - quoteEl.addClass('none'); - favEl.addClass('none'); - replyEl.addClass('none'); + + function toggle_post_tools(pid, state) { + var postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]')), + quoteEl = $(postEl[0].querySelector('.quote')), + favEl = $(postEl[0].querySelector('.favourite')), + replyEl = $(postEl[0].querySelector('.post_reply')); + + if (state) { + quoteEl.removeClass('none'); + favEl.removeClass('none'); + replyEl.removeClass('none'); + } else { + quoteEl.addClass('none'); + favEl.addClass('none'); + replyEl.addClass('none'); + } } - } - - function toggle_mod_tools(pid, state) { - var postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]')), - editEl = postEl.find('.edit'), - deleteEl = postEl.find('.delete'); - - if (state) { - editEl.removeClass('none'); - deleteEl.removeClass('none'); - } else { - editEl.addClass('none'); - deleteEl.addClass('none'); + + function toggle_mod_tools(pid, state) { + var postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]')), + editEl = postEl.find('.edit'), + deleteEl = postEl.find('.delete'); + + if (state) { + editEl.removeClass('none'); + deleteEl.removeClass('none'); + } else { + editEl.addClass('none'); + deleteEl.addClass('none'); + } } - } - var postAuthorImage, mobileAuthorOverlay, pagination; - var postcount = templates.get('postcount'); + var postAuthorImage, mobileAuthorOverlay, pagination; + var postcount = templates.get('postcount'); - function updateHeader() { - if (pagination == null) { - jQuery('.pagination-block i:first').on('click', function() { - app.scrollToTop(); - }); - jQuery('.pagination-block i:last').on('click', function() { - app.scrollToBottom(); - }); - } + function updateHeader() { + if (pagination == null) { + jQuery('.pagination-block i:first').on('click', function() { + app.scrollToTop(); + }); + jQuery('.pagination-block i:last').on('click', function() { + app.scrollToBottom(); + }); + } - jQuery('.mobile-author-overlay').css('bottom', '0px'); - postAuthorImage = postAuthorImage || document.getElementById('mobile-author-image'); - mobileAuthorOverlay = mobileAuthorOverlay || document.getElementById('mobile-author-overlay'); - pagination = pagination || document.getElementById('pagination'); + jQuery('.mobile-author-overlay').css('bottom', '0px'); + postAuthorImage = postAuthorImage || document.getElementById('mobile-author-image'); + mobileAuthorOverlay = mobileAuthorOverlay || document.getElementById('mobile-author-overlay'); + pagination = pagination || document.getElementById('pagination'); - pagination.parentNode.style.display = 'block'; + pagination.parentNode.style.display = 'block'; - var windowHeight = jQuery(window).height(); - var scrollTop = jQuery(window).scrollTop(); - var scrollBottom = scrollTop + windowHeight; + var windowHeight = jQuery(window).height(); + var scrollTop = jQuery(window).scrollTop(); + var scrollBottom = scrollTop + windowHeight; - if (scrollTop < 50 && postcount > 1) { - localStorage.removeItem("topic:" + tid + ":bookmark"); - postAuthorImage.src = (jQuery('.main-post .avatar img').attr('src')); - mobileAuthorOverlay.innerHTML = 'Posted by ' + jQuery('.main-post').attr('data-username') + ', ' + jQuery('.main-post').find('.relativeTimeAgo').html(); - pagination.innerHTML = '0 out of ' + postcount; - return; - } + if (scrollTop < 50 && postcount > 1) { + localStorage.removeItem("topic:" + tid + ":bookmark"); + postAuthorImage.src = (jQuery('.main-post .avatar img').attr('src')); + mobileAuthorOverlay.innerHTML = 'Posted by ' + jQuery('.main-post').attr('data-username') + ', ' + jQuery('.main-post').find('.relativeTimeAgo').html(); + pagination.innerHTML = '0 out of ' + postcount; + return; + } - var count = 0, smallestNonNegative = 0; + var count = 0, smallestNonNegative = 0; - jQuery('.sub-posts').each(function() { - count++; - this.postnumber = count; + jQuery('.sub-posts').each(function() { + count++; + this.postnumber = count; - var el = jQuery(this); - var elTop = el.offset().top; - var height = Math.floor(el.height()); - var elBottom = elTop + (height < 300 ? height : 300); + var el = jQuery(this); + var elTop = el.offset().top; + var height = Math.floor(el.height()); + var elBottom = elTop + (height < 300 ? height : 300); - var inView = ((elBottom >= scrollTop) && (elTop <= scrollBottom) && (elBottom <= scrollBottom) && (elTop >= scrollTop)); + var inView = ((elBottom >= scrollTop) && (elTop <= scrollBottom) && (elBottom <= scrollBottom) && (elTop >= scrollTop)); - if (inView) { - if(elTop - scrollTop > smallestNonNegative) { - localStorage.setItem("topic:" + tid + ":bookmark", el.attr('data-pid')); - smallestNonNegative = Number.MAX_VALUE; + if (inView) { + if(elTop - scrollTop > smallestNonNegative) { + localStorage.setItem("topic:" + tid + ":bookmark", el.attr('data-pid')); + smallestNonNegative = Number.MAX_VALUE; + } + + pagination.innerHTML = this.postnumber + ' out of ' + postcount; + postAuthorImage.src = (jQuery(this).find('.profile-image-block img').attr('src')); + mobileAuthorOverlay.innerHTML = 'Posted by ' + jQuery(this).attr('data-username') + ', ' + jQuery(this).find('.relativeTimeAgo').html(); } + }); - pagination.innerHTML = this.postnumber + ' out of ' + postcount; - postAuthorImage.src = (jQuery(this).find('.profile-image-block img').attr('src')); - mobileAuthorOverlay.innerHTML = 'Posted by ' + jQuery(this).attr('data-username') + ', ' + jQuery(this).find('.relativeTimeAgo').html(); - } - }); + setTimeout(function() { + if (scrollTop + windowHeight == jQuery(document).height()) { + pagination.innerHTML = postcount + ' out of ' + postcount; + } + }, 100); + } - setTimeout(function() { - if (scrollTop + windowHeight == jQuery(document).height()) { - pagination.innerHTML = postcount + ' out of ' + postcount; - } - }, 100); - } + window.onscroll = updateHeader; + window.onload = updateHeader; + }; - window.onscroll = updateHeader; - window.onload = updateHeader; -})(); + return Topic; +}); \ No newline at end of file diff --git a/public/src/forum/unread.js b/public/src/forum/unread.js index b4b78b67a1..329cfff3ff 100644 --- a/public/src/forum/unread.js +++ b/public/src/forum/unread.js @@ -1,114 +1,119 @@ -(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!'); - $('#numUnreadBadge') - .removeClass('badge-important') - .addClass('badge-inverse') - .html('0'); - } else { - app.alertError('There was an error marking topics read!'); - } +define(function() { + var Unread = {}; + + Unread.init = 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(); }); - }); - - 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); - } else { - $('#load-more-btn').hide(); - } - loadingMoreTopics = false; + socket.on('event:new_topic', function(data) { + + ++newTopicCount; + updateAlertText(); + }); - } - $(window).off('scroll').on('scroll', function() { - var bottom = ($(document).height() - $(window).height()) * 0.9; + function updateAlertText() { + var text = ''; - if ($(window).scrollTop() > bottom && !loadingMoreTopics) { - loadMoreTopics(); + 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!'); + $('#numUnreadBadge') + .removeClass('badge-important') + .addClass('badge-inverse') + .html('0'); + } 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); + } else { + $('#load-more-btn').hide(); + } + + loadingMoreTopics = false; + }); + } - if ($("body").height() <= $(window).height() && $('#topics-container').children().length >= 20) - $('#load-more-btn').show(); + $(window).off('scroll').on('scroll', function() { + var bottom = ($(document).height() - $(window).height()) * 0.9; - $('#load-more-btn').on('click', function() { - loadMoreTopics(); - }); + if ($(window).scrollTop() > bottom && !loadingMoreTopics) { + loadMoreTopics(); + } + }); + + + if ($("body").height() <= $(window).height() && $('#topics-container').children().length >= 20) + $('#load-more-btn').show(); + + $('#load-more-btn').on('click', function() { + loadMoreTopics(); + }); + }; -})(); \ No newline at end of file + return Unread; +}); \ No newline at end of file diff --git a/public/src/forum/users.js b/public/src/forum/users.js index a5d29adaa7..c845a7c4cb 100644 --- a/public/src/forum/users.js +++ b/public/src/forum/users.js @@ -1,6 +1,7 @@ -(function() { +define(function() { + var Users = {}; - $(document).ready(function() { + Users.init = function() { var timeoutId = 0; var loadingMoreUsers = false; @@ -131,6 +132,7 @@ loadMoreUsers(); } }); - }); + }; -}()); \ No newline at end of file + return Users; +}); \ No newline at end of file diff --git a/public/templates/account.tpl b/public/templates/account.tpl index 929771940b..5c7678f10c 100644 --- a/public/templates/account.tpl +++ b/public/templates/account.tpl @@ -97,7 +97,4 @@ <input type="hidden" template-variable="yourid" value="{yourid}" /> <input type="hidden" template-variable="theirid" value="{theirid}" /> -<input type="hidden" template-type="boolean" template-variable="isFollowing" value="{isFollowing}" /> - -<script type="text/javascript" src="{relative_path}/src/forum/account.js"></script> -<script type="text/javascript" src="{relative_path}/src/forum/accountheader.js"></script> \ No newline at end of file +<input type="hidden" template-type="boolean" template-variable="isFollowing" value="{isFollowing}" /> \ No newline at end of file diff --git a/public/templates/accountedit.tpl b/public/templates/accountedit.tpl index 36c0238e48..1e53ab8920 100644 --- a/public/templates/accountedit.tpl +++ b/public/templates/accountedit.tpl @@ -174,9 +174,3 @@ </div> </div> - -<input type="hidden" template-variable="gravatarpicture" value="{gravatarpicture}" /> -<input type="hidden" template-variable="uploadedpicture" value="{uploadedpicture}" /> - -<script type="text/javascript" src="{relative_path}/src/forum/accountheader.js"></script> -<script type="text/javascript" src="{relative_path}/src/forum/accountedit.js"></script> diff --git a/public/templates/accountsettings.tpl b/public/templates/accountsettings.tpl index cb200cb79e..f5ae423ac6 100644 --- a/public/templates/accountsettings.tpl +++ b/public/templates/accountsettings.tpl @@ -26,6 +26,3 @@ <a id="submitBtn" href="#" class="btn btn-primary">Save changes</a> </div> </div> - -<script type="text/javascript" src="{relative_path}/src/forum/accountheader.js"></script> -<script type="text/javascript" src="{relative_path}/src/forum/accountsettings.js"></script> \ No newline at end of file diff --git a/public/templates/admin/categories.tpl b/public/templates/admin/categories.tpl index ea6f02589e..b636606750 100644 --- a/public/templates/admin/categories.tpl +++ b/public/templates/admin/categories.tpl @@ -101,5 +101,3 @@ <div class="col-md-3"><i class="icon-adn"></i></div><div class="col-md-3"><i class="icon-android"></i></div><div class="col-md-3"><i class="icon-apple"></i></div><div class="col-md-3"><i class="icon-bitbucket"></i></div><div class="col-md-3"><i class="icon-bitbucket-sign"></i></div><div class="col-md-3"><i class="icon-bitcoin"></i></div><div class="col-md-3"><i class="icon-btc"></i></div><div class="col-md-3"><i class="icon-css3"></i></div><div class="col-md-3"><i class="icon-dribbble"></i></div><div class="col-md-3"><i class="icon-dropbox"></i></div><div class="col-md-3"><i class="icon-facebook"></i></div><div class="col-md-3"><i class="icon-facebook-sign"></i></div><div class="col-md-3"><i class="icon-flickr"></i></div><div class="col-md-3"><i class="icon-foursquare"></i></div><div class="col-md-3"><i class="icon-github"></i></div><div class="col-md-3"><i class="icon-github-alt"></i></div><div class="col-md-3"><i class="icon-github-sign"></i></div><div class="col-md-3"><i class="icon-gittip"></i></div><div class="col-md-3"><i class="icon-google-plus"></i></div><div class="col-md-3"><i class="icon-google-plus-sign"></i></div><div class="col-md-3"><i class="icon-html5"></i></div><div class="col-md-3"><i class="icon-instagram"></i></div><div class="col-md-3"><i class="icon-linkedin"></i></div><div class="col-md-3"><i class="icon-linkedin-sign"></i></div><div class="col-md-3"><i class="icon-linux"></i></div><div class="col-md-3"><i class="icon-maxcdn"></i></div><div class="col-md-3"><i class="icon-pinterest"></i></div><div class="col-md-3"><i class="icon-pinterest-sign"></i></div><div class="col-md-3"><i class="icon-renren"></i></div><div class="col-md-3"><i class="icon-skype"></i></div><div class="col-md-3"><i class="icon-stackexchange"></i></div><div class="col-md-3"><i class="icon-trello"></i></div><div class="col-md-3"><i class="icon-tumblr"></i></div><div class="col-md-3"><i class="icon-tumblr-sign"></i></div><div class="col-md-3"><i class="icon-twitter"></i></div><div class="col-md-3"><i class="icon-twitter-sign"></i></div><div class="col-md-3"><i class="icon-vk"></i></div><div class="col-md-3"><i class="icon-weibo"></i></div><div class="col-md-3"><i class="icon-windows"></i></div><div class="col-md-3"><i class="icon-xing"></i></div><div class="col-md-3"><i class="icon-xing-sign"></i></div><div class="col-md-3"><i class="icon-youtube"></i></div><div class="col-md-3"><i class="icon-youtube-play"></i></div><div class="col-md-3"><i class="icon-youtube-sign"></i></div> <div class="col-md-3"><i class="icon-ambulance"></i></div><div class="col-md-3"><i class="icon-h-sign"></i></div><div class="col-md-3"><i class="icon-hospital"></i></div><div class="col-md-3"><i class="icon-medkit"></i></div><div class="col-md-3"><i class="icon-plus-sign-alt"></i></div><div class="col-md-3"><i class="icon-stethoscope"></i></div><div class="col-md-3"><i class="icon-user-md"></i></div> </div></div></div> - -<script type="text/javascript" src="{relative_path}/src/forum/admin/categories.js"></script> \ No newline at end of file diff --git a/public/templates/admin/facebook.tpl b/public/templates/admin/facebook.tpl index 92118c573e..14c6202cda 100644 --- a/public/templates/admin/facebook.tpl +++ b/public/templates/admin/facebook.tpl @@ -17,10 +17,7 @@ <button class="btn btn-lg btn-primary" id="save">Save</button> <script> - var loadDelay = setInterval(function() { - if (nodebb_admin) { - nodebb_admin.prepare(); - clearInterval(loadDelay); - } - }, 500); + require(['forum/admin/settings'], function(Settings) { + Settings.prepare(); + }); </script> \ No newline at end of file diff --git a/public/templates/admin/footer.tpl b/public/templates/admin/footer.tpl index f5392a6499..fb69cce64e 100644 --- a/public/templates/admin/footer.tpl +++ b/public/templates/admin/footer.tpl @@ -9,7 +9,7 @@ </div> <script type="text/javascript"> - $.getScript(RELATIVE_PATH + '/src/forum/admin/footer.js'); + require(['forum/admin/footer']); </script> </body> diff --git a/public/templates/admin/gplus.tpl b/public/templates/admin/gplus.tpl index c1a691b99f..81cf11852c 100644 --- a/public/templates/admin/gplus.tpl +++ b/public/templates/admin/gplus.tpl @@ -17,10 +17,7 @@ <button class="btn btn-lg btn-primary" id="save">Save</button> <script> - var loadDelay = setInterval(function() { - if (nodebb_admin) { - nodebb_admin.prepare(); - clearInterval(loadDelay); - } - }, 500); + require(['forum/admin/settings'], function(Settings) { + Settings.prepare(); + }); </script> \ No newline at end of file diff --git a/public/templates/admin/groups.tpl b/public/templates/admin/groups.tpl index 2637bfedc2..5b53c2c65f 100644 --- a/public/templates/admin/groups.tpl +++ b/public/templates/admin/groups.tpl @@ -96,5 +96,3 @@ </div> </div> </div> - -<script type="text/javascript" src="{relative_path}/src/forum/admin/groups.js"></script> \ No newline at end of file diff --git a/public/templates/admin/header.tpl b/public/templates/admin/header.tpl index 72469a018a..aefd3dc6b6 100644 --- a/public/templates/admin/header.tpl +++ b/public/templates/admin/header.tpl @@ -25,7 +25,10 @@ <script> require.config({ baseUrl: "{relative_path}/src/modules", - waitSeconds: 3 + waitSeconds: 3, + paths: { + "forum": '../forum' + } }); </script> <link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css"> diff --git a/public/templates/admin/index.tpl b/public/templates/admin/index.tpl index a3b5987831..bd921f59a6 100644 --- a/public/templates/admin/index.tpl +++ b/public/templates/admin/index.tpl @@ -18,5 +18,3 @@ </p> </div> - -<script type="text/javascript" src="{relative_path}/src/forum/admin/index.js"></script> \ No newline at end of file diff --git a/public/templates/admin/motd.tpl b/public/templates/admin/motd.tpl index 17f6bce16e..6c1725099f 100644 --- a/public/templates/admin/motd.tpl +++ b/public/templates/admin/motd.tpl @@ -24,10 +24,7 @@ <button class="btn btn-lg btn-primary" id="save" checked>Save</button> <script> - var loadDelay = setInterval(function() { - if (nodebb_admin) { - nodebb_admin.prepare(); - clearInterval(loadDelay); - } - }, 500); + require(['forum/admin/settings'], function(Settings) { + Settings.prepare(); + }); </script> \ No newline at end of file diff --git a/public/templates/admin/plugins.tpl b/public/templates/admin/plugins.tpl index 8c4943c32c..074d53f0d9 100644 --- a/public/templates/admin/plugins.tpl +++ b/public/templates/admin/plugins.tpl @@ -21,5 +21,3 @@ Full documentation regarding plugin authoring can be found in the <a target="_blank" href="https://github.com/designcreateplay/NodeBB/wiki/Writing-Plugins-for-NodeBB">NodeBB Wiki</a>. </p> </div> - -<script type="text/javascript" src="{relative_path}/src/forum/admin/plugins.js"></script> \ No newline at end of file diff --git a/public/templates/admin/settings.tpl b/public/templates/admin/settings.tpl index b01713c9a6..7aa4fefb30 100644 --- a/public/templates/admin/settings.tpl +++ b/public/templates/admin/settings.tpl @@ -83,10 +83,7 @@ <button class="btn btn-lg btn-primary" id="save">Save</button> <script> - var loadDelay = setInterval(function() { - if (nodebb_admin) { - nodebb_admin.prepare(); - clearInterval(loadDelay); - } - }, 500); + require(['forum/admin/settings'], function(Settings) { + Settings.prepare(); + }); </script> \ No newline at end of file diff --git a/public/templates/admin/themes.tpl b/public/templates/admin/themes.tpl index fb4aaefe6a..0aa9b18116 100644 --- a/public/templates/admin/themes.tpl +++ b/public/templates/admin/themes.tpl @@ -23,4 +23,10 @@ <button class="btn btn-warning" id="revert_theme">Revert</button> This will remove any custom theme applied to your NodeBB, and restore the base theme. </p> -<script type="text/javascript" src="{relative_path}/src/forum/admin/themes.js"></script> \ No newline at end of file +<script> + var bootswatchListener = function(data) { + require(['forum/admin/themes'], function(t) { + t.render(data); + }); + } +</script> \ No newline at end of file diff --git a/public/templates/admin/topics.tpl b/public/templates/admin/topics.tpl index ee6a058f4e..1521f400ac 100644 --- a/public/templates/admin/topics.tpl +++ b/public/templates/admin/topics.tpl @@ -22,5 +22,3 @@ <div class="text-center"> <button id="topics_loadmore" class="btn btn-primary btn-lg">Load More Topics</button> </div> - -<script type="text/javascript" src="{relative_path}/src/forum/admin/topics.js"></script> \ No newline at end of file diff --git a/public/templates/admin/twitter.tpl b/public/templates/admin/twitter.tpl index 77876e066b..fb826a37bc 100644 --- a/public/templates/admin/twitter.tpl +++ b/public/templates/admin/twitter.tpl @@ -17,10 +17,7 @@ <button class="btn btn-lg btn-primary" id="save">Save</button> <script> - var loadDelay = setInterval(function() { - if (nodebb_admin) { - nodebb_admin.prepare(); - clearInterval(loadDelay); - } - }, 500); + require(['forum/admin/settings'], function(Settings) { + Settings.prepare(); + }); </script> diff --git a/public/templates/admin/users.tpl b/public/templates/admin/users.tpl index 929a95c97c..0a3bde904e 100644 --- a/public/templates/admin/users.tpl +++ b/public/templates/admin/users.tpl @@ -42,6 +42,3 @@ <button id="load-more-users-btn" class="btn btn-primary">Load More</button> </div> <input type="hidden" template-variable="yourid" value="{yourid}" /> - - -<script type="text/javascript" src="{relative_path}/src/forum/admin/users.js"></script> diff --git a/public/templates/category.tpl b/public/templates/category.tpl index 35293467c4..b1894b4b9a 100644 --- a/public/templates/category.tpl +++ b/public/templates/category.tpl @@ -96,6 +96,4 @@ <input type="hidden" template-variable="category_id" value="{category_id}" /> <input type="hidden" template-variable="twitter-intent-url" value="{twitter-intent-url}" /> <input type="hidden" template-variable="facebook-share-url" value="{facebook-share-url}" /> -<input type="hidden" template-variable="google-share-url" value="{google-share-url}" /> - -<script type="text/javascript" src="{relative_path}/src/forum/category.js"></script> \ No newline at end of file +<input type="hidden" template-variable="google-share-url" value="{google-share-url}" /> \ No newline at end of file diff --git a/public/templates/favourites.tpl b/public/templates/favourites.tpl index 1d124e4710..ddeccd1984 100644 --- a/public/templates/favourites.tpl +++ b/public/templates/favourites.tpl @@ -22,6 +22,3 @@ </div> </div> </div> - -<script type="text/javascript" src="{relative_path}/src/forum/accountheader.js"></script> -<script type="text/javascript" src="{relative_path}/src/forum/favourites.js"></script> diff --git a/public/templates/followers.tpl b/public/templates/followers.tpl index 5093d40713..9e118eb1cd 100644 --- a/public/templates/followers.tpl +++ b/public/templates/followers.tpl @@ -34,6 +34,3 @@ <input type="hidden" template-variable="yourid" value="{yourid}" /> <input type="hidden" template-variable="theirid" value="{theirid}" /> <input type="hidden" template-variable="followersCount" value="{followersCount}" /> - -<script type="text/javascript" src="{relative_path}/src/forum/followers.js"></script> -<script type="text/javascript" src="{relative_path}/src/forum/accountheader.js"></script> \ No newline at end of file diff --git a/public/templates/following.tpl b/public/templates/following.tpl index 8215d9be31..9dda27d9d4 100644 --- a/public/templates/following.tpl +++ b/public/templates/following.tpl @@ -35,6 +35,3 @@ <input type="hidden" template-variable="yourid" value="{yourid}" /> <input type="hidden" template-variable="theirid" value="{theirid}" /> <input type="hidden" template-variable="followingCount" value="{followingCount}" /> - -<script type="text/javascript" src="{relative_path}/src/forum/following.js"></script> -<script type="text/javascript" src="{relative_path}/src/forum/accountheader.js"></script> diff --git a/public/templates/footer.tpl b/public/templates/footer.tpl index 38b4614a79..27d8a74458 100644 --- a/public/templates/footer.tpl +++ b/public/templates/footer.tpl @@ -53,7 +53,7 @@ </footer> <script> - $.getScript(RELATIVE_PATH + '/src/forum/footer.js'); + require(['forum/footer']); </script> </body> diff --git a/public/templates/header.tpl b/public/templates/header.tpl index c151a5bd58..3d55265365 100644 --- a/public/templates/header.tpl +++ b/public/templates/header.tpl @@ -15,8 +15,14 @@ <script> require.config({ baseUrl: "{relative_path}/src/modules", - waitSeconds: 3 + waitSeconds: 3, + paths: { + "forum": '../forum' + } }); + requirejs.onError = function(err) { + console.log(err); + } </script> <link rel="stylesheet" type="text/css" href="{relative_path}/css/nodebb.css" /> diff --git a/public/templates/login.tpl b/public/templates/login.tpl index 11d0b86566..10d9d08948 100644 --- a/public/templates/login.tpl +++ b/public/templates/login.tpl @@ -60,5 +60,3 @@ </div> </div> </div> - -<script type="text/javascript" src="{relative_path}/src/forum/login.js"></script> \ No newline at end of file diff --git a/public/templates/recent.tpl b/public/templates/recent.tpl index 70c25a978f..8cf6127874 100644 --- a/public/templates/recent.tpl +++ b/public/templates/recent.tpl @@ -49,5 +49,3 @@ </ul> </div> </div> - -<script type="text/javascript" src="{relative_path}/src/forum/recent.js"></script> diff --git a/public/templates/register.tpl b/public/templates/register.tpl index 7184f0d3a4..06a9f980e8 100644 --- a/public/templates/register.tpl +++ b/public/templates/register.tpl @@ -80,5 +80,3 @@ </div> </div> </div> - -<script type="text/javascript" src="{relative_path}/src/forum/register.js"></script> \ No newline at end of file diff --git a/public/templates/reset.tpl b/public/templates/reset.tpl index 5dadf7ce32..3ac48f2752 100644 --- a/public/templates/reset.tpl +++ b/public/templates/reset.tpl @@ -26,5 +26,3 @@ <button class="btn btn-primary btn-block btn-lg" id="reset" type="submit">Reset Password</button> </form> </div> - -<script type="text/javascript" src="{relative_path}/src/forum/reset.js"></script> \ No newline at end of file diff --git a/public/templates/reset_code.tpl b/public/templates/reset_code.tpl index dc8a4aab07..0f145d4f48 100644 --- a/public/templates/reset_code.tpl +++ b/public/templates/reset_code.tpl @@ -34,6 +34,3 @@ </form> </div> <input type="hidden" template-variable="reset_code" value="{reset_code}" /> - - -<script type="text/javascript" src="{relative_path}/src/forum/reset_code.js"></script> \ No newline at end of file diff --git a/public/templates/search.tpl b/public/templates/search.tpl index 30e8995925..87c57c3ca1 100644 --- a/public/templates/search.tpl +++ b/public/templates/search.tpl @@ -53,5 +53,3 @@ </ul> </div> </div> - -<script type="text/javascript" src="{relative_path}/src/forum/search.js"></script> diff --git a/public/templates/topic.tpl b/public/templates/topic.tpl index a568e61cc0..42473a4274 100644 --- a/public/templates/topic.tpl +++ b/public/templates/topic.tpl @@ -199,7 +199,3 @@ <input type="hidden" template-variable="pinned" value="{pinned}" /> <input type="hidden" template-variable="topic_name" value="{topic_name}" /> <input type="hidden" template-variable="postcount" value="{postcount}" /> - - - -<script type="text/javascript" src="{relative_path}/src/forum/topic.js"></script> \ No newline at end of file diff --git a/public/templates/unread.tpl b/public/templates/unread.tpl index d960ded415..6d1ec7dcca 100644 --- a/public/templates/unread.tpl +++ b/public/templates/unread.tpl @@ -54,5 +54,3 @@ </div> </div> </div> - -<script type="text/javascript" src="{relative_path}/src/forum/unread.js"></script> \ No newline at end of file diff --git a/public/templates/users.tpl b/public/templates/users.tpl index fdd7abcafc..d68b7cd397 100644 --- a/public/templates/users.tpl +++ b/public/templates/users.tpl @@ -45,5 +45,3 @@ <button id="load-more-users-btn" class="btn btn-primary">[[users:load_more]]</button> </div> </div> - -<script type="text/javascript" src="{relative_path}/src/forum/users.js"></script> \ No newline at end of file diff --git a/src/webserver.js b/src/webserver.js index 585d6566bc..a09ec60258 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -135,22 +135,22 @@ var express = require('express'), app.use(function (req, res, next) { res.status(404); - // respond with html page - if (req.accepts('html')) { + if (path.dirname(req.url) === '/src/forum') { + // Handle missing client-side scripts + res.type('text/javascript').send(200, ''); + } else if (req.accepts('html')) { + // respond with html page + winston.warn('Route requested but not found: ' + req.url); res.redirect(nconf.get('relative_path') + '/404'); - return; - } - - // respond with json - if (req.accepts('json')) { - res.send({ + } else if (req.accepts('json')) { + // respond with json + res.json({ error: 'Not found' }); - return; + } else { + // default to plain-text. send() + res.type('txt').send('Not found'); } - - // default to plain-text. send() - res.type('txt').send('Not found'); }); app.use(function (err, req, res, next) { From 64117ab6135f5ec7e7a22d5f2f3b6885affc8c8a Mon Sep 17 00:00:00 2001 From: Julian Lam <julian@designcreateplay.com> Date: Thu, 3 Oct 2013 15:07:30 -0400 Subject: [PATCH 18/29] removing deprecated bootstrap css file from admin header --- public/templates/admin/header.tpl | 1 - 1 file changed, 1 deletion(-) diff --git a/public/templates/admin/header.tpl b/public/templates/admin/header.tpl index aefd3dc6b6..dc3004c3a2 100644 --- a/public/templates/admin/header.tpl +++ b/public/templates/admin/header.tpl @@ -7,7 +7,6 @@ var RELATIVE_PATH = "{relative_path}"; </script> <link id="base-theme" href="{relative_path}/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen"> - <link href="{relative_path}/vendor/bootstrap/css/bootstrap-responsive.min.css" rel="stylesheet" media="screen"> <link rel="stylesheet" href="{relative_path}/vendor/fontawesome/css/font-awesome.min.css"> <script type="text/javascript" src="http://code.jquery.com/jquery.js"></script> <script type="text/javascript" src="{relative_path}/vendor/bootstrap/js/bootstrap.min.js"></script> From 0e18ec022c4a8f31112e9709dbf82c33b306f13d Mon Sep 17 00:00:00 2001 From: Julian Lam <julian@designcreateplay.com> Date: Thu, 3 Oct 2013 15:51:48 -0400 Subject: [PATCH 19/29] not running init() if there is no init method in each template script --- public/src/ajaxify.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 12ede65135..7b8cf215fb 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -77,7 +77,7 @@ var ajaxify = {}; templates.load_template(function () { exec_body_scripts(content); require(['forum/' + tpl_url], function(script) { - if (script) script.init(); + if (script && script.init) script.init(); }); if (callback) { From 46f03de9f65af561a76986aaef30a357c551685d Mon Sep 17 00:00:00 2001 From: Peter Peterson <peter@artfire.com> Date: Thu, 3 Oct 2013 13:00:30 -0700 Subject: [PATCH 20/29] Added ability to set redis db to use, defaults to db0 --- src/install.js | 10 ++++++++-- src/redis.js | 11 +++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/install.js b/src/install.js index d84682ebc7..eb292e319c 100644 --- a/src/install.js +++ b/src/install.js @@ -42,6 +42,10 @@ var async = require('async'), }, { name: 'redis:password', description: 'Password of your Redis database' + }, { + name: "redis:database", + description: "Which database to use (0..n)", + 'default': 0 }, { name: 'bind_address', description: 'IP or Hostname to bind to', @@ -64,12 +68,14 @@ var async = require('async'), config.redis = { host: config['redis:host'], port: config['redis:port'], - password: config['redis:password'] + password: config['redis:password'], + database: config['redis:database'] }; delete config['redis:host']; delete config['redis:port']; delete config['redis:password']; - + delete config['redis:database']; + // Add hardcoded values config.bcrypt_rounds = 12; config.upload_path = '/public/uploads'; diff --git a/src/redis.js b/src/redis.js index c66c720788..b5852f92b3 100644 --- a/src/redis.js +++ b/src/redis.js @@ -17,6 +17,17 @@ RedisDB.exports.auth(nconf.get('redis:password')); } + if( (db = nconf.get('redis:database')) ){ + RedisDB.exports.select(db, function(error){ + if(error !== null){ + winston.err(error); + if (global.env !== 'production') { + throw new Error(error); + } + } + }); + } + RedisDB.exports.handle = function(error) { if (error !== null) { winston.err(error); From 585e07bc793539ea107ee3180ca20d35107b455d Mon Sep 17 00:00:00 2001 From: Julian Lam <julian.lam@gmail.com> Date: Thu, 3 Oct 2013 20:35:16 -0400 Subject: [PATCH 21/29] closed #368 - notifications now no longer need scores --- src/notifications.js | 33 +++++++++++++-------------------- src/threadTools.js | 2 +- src/user.js | 22 +++------------------- src/websockets.js | 2 +- 4 files changed, 18 insertions(+), 41 deletions(-) diff --git a/src/notifications.js b/src/notifications.js index c2fb26cd26..d2e1477aac 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -15,29 +15,22 @@ var RDB = require('./redis.js'), }); }); }, - create: function(text, score, path, uniqueId, callback) { - /* - * Score guide: - * 0 Low priority messages (probably unused) - * 5 Normal messages - * 10 High priority messages - * + create: function(text, path, uniqueId, callback) { + /** * uniqueId is used solely to override stale nids. * If a new nid is pushed to a user and an existing nid in the user's * (un)read list contains the same uniqueId, it will be removed, and * the new one put in its place. */ RDB.incr('notifications:next_nid', function(err, nid) { - RDB.hmset( - 'notifications:' + nid, - 'text', text || '', - 'score', score || 5, - 'path', path || null, - 'datetime', Date.now(), - 'uniqueId', uniqueId || utils.generateUUID(), - function(err, status) { - if (status === 'OK') callback(nid); - }); + RDB.hmset('notifications:' + nid, { + text: text || '', + path: path || null, + datetime: Date.now(), + uniqueId: uniqueId || utils.generateUUID() + }, function(err, status) { + if (!err) callback(nid); + }); }); }, push: function(nid, uids, callback) { @@ -51,8 +44,8 @@ var RDB = require('./redis.js'), if (parseInt(uids[x]) > 0) { (function(uid) { notifications.remove_by_uniqueId(notif_data.uniqueId, uid, function() { - RDB.zadd('uid:' + uid + ':notifications:unread', notif_data.score, nid); - global.io.sockets. in ('uid_' + uid).emit('event:new_notification'); + RDB.zadd('uid:' + uid + ':notifications:unread', notif_data.datetime, nid); + global.io.sockets.in('uid_' + uid).emit('event:new_notification'); if (callback) callback(true); }); })(uids[x]); @@ -98,7 +91,7 @@ var RDB = require('./redis.js'), if (parseInt(uid) > 0) { notifications.get(nid, function(notif_data) { RDB.zrem('uid:' + uid + ':notifications:unread', nid); - RDB.zadd('uid:' + uid + ':notifications:read', notif_data.score, nid); + RDB.zadd('uid:' + uid + ':notifications:read', notif_data.datetime, nid); if (callback) callback(); }); } diff --git a/src/threadTools.js b/src/threadTools.js index 23b641f0d2..bd0c1a126c 100644 --- a/src/threadTools.js +++ b/src/threadTools.js @@ -276,7 +276,7 @@ var RDB = require('./redis.js'), topics.getTopicField(tid, 'title', function(err, title) { topics.getTeaser(tid, function(err, teaser) { if (!err) { - notifications.create('<strong>' + teaser.username + '</strong> has posted a reply to: "<strong>' + title + '</strong>"', null, nconf.get('relative_path') + '/topic/' + tid, 'topic:' + tid, function(nid) { + notifications.create('<strong>' + teaser.username + '</strong> has posted a reply to: "<strong>' + title + '</strong>"', nconf.get('relative_path') + '/topic/' + tid, 'topic:' + tid, function(nid) { next(null, nid); }); } else next(err); diff --git a/src/user.js b/src/user.js index bbe6779303..4c6ccfc811 100644 --- a/src/user.js +++ b/src/user.js @@ -578,7 +578,7 @@ var utils = require('./../public/src/utils.js'), topics.getTopicField(tid, 'slug', function(err, slug) { var message = '<strong>' + username + '</strong> made a new post'; - notifications.create(message, 5, nconf.get('relative_path') + '/topic/' + slug + '#' + pid, 'topic:' + tid, function(nid) { + notifications.create(message, nconf.get('relative_path') + '/topic/' + slug + '#' + pid, 'topic:' + tid, function(nid) { notifications.push(nid, followers); }); }); @@ -888,7 +888,7 @@ var utils = require('./../public/src/utils.js'), async.parallel({ unread: function(next) { - RDB.zrevrangebyscore('uid:' + uid + ':notifications:unread', 10, 0, function(err, nids) { + RDB.zrevrange('uid:' + uid + ':notifications:unread', 0, 10, function(err, nids) { // @todo handle err var unread = []; @@ -910,7 +910,7 @@ var utils = require('./../public/src/utils.js'), }); }, read: function(next) { - RDB.zrevrangebyscore('uid:' + uid + ':notifications:read', 10, 0, function(err, nids) { + RDB.zrevrange('uid:' + uid + ':notifications:read', 0, 10, function(err, nids) { // @todo handle err var read = []; @@ -932,22 +932,6 @@ var utils = require('./../public/src/utils.js'), }); } }, function(err, notifications) { - // While maintaining score sorting, sort by time - var readCount = notifications.read.length, - unreadCount = notifications.unread.length; - - notifications.read.sort(function(a, b) { - if (a.score === b.score) { - return (a.datetime - b.datetime) > 0 ? -1 : 1; - } - }); - - notifications.unread.sort(function(a, b) { - if (a.score === b.score) { - return (a.datetime - b.datetime) > 0 ? -1 : 1; - } - }); - // Limit the number of notifications to `maxNotifs`, prioritising unread notifications if (notifications.read.length + notifications.unread.length > maxNotifs) { notifications.read.length = maxNotifs - notifications.unread.length; diff --git a/src/websockets.js b/src/websockets.js index 27cdb0ef8a..90784ad847 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -580,7 +580,7 @@ module.exports.init = function(io) { notifText = 'New message from <strong>' + username + '</strong>'; if (!isUserOnline(touid)) { - notifications.create(notifText, 5, 'javascript:app.openChat('' + username + '', ' + uid + ');', 'notification_' + uid + '_' + touid, function(nid) { + notifications.create(notifText, 'javascript:app.openChat('' + username + '', ' + uid + ');', 'notification_' + uid + '_' + touid, function(nid) { notifications.push(nid, [touid], function(success) { }); From 763bd775c436000462d6fdaa598af1f8d7277b4e Mon Sep 17 00:00:00 2001 From: Julian Lam <julian.lam@gmail.com> Date: Thu, 3 Oct 2013 21:18:59 -0400 Subject: [PATCH 22/29] closed #380 --- src/threadTools.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/threadTools.js b/src/threadTools.js index bd0c1a126c..6f7b9bbaf7 100644 --- a/src/threadTools.js +++ b/src/threadTools.js @@ -265,14 +265,15 @@ var RDB = require('./redis.js'), ThreadTools.get_followers = function(tid, callback) { RDB.smembers('tid:' + tid + ':followers', function(err, followers) { - callback(err, followers); + callback(err, followers.map(function(follower) { + return parseInt(follower, 10); + })); }); } ThreadTools.notify_followers = function(tid, exceptUid) { async.parallel([ function(next) { - topics.getTopicField(tid, 'title', function(err, title) { topics.getTeaser(tid, function(err, teaser) { if (!err) { @@ -282,11 +283,10 @@ var RDB = require('./redis.js'), } else next(err); }); }); - - }, function(next) { ThreadTools.get_followers(tid, function(err, followers) { + exceptUid = parseInt(exceptUid, 10); if (followers.indexOf(exceptUid) !== -1) followers.splice(followers.indexOf(exceptUid), 1); next(null, followers); }); From 4d6881fa65f440a4c30c6881c4d8ae2671879007 Mon Sep 17 00:00:00 2001 From: Julian Lam <julian.lam@gmail.com> Date: Thu, 3 Oct 2013 22:36:00 -0400 Subject: [PATCH 23/29] reset update for 0.0.7, and added new schema update for notifications --- src/upgrade.js | 213 +++++++------------------------------------------ 1 file changed, 31 insertions(+), 182 deletions(-) diff --git a/src/upgrade.js b/src/upgrade.js index 36dfb076c4..b060c532c5 100644 --- a/src/upgrade.js +++ b/src/upgrade.js @@ -1,193 +1,42 @@ var RDB = require('./redis.js'), async = require('async'), winston = require('winston'), - user = require('./user'), - Groups = require('./groups'); - - -function upgradeCategory(cid, callback) { - RDB.type('categories:' + cid + ':tid', function(err, type) { - if (type === 'set') { - RDB.smembers('categories:' + cid + ':tid', function(err, tids) { - - function moveTopic(tid, callback) { - RDB.hget('topic:' + tid, 'timestamp', function(err, timestamp) { - if (err) - return callback(err); - - RDB.zadd('temp_categories:' + cid + ':tid', timestamp, tid); - callback(null); + notifications = require('./notifications') + Upgrade = {}; + +Upgrade.upgrade = function() { + winston.info('Beginning Redis database schema update'); + + async.series([ + function(next) { + RDB.hget('notifications:1', 'score', function(err, score) { + if (score) { + winston.info('[2013/10/03] Updating Notifications'); + RDB.keys('uid:*:notifications:*', function(err, keys) { + async.each(keys, function(key, next) { + RDB.zrange(key, 0, -1, function(err, nids) { + async.each(nids, function(nid, next) { + notifications.get(nid, function(notif_data) { + RDB.zadd(key, notif_data.datetime, nid, next); + }); + }, next); + }); + }, next); }); + } else { + winston.info('[2013/10/03] Updates to Notifications skipped.'); } - - async.each(tids, moveTopic, function(err) { - if (!err) { - RDB.rename('temp_categories:' + cid + ':tid', 'categories:' + cid + ':tid'); - callback(null); - } else - callback(err); - }); - }); - } else { - winston.info('category already upgraded ' + cid); - callback(null); } - }); -} - -function upgradeUser(uid, callback) { - user.getUserFields(uid, ['joindate', 'postcount', 'reputation'], function(err, userData) { - if (err) - return callback(err); - - async.parallel([ - function(next) { - if (userData.joindate) - RDB.zadd('users:joindate', userData.joindate, uid, next); - else - next(null); - }, - function(next) { - if (userData.postcount) - RDB.zadd('users:postcount', userData.postcount, uid, next); - else - next(null); - }, - function(next) { - if (userData.reputation) - RDB.zadd('users:reputation', userData.reputation, uid, next); - else - next(null); - } - ], function(err, result) { - callback(err); - }); - }); -} - -function upgradeUserHash(uid, callback) { - user.getUserFields(uid, ['username', 'userslug', 'email'], function(err, userData) { - if (err) - return callback(err); - - async.parallel([ - function(next) { - if (userData.username) - RDB.hset('username:uid', userData.username, uid, next); - else - next(null); - }, - function(next) { - if (userData.userslug) - RDB.hset('userslug:uid', userData.userslug, uid, next); - else - next(null); - }, - function(next) { - if (userData.email) - RDB.hset('email:uid', userData.email, uid, next); - else - next(null); - } - - ], function(err, result) { - callback(err); - }); - }); -} - -function upgradeAdmins(callback) { - Groups.getGidFromName('Administrators', function(err, gid) { - if (!err && !gid) { - winston.info('Upgrading Administrators'); - - async.parallel([ - function(next) { - RDB.smembers("administrators", next); - }, - function(next) { - Groups.create('Administrators', 'Forum Administrators', next); - } - ], function(err, results) { - var gid = results[1].gid; - - async.each(results[0], function(uid, next) { - Groups.join(gid, uid, next); - }, callback); - }); + // Add new schema updates here + ], function(err) { + if (!err) { + winston.info('Redis schema update complete!'); + process.exit(); } else { - winston.info('Administrators group OK') - callback(); + winston.error('Errors were encountered while updating the NodeBB schema: ' + err.message); } }); -} - -exports.upgrade = function() { - - winston.info('upgrading nodebb now'); - - var schema = [ - function upgradeCategories(next) { - winston.info('upgrading categories'); - - RDB.lrange('categories:cid', 0, -1, function(err, cids) { - - async.each(cids, upgradeCategory, function(err) { - if (!err) { - winston.info('upgraded categories'); - next(null, null); - } else { - next(err, null); - } - }); - }); - }, - - function upgradeUsers(next) { - winston.info('upgrading users'); - - RDB.lrange('userlist', 0, -1, function(err, uids) { - - async.each(uids, upgradeUser, function(err) { - if (!err) { - winston.info('upgraded users'); - next(null, null); - } else { - next(err, null); - } - }); +}; - }); - }, - - function upgradeUserHashes(next) { - winston.info('upgrading user hashes'); - RDB.zrange('users:joindate', 0, -1, function(err, uids) { - if (err) - return next(err); - - async.each(uids, upgradeUserHash, function(err) { - if (!err) { - winston.info('upgraded user hashes'); - next(null, null); - } else { - next(err, null); - } - }); - }); - }, - - upgradeAdmins - ]; - - async.series(schema, function(err, results) { - if (!err) - winston.info('upgrade complete'); - else - winston.err(err); - - process.exit(); - - }); -} \ No newline at end of file +module.exports = Upgrade; \ No newline at end of file From 12af2a7ff62833eac010f0788c64fc6e62d01f8c Mon Sep 17 00:00:00 2001 From: Julian Lam <julian.lam@gmail.com> Date: Thu, 3 Oct 2013 23:10:17 -0400 Subject: [PATCH 24/29] install script calling proper redis db --- app.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app.js b/app.js index a081cd4fa3..750e128288 100644 --- a/app.js +++ b/app.js @@ -109,6 +109,9 @@ } else if (nconf.get('upgrade')) { meta = require('./src/meta.js'); + nconf.file({ + file: __dirname + '/config.json' + }); meta.configs.init(function () { require('./src/upgrade').upgrade(); From 0414ec7f837656e3c0ed1698cac2f6c0c316face Mon Sep 17 00:00:00 2001 From: Julian Lam <julian.lam@gmail.com> Date: Thu, 3 Oct 2013 23:21:29 -0400 Subject: [PATCH 25/29] removing testbed code from repo (why was it even checked in?!!) --- src/routes/testbed.js | 75 ------------------------------------------- src/webserver.js | 2 -- 2 files changed, 77 deletions(-) delete mode 100644 src/routes/testbed.js diff --git a/src/routes/testbed.js b/src/routes/testbed.js deleted file mode 100644 index df9dc2c9c2..0000000000 --- a/src/routes/testbed.js +++ /dev/null @@ -1,75 +0,0 @@ -(function(TestBed) { - TestBed.create_routes = function(app) { - - app.get('/bench/forloop', function(req, res) { - var benchData = {}; - - var myArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; - - function f(x) { - return x; - } - - var runCount = req.query.runs ? req.query.runs : 1000000; - - function withCaching() { - var time = process.hrtime(); - - for (var n = 0; n < runCount; ++n) { - for (var i = 0, len = myArray.length; i < len; ++i) { - f(myArray[i]); - } - } - - var diff = process.hrtime(time); - diff = diff[0] + diff[1] / 1e9; - return diff; - } - - function withoutCaching() { - var time = process.hrtime(); - - for (var n = 0; n < runCount; ++n) { - for (var i = 0; i < myArray.length; ++i) { - f(myArray[i]); - } - } - - var diff = process.hrtime(time); - diff = diff[0] + diff[1] / 1e9; - return diff; - } - - function withForeach() { - var time = process.hrtime(); - - for (var n = 0; n < runCount; ++n) { - myArray.forEach(function(index) { - - }); - } - - var diff = process.hrtime(time); - diff = diff[0] + diff[1] / 1e9; - return diff; - } - - benchData['runs'] = runCount; - - benchData['withCaching'] = withCaching(); - benchData['withoutCaching'] = withoutCaching(); - benchData['withForeach'] = withForeach(); - - res.json(benchData); - - - }); - - - - - - }; - - -}(exports)); \ No newline at end of file diff --git a/src/webserver.js b/src/webserver.js index a09ec60258..e1d3bfa591 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -17,7 +17,6 @@ var express = require('express'), admin = require('./routes/admin.js'), userRoute = require('./routes/user.js'), apiRoute = require('./routes/api.js'), - testBed = require('./routes/testbed.js'), auth = require('./routes/authentication.js'), meta = require('./meta.js'), feed = require('./feed'), @@ -201,7 +200,6 @@ var express = require('express'), auth.create_routes(app); admin.create_routes(app); userRoute.create_routes(app); - testBed.create_routes(app); apiRoute.create_routes(app); From 07d07020f0a8c6b87337dc5216781a4e220559b4 Mon Sep 17 00:00:00 2001 From: Julian Lam <julian.lam@gmail.com> Date: Fri, 4 Oct 2013 10:06:17 -0400 Subject: [PATCH 26/29] requiring latest nodebb plugin versions --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e9244ea8db..e96d196792 100644 --- a/package.json +++ b/package.json @@ -34,8 +34,8 @@ "request": "~2.25.0", "reds": "~0.2.4", "winston": "~0.7.2", - "nodebb-plugin-mentions": "~0.1.0", - "nodebb-plugin-markdown": "~0.1.0", + "nodebb-plugin-mentions": "~0.1.9", + "nodebb-plugin-markdown": "~0.1.2", "rss": "~0.2.0", "prompt": "~0.2.11", "uglify-js": "~2.4.0", From be8d9be832b4b82e098a319100ba0675c689ad96 Mon Sep 17 00:00:00 2001 From: Julian Lam <julian.lam@gmail.com> Date: Fri, 4 Oct 2013 10:27:32 -0400 Subject: [PATCH 27/29] flushed out upgrade path for notifications --- src/upgrade.js | 50 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/src/upgrade.js b/src/upgrade.js index b060c532c5..153c7c0399 100644 --- a/src/upgrade.js +++ b/src/upgrade.js @@ -11,20 +11,52 @@ Upgrade.upgrade = function() { function(next) { RDB.hget('notifications:1', 'score', function(err, score) { if (score) { - winston.info('[2013/10/03] Updating Notifications'); - RDB.keys('uid:*:notifications:*', function(err, keys) { - async.each(keys, function(key, next) { - RDB.zrange(key, 0, -1, function(err, nids) { - async.each(nids, function(nid, next) { - notifications.get(nid, function(notif_data) { - RDB.zadd(key, notif_data.datetime, nid, next); + async.series([ + function(next) { + RDB.keys('uid:*:notifications:flag', function(err, keys) { + if (keys.length > 0) { + winston.info('[2013/10/03] Removing deprecated Notification Flags'); + async.each(keys, function(key, next) { + RDB.del(key, next); + }, next); + } else { + winston.info('[2013/10/03] No Notification Flags found. Good.'); + next(); + } + }); + }, + function(next) { + winston.info('[2013/10/03] Updating Notifications'); + RDB.keys('uid:*:notifications:*', function(err, keys) { + async.each(keys, function(key, next) { + RDB.zrange(key, 0, -1, function(err, nids) { + async.each(nids, function(nid, next) { + notifications.get(nid, function(notif_data) { + RDB.zadd(key, notif_data.datetime, nid, next); + }); + }, next); }); }, next); }); - }, next); - }); + }, + function(next) { + RDB.keys('notifications:*', function(err, keys) { + if (keys.length > 0) { + winston.info('[2013/10/03] Removing Notification Scores'); + async.each(keys, function(key, next) { + if (key === 'notifications:next_nid') return next(); + RDB.hdel(key, 'score', next); + }, next); + } else { + winston.info('[2013/10/03] No Notification Scores found. Good.'); + next(); + } + }); + } + ], next); } else { winston.info('[2013/10/03] Updates to Notifications skipped.'); + next(); } }); } From 01e04d60a99eecb1b92130250b34814972608f52 Mon Sep 17 00:00:00 2001 From: Julian Lam <julian.lam@gmail.com> Date: Fri, 4 Oct 2013 10:34:08 -0400 Subject: [PATCH 28/29] fixing redis db in upgrade path --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index 750e128288..492faf9609 100644 --- a/app.js +++ b/app.js @@ -108,10 +108,10 @@ }); } else if (nconf.get('upgrade')) { - meta = require('./src/meta.js'); nconf.file({ file: __dirname + '/config.json' }); + meta = require('./src/meta.js'); meta.configs.init(function () { require('./src/upgrade').upgrade(); From 57465eb2775c596825313e6767f9f01a3b131691 Mon Sep 17 00:00:00 2001 From: Julian Lam <julian.lam@gmail.com> Date: Fri, 4 Oct 2013 10:37:32 -0400 Subject: [PATCH 29/29] misrouting now only shows warning when in debug mode --- src/webserver.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/webserver.js b/src/webserver.js index e1d3bfa591..0759ae3e37 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -139,10 +139,11 @@ var express = require('express'), res.type('text/javascript').send(200, ''); } else if (req.accepts('html')) { // respond with html page - winston.warn('Route requested but not found: ' + req.url); + if (process.env.NODE_ENV === 'development') winston.warn('Route requested but not found: ' + req.url); res.redirect(nconf.get('relative_path') + '/404'); } else if (req.accepts('json')) { // respond with json + if (process.env.NODE_ENV === 'development') winston.warn('Route requested but not found: ' + req.url); res.json({ error: 'Not found' });