diff --git a/public/language/en-GB/user.json b/public/language/en-GB/user.json index 5dc59cd59c..18d17aeb18 100644 --- a/public/language/en-GB/user.json +++ b/public/language/en-GB/user.json @@ -28,6 +28,7 @@ "reputation": "Reputation", "bookmarks":"Bookmarks", "watched_categories": "Watched categories", + "change_all": "Change All", "watched": "Watched", "ignored": "Ignored", "default-category-watch-state": "Default category watch state", diff --git a/public/src/client/account/categories.js b/public/src/client/account/categories.js index 7acebaec4a..1522af929a 100644 --- a/public/src/client/account/categories.js +++ b/public/src/client/account/categories.js @@ -10,6 +10,21 @@ define('forum/account/categories', ['forum/account/header'], function (header) { ajaxify.data.categories.forEach(function (category) { handleIgnoreWatch(category.cid); }); + + $('[component="category/watch/all"]').find('[component="category/watching"], [component="category/ignoring"], [component="category/notwatching"]').on('click', function () { + var cids = []; + var state = $(this).attr('data-state'); + $('[data-parent-cid="0"]').each(function (index, el) { + cids.push($(el).attr('data-cid')); + }); + + socket.emit('categories.setWatchState', { cid: cids, state: state, uid: ajaxify.data.uid }, function (err, modified_cids) { + if (err) { + return app.alertError(err.message); + } + updateDropdowns(modified_cids, state); + }); + }); }; function handleIgnoreWatch(cid) { @@ -22,21 +37,24 @@ define('forum/account/categories', ['forum/account/header'], function (header) { if (err) { return app.alertError(err.message); } + updateDropdowns(modified_cids, state); - modified_cids.forEach(function (cid) { - var category = $('[data-cid="' + cid + '"]'); - category.find('[component="category/watching/menu"]').toggleClass('hidden', state !== 'watching'); - category.find('[component="category/watching/check"]').toggleClass('fa-check', state === 'watching'); + app.alertSuccess('[[category:' + state + '.message]]'); + }); + }); + } - category.find('[component="category/notwatching/menu"]').toggleClass('hidden', state !== 'notwatching'); - category.find('[component="category/notwatching/check"]').toggleClass('fa-check', state === 'notwatching'); + function updateDropdowns(modified_cids, state) { + modified_cids.forEach(function (cid) { + var category = $('[data-cid="' + cid + '"]'); + category.find('[component="category/watching/menu"]').toggleClass('hidden', state !== 'watching'); + category.find('[component="category/watching/check"]').toggleClass('fa-check', state === 'watching'); - category.find('[component="category/ignoring/menu"]').toggleClass('hidden', state !== 'ignoring'); - category.find('[component="category/ignoring/check"]').toggleClass('fa-check', state === 'ignoring'); - }); + category.find('[component="category/notwatching/menu"]').toggleClass('hidden', state !== 'notwatching'); + category.find('[component="category/notwatching/check"]').toggleClass('fa-check', state === 'notwatching'); - app.alertSuccess('[[category:' + state + '.message]]'); - }); + category.find('[component="category/ignoring/menu"]').toggleClass('hidden', state !== 'ignoring'); + category.find('[component="category/ignoring/check"]').toggleClass('fa-check', state === 'ignoring'); }); } diff --git a/src/categories/index.js b/src/categories/index.js index a21340c900..661275e6c4 100644 --- a/src/categories/index.js +++ b/src/categories/index.js @@ -23,6 +23,9 @@ require('./update')(Categories); require('./watch')(Categories); Categories.exists = async function (cid) { + if (Array.isArray(cid)) { + return await db.exists(cid.map(cid => 'category:' + cid)); + } return await db.exists('category:' + cid); }; diff --git a/src/socket.io/categories.js b/src/socket.io/categories.js index 2f6c69a6e4..7b2c35b4aa 100644 --- a/src/socket.io/categories.js +++ b/src/socket.io/categories.js @@ -105,8 +105,8 @@ SocketCategories.setWatchState = async function (socket, data) { if (!data || !data.cid || !data.state) { throw new Error('[[error:invalid-data]]'); } - return await ignoreOrWatch(async function (uid, cid) { - await user.setCategoryWatchState(uid, cid, categories.watchStates[data.state]); + return await ignoreOrWatch(async function (uid, cids) { + await user.setCategoryWatchState(uid, cids, categories.watchStates[data.state]); }, socket, data); }; @@ -120,7 +120,7 @@ SocketCategories.ignore = async function (socket, data) { async function ignoreOrWatch(fn, socket, data) { let targetUid = socket.uid; - const cids = [parseInt(data.cid, 10)]; + const cids = Array.isArray(data.cid) ? data.cid.map(cid => parseInt(cid, 10)) : [parseInt(data.cid, 10)]; if (data.hasOwnProperty('uid')) { targetUid = data.uid; } @@ -137,7 +137,7 @@ async function ignoreOrWatch(fn, socket, data) { } } while (cat); - await Promise.all(cids.map(cid => fn(targetUid, cid))); + await fn(targetUid, cids); await topics.pushUnreadCount(targetUid); return cids; } diff --git a/src/user/categories.js b/src/user/categories.js index 74a6b4ed7d..eea9d6983a 100644 --- a/src/user/categories.js +++ b/src/user/categories.js @@ -6,7 +6,7 @@ const db = require('../database'); const categories = require('../categories'); module.exports = function (User) { - User.setCategoryWatchState = async function (uid, cid, state) { + User.setCategoryWatchState = async function (uid, cids, state) { if (!(parseInt(uid, 10) > 0)) { return; } @@ -14,11 +14,12 @@ module.exports = function (User) { if (!isStateValid) { throw new Error('[[error:invalid-watch-state]]'); } - const exists = await categories.exists(cid); - if (!exists) { + cids = Array.isArray(cids) ? cids : [cids]; + const exists = await categories.exists(cids); + if (exists.includes(false)) { throw new Error('[[error:no-category]]'); } - await db.sortedSetAdd('cid:' + cid + ':uid:watch:state', state, uid); + await db.sortedSetsAdd(cids.map(cid => 'cid:' + cid + ':uid:watch:state'), state, uid); }; User.getCategoryWatchState = async function (uid) {