mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-02 12:05:57 +01:00
feat: ability to re-order topic thumbnails
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
define('topicThumbs', ['api', 'bootbox', 'uploader', 'benchpress', 'translator'], function (api, bootbox, uploader, Benchpress, translator) {
|
||||
define('topicThumbs', ['api', 'bootbox', 'uploader', 'benchpress', 'translator', 'jquery-ui/widgets/sortable'], function (api, bootbox, uploader, Benchpress, translator) {
|
||||
const Thumbs = {};
|
||||
|
||||
Thumbs.get = id => api.get(`/topics/${id}/thumbs`, {});
|
||||
@@ -32,30 +32,31 @@ define('topicThumbs', ['api', 'bootbox', 'uploader', 'benchpress', 'translator']
|
||||
Thumbs.modal.open = function (payload) {
|
||||
const { id, pid } = payload;
|
||||
let { modal } = payload;
|
||||
let numThumbs;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
Promise.all([
|
||||
Thumbs.get(id),
|
||||
pid ? Thumbs.getByPid(pid) : [],
|
||||
]).then(results => new Promise((resolve) => {
|
||||
resolve(results.reduce((memo, cur) => memo.concat(cur)));
|
||||
const thumbs = results.reduce((memo, cur) => memo.concat(cur));
|
||||
numThumbs = thumbs.length;
|
||||
|
||||
resolve(thumbs);
|
||||
})).then(thumbs => Benchpress.render('modals/topic-thumbs', { thumbs })).then((html) => {
|
||||
if (modal) {
|
||||
translator.translate(html, function (translated) {
|
||||
modal.find('.bootbox-body').html(translated);
|
||||
Thumbs.modal.handleSort({ modal, numThumbs });
|
||||
});
|
||||
} else {
|
||||
modal = bootbox.dialog({
|
||||
title: '[[modules:thumbs.modal.title]]',
|
||||
message: html,
|
||||
buttons: {
|
||||
close: {
|
||||
label: '[[global:close]]',
|
||||
className: 'btn-default',
|
||||
},
|
||||
add: {
|
||||
label: '<i class="fa fa-plus"></i> [[modules:thumbs.modal.add]]',
|
||||
className: 'btn-primary',
|
||||
className: 'btn-success',
|
||||
callback: () => {
|
||||
Thumbs.upload(id).then(() => {
|
||||
Thumbs.modal.open({ ...payload, modal });
|
||||
@@ -64,9 +65,14 @@ define('topicThumbs', ['api', 'bootbox', 'uploader', 'benchpress', 'translator']
|
||||
return false;
|
||||
},
|
||||
},
|
||||
close: {
|
||||
label: '[[global:close]]',
|
||||
className: 'btn-primary',
|
||||
},
|
||||
},
|
||||
});
|
||||
Thumbs.modal.handleDelete({ ...payload, modal });
|
||||
Thumbs.modal.handleSort({ modal, numThumbs });
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -94,5 +100,26 @@ define('topicThumbs', ['api', 'bootbox', 'uploader', 'benchpress', 'translator']
|
||||
});
|
||||
};
|
||||
|
||||
Thumbs.modal.handleSort = ({ modal, numThumbs }) => {
|
||||
if (numThumbs > 1) {
|
||||
const selectorEl = modal.find('.topic-thumbs-modal');
|
||||
selectorEl.sortable({
|
||||
items: '[data-id]',
|
||||
});
|
||||
selectorEl.on('sortupdate', Thumbs.modal.handleSortChange);
|
||||
}
|
||||
};
|
||||
|
||||
Thumbs.modal.handleSortChange = (ev, ui) => {
|
||||
const items = ui.item.get(0).parentNode.querySelectorAll('[data-id]');
|
||||
Array.from(items).forEach((el, order) => {
|
||||
const id = el.getAttribute('data-id');
|
||||
let path = el.getAttribute('data-path');
|
||||
path = path.replace(new RegExp(`^${config.upload_url}`), '');
|
||||
|
||||
api.put(`/topics/${id}/thumbs/order`, { path, order }).catch(app.alertError);
|
||||
});
|
||||
};
|
||||
|
||||
return Thumbs;
|
||||
});
|
||||
|
||||
@@ -166,6 +166,25 @@ Topics.deleteThumb = async (req, res) => {
|
||||
helpers.formatApiResponse(200, res, await topics.thumbs.get(req.params.tid));
|
||||
};
|
||||
|
||||
Topics.reorderThumbs = async (req, res) => {
|
||||
await checkThumbPrivileges({ tid: req.params.tid, uid: req.user.uid, res });
|
||||
if (res.headersSent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const exists = await topics.thumbs.exists(req.params.tid, req.body.path);
|
||||
if (!exists) {
|
||||
return helpers.formatApiResponse(404, res);
|
||||
}
|
||||
|
||||
await topics.thumbs.associate({
|
||||
id: req.params.tid,
|
||||
path: req.body.path,
|
||||
score: req.body.order,
|
||||
});
|
||||
helpers.formatApiResponse(200, res);
|
||||
};
|
||||
|
||||
async function checkThumbPrivileges({ tid, uid, res }) {
|
||||
// req.params.tid could be either a tid (pushing a new thumb to an existing topic)
|
||||
// or a post UUID (a new topic being composed)
|
||||
|
||||
@@ -37,8 +37,9 @@ module.exports = function () {
|
||||
|
||||
setupApiRoute(router, 'get', '/:tid/thumbs', middleware.authenticateOrGuest, controllers.write.topics.getThumbs);
|
||||
setupApiRoute(router, 'post', '/:tid/thumbs', [multipartMiddleware, middleware.validateFiles, ...middlewares], controllers.write.topics.addThumb);
|
||||
setupApiRoute(router, 'put', '/:tid/thumbs', [], controllers.write.topics.migrateThumbs);
|
||||
setupApiRoute(router, 'put', '/:tid/thumbs', [...middlewares, middleware.checkRequired.bind(null, ['tid'])], controllers.write.topics.migrateThumbs);
|
||||
setupApiRoute(router, 'delete', '/:tid/thumbs', [...middlewares, middleware.checkRequired.bind(null, ['path'])], controllers.write.topics.deleteThumb);
|
||||
setupApiRoute(router, 'put', '/:tid/thumbs/order', [...middlewares, middleware.checkRequired.bind(null, ['path', 'order'])], controllers.write.topics.reorderThumbs);
|
||||
|
||||
setupApiRoute(router, 'get', '/:tid/events', [middleware.authenticateOrGuest, middleware.assert.topic], controllers.write.topics.getEvents);
|
||||
|
||||
|
||||
@@ -15,9 +15,11 @@ const cache = require('../cache');
|
||||
|
||||
const Thumbs = module.exports;
|
||||
|
||||
Thumbs.exists = async function (tid, path) {
|
||||
// TODO: tests
|
||||
return db.isSortedSetMember(`topic:${tid}:thumbs`, path);
|
||||
Thumbs.exists = async function (id, path) {
|
||||
const isDraft = validator.isUUID(String(id));
|
||||
const set = `${isDraft ? 'draft' : 'topic'}:${id}:thumbs`;
|
||||
|
||||
return db.isSortedSetMember(set, path);
|
||||
};
|
||||
|
||||
Thumbs.load = async function (topicData) {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<button class="btn btn-danger" data-action="remove"><i class="fa fa-times"></i> [[modules:thumbs.modal.remove]]</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
{{{ end }}}
|
||||
<hr />
|
||||
<p class="help-block">[[modules:thumbs.modal.resize-note, {config.thumbs.size}]]</p>
|
||||
</div>
|
||||
@@ -80,11 +80,11 @@ describe('Topic thumbs', () => {
|
||||
|
||||
// Touch a couple files and associate it to a topic
|
||||
createFiles();
|
||||
await db.sortedSetAdd(`topic:${topicObj.topicData.tid}:thumbs`, 0, `/${relativeThumbPaths[0]}`);
|
||||
await db.sortedSetAdd(`topic:${topicObj.topicData.tid}:thumbs`, 0, `${relativeThumbPaths[0]}`);
|
||||
});
|
||||
|
||||
it('should return bool for whether a thumb exists', async () => {
|
||||
const exists = await topics.thumbs.exists(topicObj.topicData.tid, `/${relativeThumbPaths[0]}`);
|
||||
const exists = await topics.thumbs.exists(topicObj.topicData.tid, `${relativeThumbPaths[0]}`);
|
||||
assert.strictEqual(exists, true);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user