262 lines
7.8 KiB
JavaScript
262 lines
7.8 KiB
JavaScript
import Topic from 'discourse/models/topic';
|
|
import User from 'discourse/models/user';
|
|
import TopicStatus from 'discourse/raw-views/topic-status';
|
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
|
import { withPluginApi } from 'discourse/lib/plugin-api';
|
|
import { ajax } from 'discourse/lib/ajax';
|
|
import PostCooked from 'discourse/widgets/post-cooked'
|
|
|
|
function clearAccepted(topic) {
|
|
const posts = topic.get('postStream.posts');
|
|
posts.forEach(post => {
|
|
if (post.get('post_number') > 1 ) {
|
|
post.set('accepted_answer',false);
|
|
post.set('can_accept_answer',true);
|
|
post.set('can_unaccept_answer',false);
|
|
}
|
|
});
|
|
}
|
|
|
|
function unacceptPost(post) {
|
|
if (!post.get('can_unaccept_answer')) { return; }
|
|
const topic = post.topic;
|
|
|
|
post.setProperties({
|
|
can_accept_answer: true,
|
|
can_unaccept_answer: false,
|
|
accepted_answer: false
|
|
});
|
|
topic.set('accepted_answer', undefined);
|
|
|
|
ajax("/solution/unaccept", {
|
|
type: 'POST',
|
|
data: { id: post.get('id') }
|
|
}).catch(popupAjaxError);
|
|
}
|
|
|
|
function acceptPost(post) {
|
|
const topic = post.topic;
|
|
|
|
clearAccepted(topic);
|
|
|
|
post.setProperties({
|
|
can_unaccept_answer: true,
|
|
can_accept_answer: false,
|
|
accepted_answer: true
|
|
});
|
|
|
|
topic.set('accepted_answer', {
|
|
username: post.get('username'),
|
|
post_number: post.get('post_number'),
|
|
excerpt: post.get('cooked'),
|
|
});
|
|
|
|
ajax("/solution/accept", {
|
|
type: 'POST',
|
|
data: { id: post.get('id') }
|
|
}).catch(popupAjaxError);
|
|
}
|
|
|
|
// Code for older discourse installs for backwards compatibility
|
|
function oldPluginCode() {
|
|
const PostView = require('discourse/views/post').default;
|
|
PostView.reopen({
|
|
classNameBindings: ['post.accepted_answer:accepted-answer']
|
|
});
|
|
|
|
const module = require( 'discourse/components/post-menu');
|
|
const PostMenuComponent = module.default;
|
|
const Button = module.Button;
|
|
PostMenuComponent.registerButton(function(visibleButtons){
|
|
var position = 0;
|
|
|
|
var canAccept = this.get('post.can_accept_answer');
|
|
var canUnaccept = this.get('post.can_unaccept_answer');
|
|
var accepted = this.get('post.accepted_answer');
|
|
var isOp = Discourse.User.currentProp("id") === this.get('post.topic.user_id');
|
|
|
|
if (!accepted && canAccept && !isOp) {
|
|
// first hidden position
|
|
if (this.get('collapsed')) { return; }
|
|
position = visibleButtons.length - 2;
|
|
}
|
|
if (canAccept) {
|
|
visibleButtons.splice(position,0,new Button('acceptAnswer', 'solved.accept_answer', 'check-square-o', {className: 'unaccepted'}));
|
|
}
|
|
if (canUnaccept || accepted) {
|
|
var locale = canUnaccept ? 'solved.unaccept_answer' : 'solved.accepted_answer';
|
|
visibleButtons.splice(position,0,new Button(
|
|
'unacceptAnswer',
|
|
locale,
|
|
'check-square',
|
|
{className: 'accepted fade-out', prefixHTML: '<span class="accepted-text">' + I18n.t('solved.solution') + '</span>'})
|
|
);
|
|
}
|
|
|
|
});
|
|
|
|
PostMenuComponent.reopen({
|
|
acceptedChanged: function() {
|
|
this.rerender();
|
|
}.observes('post.accepted_answer'),
|
|
|
|
clickUnacceptAnswer() {
|
|
unacceptPost(this.get('post'));
|
|
},
|
|
|
|
clickAcceptAnswer() {
|
|
acceptPost(this.get('post'));
|
|
}
|
|
});
|
|
}
|
|
|
|
function initializeWithApi(api) {
|
|
const currentUser = api.getCurrentUser();
|
|
|
|
api.includePostAttributes('can_accept_answer', 'can_unaccept_answer', 'accepted_answer');
|
|
|
|
if (api.addDiscoveryQueryParam) {
|
|
api.addDiscoveryQueryParam('solved', {replace: true, refreshModel: true});
|
|
}
|
|
|
|
api.addPostMenuButton('solved', attrs => {
|
|
const canAccept = attrs.can_accept_answer;
|
|
const canUnaccept = attrs.can_unaccept_answer;
|
|
const accepted = attrs.accepted_answer;
|
|
const isOp = currentUser && currentUser.id === attrs.topicCreatedById;
|
|
const position = (!accepted && canAccept && !isOp) ? 'second-last-hidden' : 'first';
|
|
|
|
if (canAccept) {
|
|
return {
|
|
action: 'acceptAnswer',
|
|
icon: 'check-square-o',
|
|
className: 'unaccepted',
|
|
title: 'solved.accept_answer',
|
|
position
|
|
};
|
|
} else if (canUnaccept || accepted) {
|
|
const title = canUnaccept ? 'solved.unaccept_answer' : 'solved.accepted_answer';
|
|
return {
|
|
action: 'unacceptAnswer',
|
|
icon: 'check-square',
|
|
title,
|
|
className: 'accepted fade-out',
|
|
position,
|
|
beforeButton(h) {
|
|
return h('span.accepted-text', I18n.t('solved.solution'));
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
api.decorateWidget('post-contents:after-cooked', dec => {
|
|
if (dec.attrs.post_number === 1) {
|
|
const postModel = dec.getModel();
|
|
if (postModel) {
|
|
const topic = postModel.get('topic');
|
|
if (topic.get('accepted_answer')) {
|
|
|
|
var rawhtml = `
|
|
<aside class='quote' data-post="${topic.get('accepted_answer').post_number}" data-topic="${topic.get('id')}">
|
|
<div class='title'>
|
|
${topic.get('acceptedAnswerHtml')} <div class="quote-controls"><\/div>
|
|
</div>
|
|
<blockquote>
|
|
${topic.get('accepted_answer').excerpt}
|
|
</blockquote>
|
|
</aside>`
|
|
|
|
var cooked = new PostCooked({cooked:rawhtml});
|
|
|
|
var html = cooked.init();
|
|
|
|
return dec.rawHtml(html);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
api.attachWidgetAction('post', 'acceptAnswer', function() {
|
|
const post = this.model;
|
|
const current = post.get('topic.postStream.posts').filter(p => {
|
|
return p.get('post_number') === 1 || p.get('accepted_answer');
|
|
});
|
|
acceptPost(post);
|
|
|
|
current.forEach(p => this.appEvents.trigger('post-stream:refresh', { id: p.id }));
|
|
});
|
|
|
|
api.attachWidgetAction('post', 'unacceptAnswer', function() {
|
|
const post = this.model;
|
|
const op = post.get('topic.postStream.posts').find(p => p.get('post_number') === 1);
|
|
unacceptPost(post);
|
|
this.appEvents.trigger('post-stream:refresh', { id: op.get('id') });
|
|
});
|
|
|
|
if (api.registerConnectorClass) {
|
|
api.registerConnectorClass('user-activity-bottom', 'solved-list', {
|
|
shouldRender(args, component) {
|
|
return component.siteSettings.solved_enabled;
|
|
},
|
|
});
|
|
api.registerConnectorClass('user-summary-stat', 'solved-count', {
|
|
shouldRender(args, component) {
|
|
return component.siteSettings.solved_enabled && args.model.solved_count > 0;
|
|
},
|
|
setupComponent() {
|
|
this.set('classNames', ['linked-stat']);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
export default {
|
|
name: 'extend-for-solved-button',
|
|
initialize() {
|
|
|
|
Topic.reopen({
|
|
// keeping this here cause there is complex localization
|
|
acceptedAnswerHtml: function() {
|
|
const username = this.get('accepted_answer.username');
|
|
const postNumber = this.get('accepted_answer.post_number');
|
|
|
|
if (!username || !postNumber) {
|
|
return "";
|
|
}
|
|
|
|
return I18n.t("solved.accepted_html", {
|
|
username_lower: username.toLowerCase(),
|
|
username,
|
|
post_path: this.get('url') + "/" + postNumber,
|
|
post_number: postNumber,
|
|
user_path: User.create({username: username}).get('path')
|
|
});
|
|
}.property('accepted_answer', 'id')
|
|
});
|
|
|
|
TopicStatus.reopen({
|
|
statuses: function(){
|
|
const results = this._super();
|
|
if (this.topic.has_accepted_answer) {
|
|
results.push({
|
|
openTag: 'span',
|
|
closeTag: 'span',
|
|
title: I18n.t('solved.has_accepted_answer'),
|
|
icon: 'check-square-o'
|
|
});
|
|
}else if(this.topic.can_have_answer && this.siteSettings.solved_enabled && this.siteSettings.empty_box_on_unsolved){
|
|
results.push({
|
|
openTag: 'span',
|
|
closeTag: 'span',
|
|
title: I18n.t('solved.has_no_accepted_answer'),
|
|
icon: 'square-o'
|
|
});
|
|
}
|
|
return results;
|
|
}.property()
|
|
});
|
|
|
|
withPluginApi('0.1', initializeWithApi, { noApi: oldPluginCode });
|
|
}
|
|
};
|