diff --git a/public/language/en-GB/topic.json b/public/language/en-GB/topic.json index 7cae6bfcd4..f736000fb9 100644 --- a/public/language/en-GB/topic.json +++ b/public/language/en-GB/topic.json @@ -184,10 +184,13 @@ "topic-id": "Topic ID", "move-posts-instruction": "Click the posts you want to move then enter a topic ID or go to the target topic", "move-topic-instruction": "Select the target category and then click move", - "crosspost-topic-instruction": "Select one or more categories to cross-post to. Topic(s) will be accessible from the original category and all cross-posted categories.", "change-owner-instruction": "Click the posts you want to assign to another user", "manage-editors-instruction": "Manage the users who can edit this post below.", + "crossposts.instructions": "Select one or more categories to cross-post to. Topic(s) will be accessible from the original category and all cross-posted categories.", + "crossposts.listing": "This topic has been cross-posted to the following local categories:", + "crossposts.none": "This topic has not been cross-posted to any additional categories", + "composer.title-placeholder": "Enter your topic title here...", "composer.handle-placeholder": "Enter your name/handle here", "composer.hide": "Hide", diff --git a/public/src/client/topic.js b/public/src/client/topic.js index 97787e749e..b54185bf80 100644 --- a/public/src/client/topic.js +++ b/public/src/client/topic.js @@ -414,7 +414,6 @@ define('forum/topic', [ const { crossposts } = ajaxify.data; const html = await app.parseAndTranslate('modals/crossposts', { crossposts }); bootbox.dialog({ - size: 'sm', onEscape: true, backdrop: true, title: '[[global:crossposts]]', diff --git a/public/src/client/topic/crosspost.js b/public/src/client/topic/crosspost.js new file mode 100644 index 0000000000..5c59eb855b --- /dev/null +++ b/public/src/client/topic/crosspost.js @@ -0,0 +1,126 @@ +'use strict'; + + +define('forum/topic/crosspost', [ + 'categoryFilter', 'alerts', 'hooks', 'api', 'components', +], function (categoryFilter, alerts, hooks, api, components) { + const Crosspost = {}; + let modal; + let selectedCids; + + Crosspost.init = function (tid) { + if (modal) { + return; + } + Crosspost.tid = tid; + Crosspost.cid = ajaxify.data.cid; + Crosspost.current = ajaxify.data.crossposts; + + showModal(); + }; + + function showModal() { + app.parseAndTranslate('modals/crosspost-topic', { + selectedCategory: ajaxify.data.crossposts.length ? + { + icon: 'fa-plus', + name: '[[unread:multiple-categories-selected]]', + bgColor: '#ddd', + } : + ajaxify.data.category, + }, function (html) { + modal = html; + $('body').append(modal); + + const dropdownEl = modal.find('[component="category-selector"]'); + dropdownEl.addClass('dropup'); + + categoryFilter.init($('[component="category/dropdown"]'), { + privilege: 'moderate', + onHidden: onCategoriesSelected, + hideAll: true, + hideUncategorized: true, + localOnly: true, + selectedCids: Array.from(new Set([ajaxify.data.cid, ...ajaxify.data.crossposts.map(c => c.cid)])), + }); + + modal.find('#crosspost_thread_commit').on('click', onCommitClicked); + modal.find('#crosspost_topic_cancel').on('click', closeCrosspostModal); + }); + } + + function onCategoriesSelected(data) { + ({ selectedCids } = data); + console.log('changed? ', data.changed); + if (data.changed) { + modal.find('#crosspost_thread_commit').prop('disabled', false); + } + } + + function onCommitClicked() { + const commitEl = modal.find('#crosspost_thread_commit'); + + if (!commitEl.prop('disabled') && selectedCids && selectedCids.length) { + commitEl.prop('disabled', true); + const data = { + tid: Crosspost.tid, + cids: selectedCids, + }; + + // TODO + // if (config.undoTimeout > 0) { + // return alerts.alert({ + // alert_id: 'tids_move_' + (Crosspost.tid ? Crosspost.tid.join('-') : 'all'), + // title: '[[topic:thread-tools.move]]', + // message: message, + // type: 'success', + // timeout: config.undoTimeout, + // timeoutfn: function () { + // moveTopics(data); + // }, + // clickfn: function (alert, params) { + // delete params.timeoutfn; + // alerts.success('[[topic:topic-move-undone]]'); + // }, + // }); + // } + + crosspost(data); + } + } + + function crosspost(data) { + hooks.fire('action:topic.crosspost', data); + + const cids = data.cids.map((cid) => parseInt(cid, 10)); + if (!cids.includes(Crosspost.cid)) { + cids.unshift(Crosspost.cid); + } + const current = [Crosspost.cid, ...Crosspost.current.map(x => parseInt(x.cid, 10))]; + const add = cids.filter(cid => !current.includes(cid)); + const remove = current.filter(cid => !cids.includes(cid)); + + const queries = [ + ...add.map((cid) => { return api.post(`/topics/${data.tid}/crossposts`, { cid }); }), + ...remove.map((cid) => { return api.del(`/topics/${data.tid}/crossposts`, { cid }); }), + ]; + + Promise.all(queries).then(async () => { + const statsEl = components.get('topic/stats'); + const { crossposts } = await api.get(`/topics/${data.tid}/crossposts`); + ajaxify.data.crossposts = crossposts; + const html = await app.parseAndTranslate('partials/topic/stats', ajaxify.data); + statsEl.html(html); + closeCrosspostModal(); + }).catch(alerts.error); + } + + function closeCrosspostModal() { + if (modal) { + modal.remove(); + modal = null; + } + } + + return Crosspost; +}); diff --git a/src/views/modals/crosspost-topic.tpl b/src/views/modals/crosspost-topic.tpl index a7ae3be3ea..bb95e8e329 100644 --- a/src/views/modals/crosspost-topic.tpl +++ b/src/views/modals/crosspost-topic.tpl @@ -4,7 +4,7 @@
- [[topic:crosspost-topic-instruction]] + [[topic:crossposts.instructions]]
[[topic:crossposts.listing]]
+ {{{ each crossposts }}} + {buildCategoryLabel(./category, "a", "border")} + {{{ end }}} + {{{ else }}} +[[topic:crossposts.none]]
+ {{{ end }}} +