UX: disable 'Hide results' button when poll is closed

This commit is contained in:
Régis Hanol 2015-09-16 13:01:08 +02:00
parent e211bf7d0b
commit cc75890cd4
5 changed files with 82 additions and 77 deletions

View File

@ -107,21 +107,21 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, {
// If it's the same topic as ours, build the URL from the topic object // If it's the same topic as ours, build the URL from the topic object
if (topic && topic.get('id') === topicId) { if (topic && topic.get('id') === topicId) {
navLink = "<a href='" + topic.urlForPostNumber(postNumber) + "' title='" + quoteTitle + "' class='back'></a>"; navLink = `<a href='${topic.urlForPostNumber(postNumber)}' title='${quoteTitle}' class='back'></a>`;
} else { } else {
// Made up slug should be replaced with canonical URL // Made up slug should be replaced with canonical URL
navLink = "<a href='" + Discourse.getURL("/t/via-quote/") + topicId + "/" + postNumber + "' title='" + quoteTitle + "' class='quote-other-topic'></a>"; navLink = `<a href='${Discourse.getURL("/t/via-quote/") + topicId + "/" + postNumber}' title='${quoteTitle}' class='quote-other-topic'></a>`;
} }
} else if (topic = this.get('controller.content')) { } else if (topic = this.get('controller.content')) {
// assume the same topic // assume the same topic
navLink = "<a href='" + topic.urlForPostNumber(postNumber) + "' title='" + quoteTitle + "' class='back'></a>"; navLink = `<a href='${topic.urlForPostNumber(postNumber)}' title='${quoteTitle}' class='back'></a>`;
} }
} }
// Only add the expand/contract control if it's not a full post // Only add the expand/contract control if it's not a full post
let expandContract = ""; let expandContract = "";
if (!$aside.data('full')) { if (!$aside.data('full')) {
expandContract = "<i class='fa fa-" + desc + "' title='" + I18n.t("post.expand_collapse") + "'></i>"; expandContract = `<i class='fa fa-${desc}' title='${I18n.t("post.expand_collapse")}'></i>`;
$('.title', $aside).css('cursor', 'pointer'); $('.title', $aside).css('cursor', 'pointer');
} }
$('.quote-controls', $aside).html(expandContract + navLink); $('.quote-controls', $aside).html(expandContract + navLink);
@ -129,20 +129,18 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, {
_toggleQuote($aside) { _toggleQuote($aside) {
if (this.get('expanding')) { return; } if (this.get('expanding')) { return; }
this.set('expanding', true); this.set('expanding', true);
$aside.data('expanded', !$aside.data('expanded')); $aside.data('expanded', !$aside.data('expanded'));
const self = this, const finished = () => this.set('expanding', false);
finished = function() {
self.set('expanding', false);
};
if ($aside.data('expanded')) { if ($aside.data('expanded')) {
this._updateQuoteElements($aside, 'chevron-up'); this._updateQuoteElements($aside, 'chevron-up');
// Show expanded quote // Show expanded quote
const $blockQuote = $('blockquote', $aside); const $blockQuote = $('blockquote', $aside);
$aside.data('original-contents',$blockQuote.html()); $aside.data('original-contents', $blockQuote.html());
const originalText = $blockQuote.text().trim(); const originalText = $blockQuote.text().trim();
$blockQuote.html(I18n.t("loading")); $blockQuote.html(I18n.t("loading"));
@ -154,7 +152,7 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, {
const postId = parseInt($aside.data('post'), 10); const postId = parseInt($aside.data('post'), 10);
topicId = parseInt(topicId, 10); topicId = parseInt(topicId, 10);
Discourse.ajax("/posts/by_number/" + topicId + "/" + postId).then(function (result) { Discourse.ajax(`/posts/by_number/${topicId}/${postId}`).then(result => {
const div = $("<div class='expanded-quote'></div>"); const div = $("<div class='expanded-quote'></div>");
div.html(result.cooked); div.html(result.cooked);
div.highlight(originalText, {caseSensitive: true, element: 'span', className: 'highlighted'}); div.highlight(originalText, {caseSensitive: true, element: 'span', className: 'highlighted'});

View File

@ -1,3 +1,5 @@
import computed from "ember-addons/ember-computed-decorators";
export default Ember.Controller.extend({ export default Ember.Controller.extend({
isMultiple: Ember.computed.equal("poll.type", "multiple"), isMultiple: Ember.computed.equal("poll.type", "multiple"),
isNumber: Ember.computed.equal("poll.type", "number"), isNumber: Ember.computed.equal("poll.type", "number"),
@ -11,12 +13,10 @@ export default Ember.Controller.extend({
showingResults: Em.computed.or("isClosed", "post.topic.closed", "post.topic.archived", "showResults"), showingResults: Em.computed.or("isClosed", "post.topic.closed", "post.topic.archived", "showResults"),
showResultsDisabled: Em.computed.equal("poll.voters", 0), showResultsDisabled: Em.computed.equal("poll.voters", 0),
hideResultsDisabled: Em.computed.alias("isClosed"), hideResultsDisabled: Em.computed.or("isClosed", "post.topic.closed", "post.topic.archived"),
poll: function() {
const poll = this.get("model"),
vote = this.get("vote");
@computed("model", "vote")
poll(poll, vote) {
if (poll) { if (poll) {
const options = _.map(poll.get("options"), o => Em.Object.create(o)); const options = _.map(poll.get("options"), o => Em.Object.create(o));
@ -28,44 +28,46 @@ export default Ember.Controller.extend({
} }
return poll; return poll;
}.property("model"), },
selectedOptions: function() { @computed("poll.options.@each.selected")
selectedOptions() {
return _.map(this.get("poll.options").filterBy("selected"), o => o.get("id")); return _.map(this.get("poll.options").filterBy("selected"), o => o.get("id"));
}.property("poll.options.@each.selected"), },
min: function() { @computed("poll.min")
let min = parseInt(this.get("poll.min"), 10); min(min) {
min = parseInt(min, 10);
if (isNaN(min) || min < 1) { min = 1; } if (isNaN(min) || min < 1) { min = 1; }
return min; return min;
}.property("poll.min"), },
max: function() { @computed("poll.max", "poll.options.length")
let options = this.get("poll.options.length"), max(max, options) {
max = parseInt(this.get("poll.max"), 10); max = parseInt(max, 10);
if (isNaN(max) || max > options) { max = options; } if (isNaN(max) || max > options) { max = options; }
return max; return max;
}.property("poll.max", "poll.options.length"), },
votersText: function() { @computed("poll.voters")
return I18n.t("poll.voters", { count: this.get("poll.voters") }); votersText(count) {
}.property("poll.voters"), return I18n.t("poll.voters", { count });
},
totalVotes: function() { @computed("poll.options.@each.votes")
totalVotes() {
return _.reduce(this.get("poll.options"), function(total, o) { return _.reduce(this.get("poll.options"), function(total, o) {
return total + parseInt(o.get("votes"), 10); return total + parseInt(o.get("votes"), 10);
}, 0); }, 0);
}.property("poll.options.@each.votes"), },
totalVotesText: function() { @computed("totalVotes")
return I18n.t("poll.total_votes", { count: this.get("totalVotes") }); totalVotesText(count) {
}.property("totalVotes"), return I18n.t("poll.total_votes", { count });
},
multipleHelpText: function() {
const options = this.get("poll.options.length"),
min = this.get("min"),
max = this.get("max");
@computed("min", "max", "poll.options.length")
multipleHelpText(min, max, options) {
if (max > 0) { if (max > 0) {
if (min === max) { if (min === max) {
if (min > 1) { if (min > 1) {
@ -73,7 +75,7 @@ export default Ember.Controller.extend({
} }
} else if (min > 1) { } else if (min > 1) {
if (max < options) { if (max < options) {
return I18n.t("poll.multiple.help.between_min_and_max_options", { min: min, max: max }); return I18n.t("poll.multiple.help.between_min_and_max_options", { min, max });
} else { } else {
return I18n.t("poll.multiple.help.at_least_min_options", { count: min }); return I18n.t("poll.multiple.help.at_least_min_options", { count: min });
} }
@ -81,33 +83,31 @@ export default Ember.Controller.extend({
return I18n.t("poll.multiple.help.up_to_max_options", { count: max }); return I18n.t("poll.multiple.help.up_to_max_options", { count: max });
} }
} }
}.property("min", "max", "poll.options.length"), },
canCastVotes: function() { @computed("isClosed", "showResults", "loading", "isMultiple", "selectedOptions.length", "min", "max")
if (this.get("isClosed") || this.get("showingResults") || this.get("loading")) { canCastVotes(isClosed, showResults, loading, isMultiple, selectedOptionCount, min, max) {
if (isClosed || showResults || loading) {
return false; return false;
} }
const selectedOptionCount = this.get("selectedOptions.length"); if (isMultiple) {
return selectedOptionCount >= min && selectedOptionCount <= max;
if (this.get("isMultiple")) {
return selectedOptionCount >= this.get("min") && selectedOptionCount <= this.get("max");
} else { } else {
return selectedOptionCount > 0; return selectedOptionCount > 0;
} }
}.property("isClosed", "showingResults", "loading", },
"selectedOptions.length",
"isMultiple", "min", "max"),
castVotesDisabled: Em.computed.not("canCastVotes"), castVotesDisabled: Em.computed.not("canCastVotes"),
canToggleStatus: function() { @computed("loading", "post.user_id", "post.topic.closed", "post.topic.archived")
canToggleStatus(loading, userId, topicClosed, topicArchived) {
return this.currentUser && return this.currentUser &&
(this.currentUser.get("id") === this.get("post.user_id") || this.currentUser.get("staff")) && (this.currentUser.get("id") === userId || this.currentUser.get("staff")) &&
!this.get("loading") && !loading &&
!this.get("post.topic.closed") && !topicClosed &&
!this.get("post.topic.archived"); !topicArchived;
}.property("loading", "post.user_id", "post.topic.{closed,archived}"), },
actions: { actions: {
@ -130,8 +130,6 @@ export default Ember.Controller.extend({
if (!this.get("canCastVotes")) { return; } if (!this.get("canCastVotes")) { return; }
if (!this.currentUser) { return this.send("showLogin"); } if (!this.currentUser) { return this.send("showLogin"); }
const self = this;
this.set("loading", true); this.set("loading", true);
Discourse.ajax("/polls/vote", { Discourse.ajax("/polls/vote", {
@ -141,13 +139,13 @@ export default Ember.Controller.extend({
poll_name: this.get("poll.name"), poll_name: this.get("poll.name"),
options: this.get("selectedOptions"), options: this.get("selectedOptions"),
} }
}).then(function(results) { }).then(results => {
self.setProperties({ vote: results.vote, showResults: true }); this.setProperties({ vote: results.vote, showResults: true });
self.set("model", Em.Object.create(results.poll)); this.set("model", Em.Object.create(results.poll));
}).catch(function() { }).catch(() => {
bootbox.alert(I18n.t("poll.error_while_casting_votes")); bootbox.alert(I18n.t("poll.error_while_casting_votes"));
}).finally(function() { }).finally(() => {
self.set("loading", false); this.set("loading", false);
}); });
}, },
@ -176,11 +174,11 @@ export default Ember.Controller.extend({
poll_name: self.get("poll.name"), poll_name: self.get("poll.name"),
status: self.get("isClosed") ? "open" : "closed", status: self.get("isClosed") ? "open" : "closed",
} }
}).then(function(results) { }).then(results => {
self.set("model", Em.Object.create(results.poll)); self.set("model", Em.Object.create(results.poll));
}).catch(function() { }).catch(() => {
bootbox.alert(I18n.t("poll.error_while_toggling_status")); bootbox.alert(I18n.t("poll.error_while_toggling_status"));
}).finally(function() { }).finally(() => {
self.set("loading", false); self.set("loading", false);
}); });
} }

View File

@ -34,7 +34,9 @@
<div class="poll-buttons"> <div class="poll-buttons">
{{#if isMultiple}} {{#if isMultiple}}
{{d-button class="cast-votes" title="poll.cast-votes.title" label="poll.cast-votes.label" disabled=castVotesDisabled action="castVotes"}} {{#unless hideResultsDisabled}}
{{d-button class="cast-votes" title="poll.cast-votes.title" label="poll.cast-votes.label" disabled=castVotesDisabled action="castVotes"}}
{{/unless}}
{{/if}} {{/if}}
{{#if showingResults}} {{#if showingResults}}

View File

@ -1,4 +1,5 @@
import PostView from "discourse/views/post"; import PostView from "discourse/views/post";
import { on } from "ember-addons/ember-computed-decorators";
function createPollView(container, post, poll, vote) { function createPollView(container, post, poll, vote) {
const controller = container.lookup("controller:poll", { singleton: false }), const controller = container.lookup("controller:poll", { singleton: false }),
@ -22,12 +23,14 @@ export default {
messageBus.subscribe("/polls", data => { messageBus.subscribe("/polls", data => {
const post = container.lookup("controller:topic").get('model.postStream').findLoadedPost(data.post_id); const post = container.lookup("controller:topic").get('model.postStream').findLoadedPost(data.post_id);
// HACK to trigger the "postViewUpdated" event // HACK to trigger the "postViewUpdated" event
Em.run.next(_ => post.set("cooked", post.get("cooked") + " ")); Em.run.next(() => post.set("cooked", post.get("cooked") + " "));
}); });
// overwrite polls // overwrite polls
PostView.reopen({ PostView.reopen({
_createPollViews: function($post) {
@on("postViewInserted", "postViewUpdated")
_createPollViews($post) {
const post = this.get("post"), const post = this.get("post"),
polls = post.get("polls"), polls = post.get("polls"),
votes = post.get("polls_votes") || {}; votes = post.get("polls_votes") || {};
@ -48,11 +51,11 @@ export default {
pollView = createPollView(container, post, polls[pollName], votes[pollName]); pollView = createPollView(container, post, polls[pollName], votes[pollName]);
$poll.replaceWith($div); $poll.replaceWith($div);
Em.run.next(_ => pollView.renderer.replaceIn(pollView, $div[0])); Em.run.next(() => pollView.renderer.replaceIn(pollView, $div[0]));
pollViews[pollName] = pollView; pollViews[pollName] = pollView;
}); });
messageBus.subscribe("/polls/" + this.get("post.id"), results => { messageBus.subscribe(`/polls/${this.get("post.id")}`, results => {
if (results && results.polls) { if (results && results.polls) {
_.forEach(results.polls, poll => { _.forEach(results.polls, poll => {
if (pollViews[poll.name]) { if (pollViews[poll.name]) {
@ -63,15 +66,16 @@ export default {
}); });
this.set("pollViews", pollViews); this.set("pollViews", pollViews);
}.on("postViewInserted", "postViewUpdated"), },
_cleanUpPollViews: function() { @on("willClearRender")
messageBus.unsubscribe("/polls/" + this.get("post.id")); _cleanUpPollViews() {
messageBus.unsubscribe(`/polls/${this.get("post.id")}`);
if (this.get("pollViews")) { if (this.get("pollViews")) {
_.forEach(this.get("pollViews"), v => v.destroy()); _.forEach(this.get("pollViews"), v => v.destroy());
} }
}.on("willClearRender") }
}); });
} }
}; };

View File

@ -1,3 +1,5 @@
import { on } from "ember-addons/ember-computed-decorators";
export default Em.View.extend({ export default Em.View.extend({
templateName: "poll", templateName: "poll",
classNames: ["poll"], classNames: ["poll"],
@ -9,8 +11,9 @@ export default Em.View.extend({
"data-poll-name": Em.computed.alias("poll.name"), "data-poll-name": Em.computed.alias("poll.name"),
"data-poll-status": Em.computed.alias("poll.status"), "data-poll-status": Em.computed.alias("poll.status"),
_fixPollContainerHeight: function() { @on("didInsertElement")
_fixPollContainerHeight() {
const pollContainer = this.$(".poll-container"); const pollContainer = this.$(".poll-container");
pollContainer.height(pollContainer.height()); pollContainer.height(pollContainer.height());
}.on("didInsertElement") }
}); });