DEV: Remove widget wrapper from poll plugin (#28666)
- Uses `helper.renderGlimmer` with GJS to render the `<Poll` component without any widgets - Moves some logic into component, so that only `@post`, `@poll` and `@titleHTML` need to be passed into the component (no more 'attrs') - Updates `modifyClass` calls to modern syntax - Replaces observer in `Post` model with a native setter & tracked property - Replaced Poll EmberObject instances with TrackedObject - Updated component tests with new arguments - Updated some tests to qunit-dom - Fixed up core `repliesBelow` and `repliesAbove` logic to create post models properly. Previously it was passing 'transformed' versions of posts into the model, which doesn't make sense.
This commit is contained in:
parent
a2f625a0ef
commit
e6edd52047
|
@ -618,16 +618,8 @@ createWidget("post-contents", {
|
||||||
this.state.repliesBelow = posts.map((p) => {
|
this.state.repliesBelow = posts.map((p) => {
|
||||||
let result = transformWithCallbacks(p);
|
let result = transformWithCallbacks(p);
|
||||||
|
|
||||||
// these would conflict with computed properties with identical names
|
|
||||||
// in the post model if we kept them.
|
|
||||||
delete result.new_user;
|
|
||||||
delete result.deleted;
|
|
||||||
delete result.shareUrl;
|
|
||||||
delete result.firstPost;
|
|
||||||
delete result.usernameUrl;
|
|
||||||
|
|
||||||
result.customShare = `${topicUrl}/${p.post_number}`;
|
result.customShare = `${topicUrl}/${p.post_number}`;
|
||||||
result.asPost = this.store.createRecord("post", result);
|
result.asPost = this.store.createRecord("post", p);
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -882,18 +874,8 @@ createWidget("post-article", {
|
||||||
this.state.repliesAbove = posts.map((p) => {
|
this.state.repliesAbove = posts.map((p) => {
|
||||||
let result = transformWithCallbacks(p);
|
let result = transformWithCallbacks(p);
|
||||||
|
|
||||||
// We don't want to overwrite CPs - we are doing something a bit weird
|
|
||||||
// here by creating a post object from a transformed post. They aren't
|
|
||||||
// 100% the same.
|
|
||||||
delete result.new_user;
|
|
||||||
delete result.deleted;
|
|
||||||
delete result.shareUrl;
|
|
||||||
delete result.firstPost;
|
|
||||||
delete result.usernameUrl;
|
|
||||||
delete result.topicNotificationLevel;
|
|
||||||
|
|
||||||
result.customShare = `${topicUrl}/${p.post_number}`;
|
result.customShare = `${topicUrl}/${p.post_number}`;
|
||||||
result.asPost = this.store.createRecord("post", result);
|
result.asPost = this.store.createRecord("post", p);
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,6 +11,7 @@ import I18n from "discourse-i18n";
|
||||||
|
|
||||||
export default class PollBreakdownModal extends Component {
|
export default class PollBreakdownModal extends Component {
|
||||||
@service dialog;
|
@service dialog;
|
||||||
|
@service siteSettings;
|
||||||
|
|
||||||
model = null;
|
model = null;
|
||||||
charts = null;
|
charts = null;
|
||||||
|
@ -19,7 +20,7 @@ export default class PollBreakdownModal extends Component {
|
||||||
displayMode = "percentage";
|
displayMode = "percentage";
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.set("groupedBy", this.model.groupableUserFields[0]);
|
this.set("groupedBy", this.groupableUserFields[0]?.id);
|
||||||
loadScript("/javascripts/Chart.min.js")
|
loadScript("/javascripts/Chart.min.js")
|
||||||
.then(() => loadScript("/javascripts/chartjs-plugin-datalabels.min.js"))
|
.then(() => loadScript("/javascripts/chartjs-plugin-datalabels.min.js"))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
@ -33,17 +34,19 @@ export default class PollBreakdownModal extends Component {
|
||||||
return pollTitle ? htmlSafe(pollTitle) : topicTitle;
|
return pollTitle ? htmlSafe(pollTitle) : topicTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@discourseComputed("model.groupableUserFields")
|
get groupableUserFields() {
|
||||||
groupableUserFields(fields) {
|
return this.siteSettings.poll_groupable_user_fields
|
||||||
return fields.map((field) => {
|
.split("|")
|
||||||
const transformed = field.split("_").filter(Boolean);
|
.filter(Boolean)
|
||||||
|
.map((field) => {
|
||||||
|
const transformed = field.split("_").filter(Boolean);
|
||||||
|
|
||||||
if (transformed.length > 1) {
|
if (transformed.length > 1) {
|
||||||
transformed[0] = classify(transformed[0]);
|
transformed[0] = classify(transformed[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { id: field, label: transformed.join(" ") };
|
return { id: field, label: transformed.join(" ") };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@discourseComputed("model.poll.options")
|
@discourseComputed("model.poll.options")
|
||||||
|
|
|
@ -42,11 +42,10 @@ export default class PollComponent extends Component {
|
||||||
@service dialog;
|
@service dialog;
|
||||||
@service modal;
|
@service modal;
|
||||||
|
|
||||||
@tracked vote = this.args.attrs.vote || [];
|
@tracked vote = this.args.post.polls_votes?.[this.args.poll.name] || [];
|
||||||
@tracked poll = this.args.attrs.poll;
|
|
||||||
@tracked preloadedVoters = this.defaultPreloadedVoters();
|
@tracked preloadedVoters = this.defaultPreloadedVoters();
|
||||||
@tracked voterListExpanded = false;
|
@tracked voterListExpanded = false;
|
||||||
@tracked hasSavedVote = this.args.attrs.hasSavedVote;
|
@tracked hasSavedVote = this.vote.length > 0;
|
||||||
|
|
||||||
@tracked
|
@tracked
|
||||||
showResults =
|
showResults =
|
||||||
|
@ -123,13 +122,17 @@ export default class PollComponent extends Component {
|
||||||
this.vote = [...this.vote];
|
this.vote = [...this.vote];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
get poll() {
|
||||||
|
return this.args.poll;
|
||||||
|
}
|
||||||
|
|
||||||
defaultPreloadedVoters() {
|
defaultPreloadedVoters() {
|
||||||
const preloadedVoters = {};
|
const preloadedVoters = {};
|
||||||
|
|
||||||
if (this.poll.public && this.args.preloadedVoters) {
|
if (this.poll.public && this.poll.preloaded_voters) {
|
||||||
Object.keys(this.args.preloadedVoters).forEach((key) => {
|
Object.keys(this.poll.preloaded_voters).forEach((key) => {
|
||||||
preloadedVoters[key] = {
|
preloadedVoters[key] = {
|
||||||
voters: this.args.preloadedVoters[key],
|
voters: this.poll.preloaded_voters[key],
|
||||||
loading: false,
|
loading: false,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -148,15 +151,17 @@ export default class PollComponent extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
get id() {
|
get id() {
|
||||||
return this.args.attrs.id;
|
return `${this.args.poll.name}-${this.args.post.id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
get post() {
|
get post() {
|
||||||
return this.args.attrs.post;
|
return this.args.post;
|
||||||
}
|
}
|
||||||
|
|
||||||
get groupableUserFields() {
|
get groupableUserFields() {
|
||||||
return this.args.attrs.groupableUserFields;
|
return this.siteSettings.poll_groupable_user_fields
|
||||||
|
.split("|")
|
||||||
|
.filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
get isStaff() {
|
get isStaff() {
|
||||||
|
@ -164,7 +169,7 @@ export default class PollComponent extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
get titleHTML() {
|
get titleHTML() {
|
||||||
return htmlSafe(this.args.attrs.titleHTML);
|
return htmlSafe(this.args.titleHTML);
|
||||||
}
|
}
|
||||||
|
|
||||||
get topicArchived() {
|
get topicArchived() {
|
||||||
|
@ -192,7 +197,7 @@ export default class PollComponent extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
get status() {
|
get status() {
|
||||||
return this.poll.get("status");
|
return this.poll.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -206,7 +211,7 @@ export default class PollComponent extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const poll = await ajax("/polls/vote", {
|
const { poll } = await ajax("/polls/vote", {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
data: {
|
data: {
|
||||||
post_id: this.post.id,
|
post_id: this.post.id,
|
||||||
|
@ -216,7 +221,8 @@ export default class PollComponent extends Component {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.hasSavedVote = true;
|
this.hasSavedVote = true;
|
||||||
this.poll.setProperties(poll);
|
Object.assign(this.poll, poll);
|
||||||
|
|
||||||
this.appEvents.trigger("poll:voted", poll, this.post, this.vote);
|
this.appEvents.trigger("poll:voted", poll, this.post, this.vote);
|
||||||
|
|
||||||
if (this.poll.results !== ON_CLOSE) {
|
if (this.poll.results !== ON_CLOSE) {
|
||||||
|
@ -243,7 +249,7 @@ export default class PollComponent extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
get options() {
|
get options() {
|
||||||
let enrichedOptions = this.poll.get("options");
|
let enrichedOptions = this.poll.options;
|
||||||
|
|
||||||
if (this.isRankedChoice) {
|
if (this.isRankedChoice) {
|
||||||
enrichedOptions.forEach((candidate) => {
|
enrichedOptions.forEach((candidate) => {
|
||||||
|
@ -262,11 +268,11 @@ export default class PollComponent extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
get voters() {
|
get voters() {
|
||||||
return this.poll.get("voters");
|
return this.poll.voters;
|
||||||
}
|
}
|
||||||
|
|
||||||
get rankedChoiceOutcome() {
|
get rankedChoiceOutcome() {
|
||||||
return this.poll.get("ranked_choice_outcome") || [];
|
return this.poll.ranked_choice_outcome || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
get min() {
|
get min() {
|
||||||
|
@ -574,7 +580,7 @@ export default class PollComponent extends Component {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.poll.set("status", status);
|
this.poll.status = status;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.poll.results === ON_CLOSE ||
|
this.poll.results === ON_CLOSE ||
|
||||||
|
@ -606,7 +612,10 @@ export default class PollComponent extends Component {
|
||||||
@action
|
@action
|
||||||
showBreakdown() {
|
showBreakdown() {
|
||||||
this.modal.show(PollBreakdownModal, {
|
this.modal.show(PollBreakdownModal, {
|
||||||
model: this.args.attrs,
|
model: {
|
||||||
|
poll: this.poll,
|
||||||
|
post: this.post,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -660,121 +669,129 @@ export default class PollComponent extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div class="poll">
|
||||||
{{didUpdate this.updatedVoters @preloadedVoters}}
|
<div
|
||||||
class="poll-container"
|
{{didUpdate this.updatedVoters this.poll.preloaded_voters}}
|
||||||
>
|
class="poll-container"
|
||||||
{{this.titleHTML}}
|
>
|
||||||
{{#if this.notInVotingGroup}}
|
{{this.titleHTML}}
|
||||||
<div class="alert alert-danger">{{this.pollGroups}}</div>
|
{{#if this.notInVotingGroup}}
|
||||||
{{/if}}
|
<div class="alert alert-danger">{{this.pollGroups}}</div>
|
||||||
{{#if this.showResults}}
|
{{/if}}
|
||||||
<div class={{this.resultsWidgetTypeClass}}>
|
{{#if this.showResults}}
|
||||||
{{#if this.isNumber}}
|
<div class={{this.resultsWidgetTypeClass}}>
|
||||||
<span>{{this.averageRating}}</span>
|
{{#if this.isNumber}}
|
||||||
{{else}}
|
<span>{{this.averageRating}}</span>
|
||||||
{{#if this.resultsPie}}
|
|
||||||
<PollResultsPie @id={{this.id}} @options={{this.options}} />
|
|
||||||
{{else}}
|
{{else}}
|
||||||
<PollResultsTabs
|
{{#if this.resultsPie}}
|
||||||
@options={{this.options}}
|
<PollResultsPie @id={{this.id}} @options={{this.options}} />
|
||||||
@pollName={{this.poll.name}}
|
{{else}}
|
||||||
@pollType={{this.poll.type}}
|
<PollResultsTabs
|
||||||
@isRankedChoice={{this.isRankedChoice}}
|
@options={{this.options}}
|
||||||
@isPublic={{this.poll.public}}
|
@pollName={{this.poll.name}}
|
||||||
@postId={{this.post.id}}
|
@pollType={{this.poll.type}}
|
||||||
@vote={{this.vote}}
|
@isRankedChoice={{this.isRankedChoice}}
|
||||||
@voters={{this.preloadedVoters}}
|
@isPublic={{this.poll.public}}
|
||||||
@votersCount={{this.poll.voters}}
|
@postId={{this.post.id}}
|
||||||
@fetchVoters={{this.fetchVoters}}
|
@vote={{this.vote}}
|
||||||
@rankedChoiceOutcome={{this.rankedChoiceOutcome}}
|
@voters={{this.preloadedVoters}}
|
||||||
@showTally={{this.showTally}}
|
@votersCount={{this.poll.voters}}
|
||||||
/>
|
@fetchVoters={{this.fetchVoters}}
|
||||||
|
@rankedChoiceOutcome={{this.rankedChoiceOutcome}}
|
||||||
|
@showTally={{this.showTally}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
</div>
|
||||||
</div>
|
{{else}}
|
||||||
{{else}}
|
<PollOptions
|
||||||
<PollOptions
|
@isCheckbox={{this.isCheckbox}}
|
||||||
@isCheckbox={{this.isCheckbox}}
|
@isRankedChoice={{this.isRankedChoice}}
|
||||||
@isRankedChoice={{this.isRankedChoice}}
|
@options={{this.options}}
|
||||||
@options={{this.options}}
|
@votes={{this.vote}}
|
||||||
@votes={{this.vote}}
|
@sendOptionSelect={{this.toggleOption}}
|
||||||
@sendOptionSelect={{this.toggleOption}}
|
/>
|
||||||
/>
|
{{/if}}
|
||||||
{{/if}}
|
</div>
|
||||||
</div>
|
<PollInfo
|
||||||
<PollInfo
|
@options={{this.options}}
|
||||||
@options={{this.options}}
|
@min={{this.min}}
|
||||||
@min={{this.min}}
|
@max={{this.max}}
|
||||||
@max={{this.max}}
|
@isMultiple={{this.isMultiple}}
|
||||||
@isMultiple={{this.isMultiple}}
|
@close={{this.close}}
|
||||||
@close={{this.close}}
|
|
||||||
@closed={{this.closed}}
|
|
||||||
@results={{this.poll.results}}
|
|
||||||
@showResults={{this.showResults}}
|
|
||||||
@postUserId={{this.poll.post.user_id}}
|
|
||||||
@isPublic={{this.poll.public}}
|
|
||||||
@hasVoted={{this.hasVoted}}
|
|
||||||
@voters={{this.voters}}
|
|
||||||
/>
|
|
||||||
<div class="poll-buttons">
|
|
||||||
{{#if this.showCastVotesButton}}
|
|
||||||
<button
|
|
||||||
class={{this.castVotesButtonClass}}
|
|
||||||
title="poll.cast-votes.title"
|
|
||||||
disabled={{this.castVotesDisabled}}
|
|
||||||
{{on "click" this.castVotes}}
|
|
||||||
>
|
|
||||||
{{icon this.castVotesButtonIcon}}
|
|
||||||
<span class="d-button-label">{{i18n "poll.cast-votes.label"}}</span>
|
|
||||||
</button>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.showHideResultsButton}}
|
|
||||||
<button
|
|
||||||
class="btn btn-default toggle-results"
|
|
||||||
title="poll.hide-results.title"
|
|
||||||
{{on "click" this.toggleResults}}
|
|
||||||
>
|
|
||||||
{{icon "chevron-left"}}
|
|
||||||
<span class="d-button-label">{{i18n "poll.hide-results.label"}}</span>
|
|
||||||
</button>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.showShowResultsButton}}
|
|
||||||
<button
|
|
||||||
class="btn btn-default toggle-results"
|
|
||||||
title="poll.show-results.title"
|
|
||||||
{{on "click" this.toggleResults}}
|
|
||||||
>
|
|
||||||
{{icon "chart-bar"}}
|
|
||||||
<span class="d-button-label">{{i18n "poll.show-results.label"}}</span>
|
|
||||||
</button>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.showRemoveVoteButton}}
|
|
||||||
<button
|
|
||||||
class="btn btn-default remove-vote"
|
|
||||||
title="poll.remove-vote.title"
|
|
||||||
{{on "click" this.removeVote}}
|
|
||||||
>
|
|
||||||
{{icon "undo"}}
|
|
||||||
<span class="d-button-label">{{i18n "poll.remove-vote.label"}}</span>
|
|
||||||
</button>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<PollButtonsDropdown
|
|
||||||
@closed={{this.closed}}
|
@closed={{this.closed}}
|
||||||
|
@results={{this.poll.results}}
|
||||||
|
@showResults={{this.showResults}}
|
||||||
|
@postUserId={{this.poll.post.user_id}}
|
||||||
|
@isPublic={{this.poll.public}}
|
||||||
|
@hasVoted={{this.hasVoted}}
|
||||||
@voters={{this.voters}}
|
@voters={{this.voters}}
|
||||||
@isStaff={{this.isStaff}}
|
|
||||||
@isMe={{this.isMe}}
|
|
||||||
@isRankedChoice={{this.isRankedChoice}}
|
|
||||||
@topicArchived={{this.topicArchived}}
|
|
||||||
@groupableUserFields={{this.groupableUserFields}}
|
|
||||||
@isAutomaticallyClosed={{this.isAutomaticallyClosed}}
|
|
||||||
@dropDownClick={{this.dropDownClick}}
|
|
||||||
@availableDisplayMode={{this.availableDisplayMode}}
|
|
||||||
/>
|
/>
|
||||||
|
<div class="poll-buttons">
|
||||||
|
{{#if this.showCastVotesButton}}
|
||||||
|
<button
|
||||||
|
class={{this.castVotesButtonClass}}
|
||||||
|
title="poll.cast-votes.title"
|
||||||
|
disabled={{this.castVotesDisabled}}
|
||||||
|
{{on "click" this.castVotes}}
|
||||||
|
>
|
||||||
|
{{icon this.castVotesButtonIcon}}
|
||||||
|
<span class="d-button-label">{{i18n "poll.cast-votes.label"}}</span>
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.showHideResultsButton}}
|
||||||
|
<button
|
||||||
|
class="btn btn-default toggle-results"
|
||||||
|
title="poll.hide-results.title"
|
||||||
|
{{on "click" this.toggleResults}}
|
||||||
|
>
|
||||||
|
{{icon "chevron-left"}}
|
||||||
|
<span class="d-button-label">{{i18n
|
||||||
|
"poll.hide-results.label"
|
||||||
|
}}</span>
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.showShowResultsButton}}
|
||||||
|
<button
|
||||||
|
class="btn btn-default toggle-results"
|
||||||
|
title="poll.show-results.title"
|
||||||
|
{{on "click" this.toggleResults}}
|
||||||
|
>
|
||||||
|
{{icon "chart-bar"}}
|
||||||
|
<span class="d-button-label">{{i18n
|
||||||
|
"poll.show-results.label"
|
||||||
|
}}</span>
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.showRemoveVoteButton}}
|
||||||
|
<button
|
||||||
|
class="btn btn-default remove-vote"
|
||||||
|
title="poll.remove-vote.title"
|
||||||
|
{{on "click" this.removeVote}}
|
||||||
|
>
|
||||||
|
{{icon "undo"}}
|
||||||
|
<span class="d-button-label">{{i18n
|
||||||
|
"poll.remove-vote.label"
|
||||||
|
}}</span>
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<PollButtonsDropdown
|
||||||
|
@closed={{this.closed}}
|
||||||
|
@voters={{this.voters}}
|
||||||
|
@isStaff={{this.isStaff}}
|
||||||
|
@isMe={{this.isMe}}
|
||||||
|
@isRankedChoice={{this.isRankedChoice}}
|
||||||
|
@topicArchived={{this.topicArchived}}
|
||||||
|
@groupableUserFields={{this.groupableUserFields}}
|
||||||
|
@isAutomaticallyClosed={{this.isAutomaticallyClosed}}
|
||||||
|
@dropDownClick={{this.dropDownClick}}
|
||||||
|
@availableDisplayMode={{this.availableDisplayMode}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import EmberObject from "@ember/object";
|
||||||
|
import { TrackedObject } from "@ember-compat/tracked-built-ins";
|
||||||
|
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
import { PIE_CHART_TYPE } from "../components/modal/poll-ui-builder";
|
||||||
|
import Poll from "../components/poll";
|
||||||
|
|
||||||
|
function attachPolls(elem, helper) {
|
||||||
|
let pollNodes = [...elem.querySelectorAll(".poll")];
|
||||||
|
pollNodes = pollNodes.filter(
|
||||||
|
(node) => node.parentNode.tagName !== "BLOCKQUOTE"
|
||||||
|
);
|
||||||
|
if (!pollNodes.length || !helper) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const post = helper.getModel();
|
||||||
|
const polls = post.pollsObject;
|
||||||
|
|
||||||
|
pollNodes.forEach((pollNode) => {
|
||||||
|
const pollName = pollNode.dataset.pollName;
|
||||||
|
let poll = polls[pollName];
|
||||||
|
let pollPost = post;
|
||||||
|
|
||||||
|
const quotedId = pollNode.closest(".expanded-quote")?.dataset.postId;
|
||||||
|
if (quotedId && post.quoted[quotedId]) {
|
||||||
|
pollPost = EmberObject.create(post.quoted[quotedId]);
|
||||||
|
poll = new TrackedObject(pollPost.polls.find((p) => p.name === pollName));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (poll) {
|
||||||
|
const titleHTML = pollNode.querySelector(".poll-title")?.outerHTML;
|
||||||
|
|
||||||
|
const newPollNode = document.createElement("div");
|
||||||
|
Object.assign(newPollNode.dataset, {
|
||||||
|
pollName: poll.name,
|
||||||
|
pollType: poll.type,
|
||||||
|
});
|
||||||
|
newPollNode.classList.add("poll-outer");
|
||||||
|
if (poll.chart_type === PIE_CHART_TYPE) {
|
||||||
|
newPollNode.classList.add("pie");
|
||||||
|
}
|
||||||
|
|
||||||
|
pollNode.replaceWith(newPollNode);
|
||||||
|
helper.renderGlimmer(newPollNode, <template>
|
||||||
|
<Poll @poll={{poll}} @post={{post}} @titleHTML={{titleHTML}} />
|
||||||
|
</template>);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function initializePolls(api) {
|
||||||
|
api.modifyClass(
|
||||||
|
"controller:topic",
|
||||||
|
(Superclass) =>
|
||||||
|
class extends Superclass {
|
||||||
|
subscribe() {
|
||||||
|
super.subscribe(...arguments);
|
||||||
|
this.messageBus.subscribe(
|
||||||
|
`/polls/${this.model.id}`,
|
||||||
|
this._onPollMessage
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsubscribe() {
|
||||||
|
this.messageBus.unsubscribe("/polls/*", this._onPollMessage);
|
||||||
|
super.unsubscribe(...arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
@bind
|
||||||
|
_onPollMessage(msg) {
|
||||||
|
const post = this.get("model.postStream").findLoadedPost(msg.post_id);
|
||||||
|
if (post) {
|
||||||
|
post.polls = msg.polls;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
api.modifyClass(
|
||||||
|
"model:post",
|
||||||
|
(Superclass) =>
|
||||||
|
class extends Superclass {
|
||||||
|
@tracked pollsObject = new TrackedObject();
|
||||||
|
@tracked _polls;
|
||||||
|
|
||||||
|
get polls() {
|
||||||
|
return this._polls;
|
||||||
|
}
|
||||||
|
|
||||||
|
set polls(value) {
|
||||||
|
this._polls = value;
|
||||||
|
this._refreshPollsObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
_refreshPollsObject() {
|
||||||
|
for (const rawPoll of this.polls) {
|
||||||
|
const name = rawPoll.name;
|
||||||
|
this.pollsObject[name] ||= new TrackedObject();
|
||||||
|
Object.assign(this.pollsObject[name], rawPoll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
api.decorateCookedElement(attachPolls, { onlyStream: true });
|
||||||
|
|
||||||
|
const siteSettings = api.container.lookup("service:site-settings");
|
||||||
|
if (siteSettings.poll_enabled) {
|
||||||
|
api.addSearchSuggestion("in:polls");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "extend-for-poll",
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
withPluginApi("0.8.7", initializePolls);
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,150 +0,0 @@
|
||||||
import EmberObject from "@ember/object";
|
|
||||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
|
||||||
import WidgetGlue from "discourse/widgets/glue";
|
|
||||||
import { getRegister } from "discourse-common/lib/get-owner";
|
|
||||||
import { bind, observes } from "discourse-common/utils/decorators";
|
|
||||||
|
|
||||||
const PLUGIN_ID = "discourse-poll";
|
|
||||||
let _glued = [];
|
|
||||||
let _interval = null;
|
|
||||||
|
|
||||||
function rerender() {
|
|
||||||
_glued.forEach((g) => g.queueRerender());
|
|
||||||
}
|
|
||||||
|
|
||||||
function cleanUpPolls() {
|
|
||||||
if (_interval) {
|
|
||||||
clearInterval(_interval);
|
|
||||||
_interval = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
_glued.forEach((g) => g.cleanUp());
|
|
||||||
_glued = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function initializePolls(api) {
|
|
||||||
const register = getRegister(api),
|
|
||||||
pollGroupableUserFields = api.container.lookup(
|
|
||||||
"service:site-settings"
|
|
||||||
).poll_groupable_user_fields;
|
|
||||||
cleanUpPolls();
|
|
||||||
|
|
||||||
api.modifyClass("controller:topic", {
|
|
||||||
pluginId: PLUGIN_ID,
|
|
||||||
|
|
||||||
subscribe() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.messageBus.subscribe(`/polls/${this.model.id}`, this._onPollMessage);
|
|
||||||
},
|
|
||||||
|
|
||||||
unsubscribe() {
|
|
||||||
this.messageBus.unsubscribe("/polls/*", this._onPollMessage);
|
|
||||||
this._super(...arguments);
|
|
||||||
},
|
|
||||||
|
|
||||||
@bind
|
|
||||||
_onPollMessage(msg) {
|
|
||||||
const post = this.get("model.postStream").findLoadedPost(msg.post_id);
|
|
||||||
post?.set("polls", msg.polls);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
api.modifyClass("model:post", {
|
|
||||||
pluginId: PLUGIN_ID,
|
|
||||||
_polls: null,
|
|
||||||
pollsObject: null,
|
|
||||||
|
|
||||||
// we need a proper ember object so it is bindable
|
|
||||||
@observes("polls")
|
|
||||||
pollsChanged() {
|
|
||||||
const polls = this.polls;
|
|
||||||
if (polls) {
|
|
||||||
this._polls = this._polls || {};
|
|
||||||
polls.forEach((p) => {
|
|
||||||
const existing = this._polls[p.name];
|
|
||||||
if (existing) {
|
|
||||||
this._polls[p.name].setProperties(p);
|
|
||||||
} else {
|
|
||||||
this._polls[p.name] = EmberObject.create(p);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.set("pollsObject", this._polls);
|
|
||||||
rerender();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function attachPolls(elem, helper) {
|
|
||||||
let pollNodes = [...elem.querySelectorAll(".poll")];
|
|
||||||
pollNodes = pollNodes.filter(
|
|
||||||
(node) => node.parentNode.tagName !== "BLOCKQUOTE"
|
|
||||||
);
|
|
||||||
if (!pollNodes.length || !helper) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const post = helper.getModel();
|
|
||||||
api.preventCloak(post.id);
|
|
||||||
post.pollsChanged();
|
|
||||||
|
|
||||||
const polls = post.pollsObject || {};
|
|
||||||
const votes = post.polls_votes || {};
|
|
||||||
|
|
||||||
_interval = _interval || setInterval(rerender, 30000);
|
|
||||||
|
|
||||||
pollNodes.forEach((pollNode) => {
|
|
||||||
const pollName = pollNode.dataset.pollName;
|
|
||||||
let poll = polls[pollName];
|
|
||||||
let pollPost = post;
|
|
||||||
let vote = votes[pollName] || [];
|
|
||||||
|
|
||||||
const quotedId = pollNode.closest(".expanded-quote")?.dataset.postId;
|
|
||||||
if (quotedId && post.quoted[quotedId]) {
|
|
||||||
pollPost = post.quoted[quotedId];
|
|
||||||
pollPost = EmberObject.create(pollPost);
|
|
||||||
poll = EmberObject.create(pollPost.polls.findBy("name", pollName));
|
|
||||||
vote = pollPost.polls_votes || {};
|
|
||||||
vote = vote[pollName] || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (poll) {
|
|
||||||
const titleElement = pollNode.querySelector(".poll-title");
|
|
||||||
|
|
||||||
const attrs = {
|
|
||||||
id: `${pollName}-${pollPost.id}`,
|
|
||||||
post: pollPost,
|
|
||||||
poll,
|
|
||||||
vote,
|
|
||||||
hasSavedVote: vote.length > 0,
|
|
||||||
titleHTML: titleElement?.outerHTML,
|
|
||||||
groupableUserFields: (pollGroupableUserFields || "")
|
|
||||||
.split("|")
|
|
||||||
.filter(Boolean),
|
|
||||||
_postCookedWidget: helper.widget,
|
|
||||||
};
|
|
||||||
const glue = new WidgetGlue("discourse-poll", register, attrs);
|
|
||||||
glue.appendTo(pollNode);
|
|
||||||
_glued.push(glue);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
api.includePostAttributes("polls", "polls_votes");
|
|
||||||
api.decorateCookedElement(attachPolls, {
|
|
||||||
onlyStream: true,
|
|
||||||
});
|
|
||||||
api.cleanupStream(cleanUpPolls);
|
|
||||||
|
|
||||||
const siteSettings = api.container.lookup("service:site-settings");
|
|
||||||
if (siteSettings.poll_enabled) {
|
|
||||||
api.addSearchSuggestion("in:polls");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "extend-for-poll",
|
|
||||||
|
|
||||||
initialize() {
|
|
||||||
withPluginApi("0.8.7", initializePolls);
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,36 +0,0 @@
|
||||||
import { hbs } from "ember-cli-htmlbars";
|
|
||||||
import RenderGlimmer from "discourse/widgets/render-glimmer";
|
|
||||||
import { createWidget } from "discourse/widgets/widget";
|
|
||||||
import { PIE_CHART_TYPE } from "../components/modal/poll-ui-builder";
|
|
||||||
|
|
||||||
export default createWidget("discourse-poll", {
|
|
||||||
tagName: "div",
|
|
||||||
buildKey: (attrs) => `poll-${attrs.id}`,
|
|
||||||
services: ["dialog"],
|
|
||||||
|
|
||||||
buildAttributes(attrs) {
|
|
||||||
let cssClasses = "poll-outer";
|
|
||||||
if (attrs.poll.chart_type === PIE_CHART_TYPE) {
|
|
||||||
cssClasses += " pie";
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
class: cssClasses,
|
|
||||||
"data-poll-name": attrs.poll.name,
|
|
||||||
"data-poll-type": attrs.poll.type,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
html(attrs) {
|
|
||||||
return [
|
|
||||||
new RenderGlimmer(
|
|
||||||
this,
|
|
||||||
"div.poll",
|
|
||||||
hbs`<Poll @attrs={{@data.attrs}} @preloadedVoters={{@data.preloadedVoters}} />`,
|
|
||||||
{
|
|
||||||
attrs,
|
|
||||||
preloadedVoters: attrs.poll.preloaded_voters,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
];
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,15 +1,10 @@
|
||||||
import EmberObject from "@ember/object";
|
import EmberObject from "@ember/object";
|
||||||
import { click, render } from "@ember/test-helpers";
|
import { click, render } from "@ember/test-helpers";
|
||||||
|
import { TrackedObject } from "@ember-compat/tracked-built-ins";
|
||||||
import hbs from "htmlbars-inline-precompile";
|
import hbs from "htmlbars-inline-precompile";
|
||||||
import { module, test } from "qunit";
|
import { module, test } from "qunit";
|
||||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||||
import pretender, { response } from "discourse/tests/helpers/create-pretender";
|
import pretender, { response } from "discourse/tests/helpers/create-pretender";
|
||||||
import {
|
|
||||||
count,
|
|
||||||
exists,
|
|
||||||
query,
|
|
||||||
queryAll,
|
|
||||||
} from "discourse/tests/helpers/qunit-helpers";
|
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
|
|
||||||
let requests = 0;
|
let requests = 0;
|
||||||
|
@ -48,112 +43,86 @@ module("Poll | Component | poll", function (hooks) {
|
||||||
|
|
||||||
test("shows vote", async function (assert) {
|
test("shows vote", async function (assert) {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
attributes: EmberObject.create({
|
post: EmberObject.create({
|
||||||
post: EmberObject.create({
|
id: 42,
|
||||||
id: 42,
|
topic: {
|
||||||
topic: {
|
archived: false,
|
||||||
archived: false,
|
},
|
||||||
},
|
user_id: 29,
|
||||||
user_id: 29,
|
}),
|
||||||
}),
|
poll: new TrackedObject({
|
||||||
poll: EmberObject.create({
|
name: "poll",
|
||||||
name: "poll",
|
type: "regular",
|
||||||
type: "regular",
|
status: "closed",
|
||||||
status: "closed",
|
results: "always",
|
||||||
results: "always",
|
options: [
|
||||||
options: [
|
{ id: "1f972d1df351de3ce35a787c89faad29", html: "yes", votes: 1 },
|
||||||
{ id: "1f972d1df351de3ce35a787c89faad29", html: "yes", votes: 1 },
|
{ id: "d7ebc3a9beea2e680815a1e4f57d6db6", html: "no", votes: 0 },
|
||||||
{ id: "d7ebc3a9beea2e680815a1e4f57d6db6", html: "no", votes: 0 },
|
],
|
||||||
],
|
voters: 1,
|
||||||
voters: 1,
|
chart_type: "bar",
|
||||||
chart_type: "bar",
|
|
||||||
}),
|
|
||||||
vote: [],
|
|
||||||
groupableUserFields: [],
|
|
||||||
}),
|
}),
|
||||||
preloadedVoters: [],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await render(
|
await render(hbs`<Poll @post={{this.post}} @poll={{this.poll}} />`);
|
||||||
hbs`<Poll @attrs={{this.attributes}} @preloadedVoters={{this.preloadedVoters}} />`
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.deepEqual(
|
assert.dom(".results li:nth-of-type(1) .option p").hasText("100% yes");
|
||||||
Array.from(queryAll(".results li .option p")).map(
|
assert.dom(".results li:nth-of-type(2) .option p").hasText("0% no");
|
||||||
(span) => span.innerText
|
|
||||||
),
|
|
||||||
["100% yes", "0% no"]
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("does not show results after voting when results are to be shown only on closed", async function (assert) {
|
test("does not show results after voting when results are to be shown only on closed", async function (assert) {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
attributes: EmberObject.create({
|
post: EmberObject.create({
|
||||||
post: EmberObject.create({
|
id: 42,
|
||||||
id: 42,
|
topic: {
|
||||||
topic: {
|
archived: false,
|
||||||
archived: false,
|
},
|
||||||
},
|
user_id: 29,
|
||||||
user_id: 29,
|
}),
|
||||||
}),
|
poll: new TrackedObject({
|
||||||
hasSavedVote: true,
|
name: "poll",
|
||||||
poll: EmberObject.create({
|
type: "regular",
|
||||||
name: "poll",
|
status: "open",
|
||||||
type: "regular",
|
results: "on_close",
|
||||||
status: "open",
|
options: [
|
||||||
results: "on_close",
|
{ id: "1f972d1df351de3ce35a787c89faad29", html: "yes" },
|
||||||
options: [
|
{ id: "d7ebc3a9beea2e680815a1e4f57d6db6", html: "no" },
|
||||||
{ id: "1f972d1df351de3ce35a787c89faad29", html: "yes" },
|
],
|
||||||
{ id: "d7ebc3a9beea2e680815a1e4f57d6db6", html: "no" },
|
voters: 1,
|
||||||
],
|
chart_type: "bar",
|
||||||
voters: 1,
|
|
||||||
chart_type: "bar",
|
|
||||||
}),
|
|
||||||
vote: ["1f972d1df351de3ce35a787c89faad29"],
|
|
||||||
groupableUserFields: [],
|
|
||||||
}),
|
}),
|
||||||
preloadedVoters: [],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await render(
|
await render(hbs`<Poll @post={{this.post}} @poll={{this.poll}} />`);
|
||||||
hbs`<Poll @attrs={{this.attributes}} @preloadedVoters={{this.preloadedVoters}} />`
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.ok(exists("ul.options"), "options are shown");
|
assert.dom("ul.options").exists("options are shown");
|
||||||
assert.ok(!exists("ul.results"), "results are not shown");
|
assert.dom("ul.results").doesNotExist("results are not shown");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("can vote", async function (assert) {
|
test("can vote", async function (assert) {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
attributes: EmberObject.create({
|
post: EmberObject.create({
|
||||||
post: EmberObject.create({
|
id: 42,
|
||||||
id: 42,
|
topic: {
|
||||||
topic: {
|
archived: false,
|
||||||
archived: false,
|
},
|
||||||
},
|
user_id: 29,
|
||||||
user_id: 29,
|
}),
|
||||||
}),
|
poll: new TrackedObject({
|
||||||
poll: EmberObject.create({
|
name: "poll",
|
||||||
name: "poll",
|
type: "regular",
|
||||||
type: "regular",
|
status: "open",
|
||||||
status: "open",
|
results: "always",
|
||||||
results: "always",
|
options: [
|
||||||
options: [
|
{ id: "1f972d1df351de3ce35a787c89faad29", html: "yes", votes: 0 },
|
||||||
{ id: "1f972d1df351de3ce35a787c89faad29", html: "yes", votes: 0 },
|
{ id: "d7ebc3a9beea2e680815a1e4f57d6db6", html: "no", votes: 0 },
|
||||||
{ id: "d7ebc3a9beea2e680815a1e4f57d6db6", html: "no", votes: 0 },
|
],
|
||||||
],
|
voters: 0,
|
||||||
voters: 0,
|
chart_type: "bar",
|
||||||
chart_type: "bar",
|
|
||||||
}),
|
|
||||||
vote: [],
|
|
||||||
groupableUserFields: [],
|
|
||||||
}),
|
}),
|
||||||
preloadedVoters: [],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await render(
|
await render(hbs`<Poll @post={{this.post}} @poll={{this.poll}} />`);
|
||||||
hbs`<Poll @attrs={{this.attributes}} @preloadedVoters={{this.preloadedVoters}} />`
|
|
||||||
);
|
|
||||||
|
|
||||||
requests = 0;
|
requests = 0;
|
||||||
|
|
||||||
|
@ -161,100 +130,84 @@ module("Poll | Component | poll", function (hooks) {
|
||||||
"li[data-poll-option-id='1f972d1df351de3ce35a787c89faad29'] button"
|
"li[data-poll-option-id='1f972d1df351de3ce35a787c89faad29'] button"
|
||||||
);
|
);
|
||||||
assert.strictEqual(requests, 1);
|
assert.strictEqual(requests, 1);
|
||||||
assert.strictEqual(count(".chosen"), 1);
|
assert.dom(".chosen").exists({ count: 1 });
|
||||||
|
|
||||||
await click(".toggle-results");
|
await click(".toggle-results");
|
||||||
assert.strictEqual(
|
assert
|
||||||
count("li[data-poll-option-id='1f972d1df351de3ce35a787c89faad29']"),
|
.dom("li[data-poll-option-id='1f972d1df351de3ce35a787c89faad29']")
|
||||||
1
|
.exists({ count: 1 });
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("cannot vote if not member of the right group", async function (assert) {
|
test("cannot vote if not member of the right group", async function (assert) {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
attributes: EmberObject.create({
|
post: EmberObject.create({
|
||||||
post: EmberObject.create({
|
id: 42,
|
||||||
id: 42,
|
topic: {
|
||||||
topic: {
|
archived: false,
|
||||||
archived: false,
|
},
|
||||||
},
|
user_id: 29,
|
||||||
user_id: 29,
|
}),
|
||||||
}),
|
poll: new TrackedObject({
|
||||||
poll: EmberObject.create({
|
name: "poll",
|
||||||
name: "poll",
|
type: "regular",
|
||||||
type: "regular",
|
status: "open",
|
||||||
status: "open",
|
results: "always",
|
||||||
results: "always",
|
options: [
|
||||||
options: [
|
{ id: "1f972d1df351de3ce35a787c89faad29", html: "yes", votes: 0 },
|
||||||
{ id: "1f972d1df351de3ce35a787c89faad29", html: "yes", votes: 0 },
|
{ id: "d7ebc3a9beea2e680815a1e4f57d6db6", html: "no", votes: 0 },
|
||||||
{ id: "d7ebc3a9beea2e680815a1e4f57d6db6", html: "no", votes: 0 },
|
],
|
||||||
],
|
voters: 0,
|
||||||
voters: 0,
|
chart_type: "bar",
|
||||||
chart_type: "bar",
|
groups: "foo",
|
||||||
groups: "foo",
|
|
||||||
}),
|
|
||||||
vote: [],
|
|
||||||
groupableUserFields: [],
|
|
||||||
}),
|
}),
|
||||||
preloadedVoters: [],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await render(
|
await render(hbs`<Poll @post={{this.post}} @poll={{this.poll}} />`);
|
||||||
hbs`<Poll @attrs={{this.attributes}} @preloadedVoters={{this.preloadedVoters}} />`
|
|
||||||
);
|
|
||||||
|
|
||||||
requests = 0;
|
requests = 0;
|
||||||
|
|
||||||
await click(
|
await click(
|
||||||
"li[data-poll-option-id='1f972d1df351de3ce35a787c89faad29'] button"
|
"li[data-poll-option-id='1f972d1df351de3ce35a787c89faad29'] button"
|
||||||
);
|
);
|
||||||
assert.strictEqual(
|
assert
|
||||||
query(".poll-container .alert").innerText,
|
.dom(".poll-container .alert")
|
||||||
I18n.t("poll.results.groups.title", { groups: "foo" })
|
.hasText(I18n.t("poll.results.groups.title", { groups: "foo" }));
|
||||||
);
|
|
||||||
assert.strictEqual(requests, 0);
|
assert.strictEqual(requests, 0);
|
||||||
assert.ok(!exists(".chosen"));
|
assert.dom(".chosen").doesNotExist();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("voting on a multiple poll with no min attribute", async function (assert) {
|
test("voting on a multiple poll with no min attribute", async function (assert) {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
attributes: EmberObject.create({
|
post: EmberObject.create({
|
||||||
post: EmberObject.create({
|
id: 42,
|
||||||
id: 42,
|
topic: {
|
||||||
topic: {
|
archived: false,
|
||||||
archived: false,
|
},
|
||||||
},
|
user_id: 29,
|
||||||
user_id: 29,
|
}),
|
||||||
}),
|
poll: EmberObject.create({
|
||||||
poll: EmberObject.create({
|
name: "poll",
|
||||||
name: "poll",
|
type: "multiple",
|
||||||
type: "multiple",
|
status: "open",
|
||||||
status: "open",
|
results: "always",
|
||||||
results: "always",
|
max: 2,
|
||||||
max: 2,
|
options: [
|
||||||
options: [
|
{ id: "1f972d1df351de3ce35a787c89faad29", html: "yes", votes: 0 },
|
||||||
{ id: "1f972d1df351de3ce35a787c89faad29", html: "yes", votes: 0 },
|
{ id: "d7ebc3a9beea2e680815a1e4f57d6db6", html: "no", votes: 0 },
|
||||||
{ id: "d7ebc3a9beea2e680815a1e4f57d6db6", html: "no", votes: 0 },
|
],
|
||||||
],
|
voters: 0,
|
||||||
voters: 0,
|
chart_type: "bar",
|
||||||
chart_type: "bar",
|
|
||||||
}),
|
|
||||||
vote: [],
|
|
||||||
groupableUserFields: [],
|
|
||||||
}),
|
}),
|
||||||
preloadedVoters: [],
|
|
||||||
});
|
});
|
||||||
await render(
|
await render(hbs`<Poll @post={{this.post}} @poll={{this.poll}} />`);
|
||||||
hbs`<Poll @attrs={{this.attributes}} @preloadedVoters={{this.preloadedVoters}} />`
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.ok(exists(".poll-buttons .cast-votes:disabled"));
|
assert.dom(".poll-buttons .cast-votes:disabled").exists();
|
||||||
|
|
||||||
await click(
|
await click(
|
||||||
"li[data-poll-option-id='1f972d1df351de3ce35a787c89faad29'] button"
|
"li[data-poll-option-id='1f972d1df351de3ce35a787c89faad29'] button"
|
||||||
);
|
);
|
||||||
|
|
||||||
await click(".poll-buttons .cast-votes");
|
await click(".poll-buttons .cast-votes");
|
||||||
assert.ok(exists(".chosen"));
|
assert.dom(".chosen").exists();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue