diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..2b3ed3b
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,103 @@
+{
+ "env": {
+ "jasmine": true,
+ "node": true,
+ "mocha": true,
+ "browser": true,
+ "builtin": true
+ },
+ ecmaVersion: 7,
+ "globals":
+ {"Ember":true,
+ "jQuery":true,
+ "$":true,
+ "RSVP":true,
+ "Discourse":true,
+ "Em":true,
+ "PreloadStore":true,
+ "Handlebars":true,
+ "I18n":true,
+ "bootbox":true,
+ "module":true,
+ "moduleFor":true,
+ "moduleForComponent":true,
+ "Pretender":true,
+ "sandbox":true,
+ "controllerFor":true,
+ "test":true,
+ "ok":true,
+ "not":true,
+ "expect":true,
+ "equal":true,
+ "visit":true,
+ "andThen":true,
+ "click":true,
+ "currentPath":true,
+ "currentRouteName":true,
+ "currentURL":true,
+ "fillIn":true,
+ "keyEvent":true,
+ "triggerEvent":true,
+ "count":true,
+ "exists":true,
+ "visible":true,
+ "invisible":true,
+ "asyncRender":true,
+ "selectDropdown":true,
+ "asyncTestDiscourse":true,
+ "fixture":true,
+ "find":true,
+ "sinon":true,
+ "moment":true,
+ "start":true,
+ "_":true,
+ "alert":true,
+ "containsInstance":true,
+ "deepEqual":true,
+ "notEqual":true,
+ "define":true,
+ "require":true,
+ "requirejs":true,
+ "hasModule":true,
+ "Blob":true,
+ "File":true},
+ "rules": {
+ "block-scoped-var": 2,
+ "dot-notation": 0,
+ "eqeqeq": [
+ 2,
+ "allow-null"
+ ],
+ "guard-for-in": 2,
+ "no-bitwise": 2,
+ "no-caller": 2,
+ "no-cond-assign": 0,
+ "no-debugger": 2,
+ "no-empty": 0,
+ "no-eval": 2,
+ "no-extend-native": 2,
+ "no-extra-parens": 0,
+ "no-irregular-whitespace": 2,
+ "no-iterator": 2,
+ "no-loop-func": 2,
+ "no-multi-str": 2,
+ "no-new": 2,
+ "no-plusplus": 0,
+ "no-proto": 2,
+ "no-script-url": 2,
+ "no-sequences": 2,
+ "no-shadow": 2,
+ "no-undef": 2,
+ "no-unused-vars": 2,
+ "no-with": 2,
+ "no-this-before-super": 2,
+ "semi": 2,
+ "strict": 0,
+ "valid-typeof": 2,
+ "wrap-iife": [
+ 2,
+ "inside"
+ ]
+ },
+ "parser": "babel-eslint"
+}
diff --git a/assets/javascripts/discourse/initializers/extend-for-solved-button.js.es6 b/assets/javascripts/discourse/initializers/extend-for-solved-button.js.es6
index 03420f7..2700cf9 100644
--- a/assets/javascripts/discourse/initializers/extend-for-solved-button.js.es6
+++ b/assets/javascripts/discourse/initializers/extend-for-solved-button.js.es6
@@ -4,18 +4,165 @@ import { Button } from 'discourse/components/post-menu';
import Topic from 'discourse/models/topic';
import User from 'discourse/models/user';
import TopicStatus from 'discourse/views/topic-status';
-import computed from 'ember-addons/ember-computed-decorators';
import { popupAjaxError } from 'discourse/lib/ajax-error';
+import { withPluginApi } from 'discourse/lib/plugin-api';
+
+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);
+
+ Discourse.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.setProperties({
+ username: post.get('username'),
+ post_number: post.get('post_number')
+ });
+
+ Discourse.ajax("/solution/accept", {
+ type: 'POST',
+ data: { id: post.get('.id') }
+ }).catch(popupAjaxError);
+}
+
+// Code for older discourse installs for backwards compatibility
+function oldPluginCode() {
+ PostView.reopen({
+ classNameBindings: ['post.accepted_answer:accepted-answer']
+ });
+
+ 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: '' + I18n.t('solved.solution') + ''})
+ );
+ }
+
+ });
+
+ 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');
+
+ 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.user_id;
+ 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.attachWidgetAction('post', 'acceptAnswer', function() {
+ const post = this.model;
+ const current = post.get('topic.postStream.posts').filterProperty('accepted_answer');
+ acceptPost(post);
+
+ current.forEach(p => this.appEvents.trigger('post-stream:refresh', { id: p.id }));
+ });
+
+ api.attachWidgetAction('post', 'unacceptAnswer', function() {
+ unacceptPost(this.model);
+ });
+}
export default {
name: 'extend-for-solved-button',
- initialize: function() {
+ initialize() {
Topic.reopen({
// keeping this here cause there is complex localization
- acceptedAnswerHtml: function(){
+ acceptedAnswerHtml: function() {
const username = this.get('accepted_answer.username');
- var postNumber = this.get('accepted_answer.post_number');
+ const postNumber = this.get('accepted_answer.post_number');
if (!username || !postNumber) {
return "";
@@ -33,7 +180,7 @@ export default {
TopicStatus.reopen({
statuses: function(){
- var results = this._super();
+ const results = this._super();
if (this.topic.has_accepted_answer) {
results.push({
openTag: 'span',
@@ -46,90 +193,6 @@ export default {
}.property()
});
- PostView.reopen({
- classNameBindings: ['post.accepted_answer:accepted-answer']
- });
-
- 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 = 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: '' + I18n.t('solved.solution') + ''})
- );
- }
-
- });
-
- PostMenuComponent.reopen({
- acceptedChanged: function(){
- this.rerender();
- }.observes('post.accepted_answer'),
-
- clickUnacceptAnswer: function(){
- if (!this.get('post.can_unaccept_answer')) { return; }
-
- this.set('post.can_accept_answer', true);
- this.set('post.can_unaccept_answer', false);
- this.set('post.accepted_answer', false);
- this.set('post.topic.accepted_answer', undefined);
-
- Discourse.ajax("/solution/unaccept", {
- type: 'POST',
- data: {
- id: this.get('post.id')
- }
- }).catch(popupAjaxError);
- },
-
- clearAcceptedAnswer: function(){
- const posts = this.get('post.topic.postStream.posts');
- posts.forEach(function(post){
- if (post.get('post_number') > 1 ) {
- post.set('accepted_answer',false);
- post.set('can_accept_answer',true);
- post.set('can_unaccept_answer',false);
- }
- });
- },
-
- clickAcceptAnswer: function(){
-
- this.clearAcceptedAnswer();
-
- this.set('post.can_unaccept_answer', true);
- this.set('post.can_accept_answer', false);
- this.set('post.accepted_answer', true);
-
- this.set('post.topic.accepted_answer', {
- username: this.get('post.username'),
- post_number: this.get('post.post_number')
- });
-
- Discourse.ajax("/solution/accept", {
- type: 'POST',
- data: {
- id: this.get('post.id')
- }
- }).catch(popupAjaxError);
- }
- });
+ withPluginApi('0.1', initializeWithApi, { noApi: oldPluginCode });
}
};
diff --git a/plugin.rb b/plugin.rb
index 758555c..6adb14e 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -207,20 +207,21 @@ after_initialize do
topic = (topic_view && topic_view.topic) || object.topic
if topic
- scope.can_accept_answer?(topic) &&
- object.post_number > 1 && !accepted_answer
+ return scope.can_accept_answer?(topic) && object.post_number > 1 && !accepted_answer
end
+
+ false
end
def can_unaccept_answer
topic = (topic_view && topic_view.topic) || object.topic
if topic
- scope.can_accept_answer?(topic) && post_custom_fields["is_accepted_answer"]
+ return scope.can_accept_answer?(topic) && (post_custom_fields["is_accepted_answer"] == 'true')
end
end
def accepted_answer
- post_custom_fields["is_accepted_answer"]
+ post_custom_fields["is_accepted_answer"] == 'true'
end
end