REFACTOR: improve poll info layout (#22353)

This commit is contained in:
Kris 2023-07-05 12:20:18 -04:00 committed by GitHub
parent d75d64bf16
commit 4cec091f1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 529 additions and 320 deletions

View File

@ -11,7 +11,6 @@
.widget-dropdown-body {
display: flex;
flex-direction: column;
padding: 0.25em;
background: var(--secondary);
z-index: z("dropdown");
border: 1px solid var(--primary-low);
@ -22,7 +21,7 @@
.widget-dropdown-item {
cursor: pointer;
padding: 0.25em;
padding: 0.5em 1em;
display: flex;
flex: 1;
align-items: center;
@ -43,7 +42,7 @@
}
&:hover {
background: var(--tertiary-low);
background: var(--d-hover);
}
}

View File

@ -19,7 +19,13 @@ $breakpoints: (
);
@mixin breakpoint($bp, $rule: max-width, $type: screen, $sidebar: false) {
@media #{$type} and (#{$rule}: map-get($breakpoints, $bp)) {
$bp-value: map-get($breakpoints, $bp);
@if $rule == min-width {
$bp-value: calc(#{$bp-value} + 1px);
}
@media #{$type} and (#{$rule}: #{$bp-value}) {
@content;
}

View File

@ -7,17 +7,48 @@ import { createWidget } from "discourse/widgets/widget";
import evenRound from "discourse/plugins/poll/lib/even-round";
import { getColors } from "discourse/plugins/poll/lib/chart-colors";
import { h } from "virtual-dom";
import { iconNode } from "discourse-common/lib/icon-library";
import { iconHTML, iconNode } from "discourse-common/lib/icon-library";
import loadScript from "discourse/lib/load-script";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { relativeAge } from "discourse/lib/formatter";
import round from "discourse/lib/round";
import { applyLocalDates } from "discourse/lib/local-dates";
import hbs from "discourse/widgets/hbs-compiler";
import PollBreakdownModal from "../components/modal/poll-breakdown";
import { getOwner } from "@ember/application";
const FETCH_VOTERS_COUNT = 25;
const buttonOptionsMap = {
exportResults: {
className: "btn-default export-results",
label: "poll.export-results.label",
title: "poll.export-results.title",
icon: "download",
action: "exportResults",
},
showBreakdown: {
className: "btn-default show-breakdown",
label: "poll.breakdown.breakdown",
icon: "chart-pie",
action: "showBreakdown",
},
openPoll: {
className: "btn-default toggle-status",
label: "poll.open.label",
title: "poll.open.title",
icon: "unlock-alt",
action: "toggleStatus",
},
closePoll: {
className: "btn-default toggle-status",
label: "poll.close.label",
title: "poll.close.title",
icon: "lock",
action: "toggleStatus",
},
};
function optionHtml(option, siteSettings = {}) {
const el = document.createElement("span");
el.innerHTML = option.html;
@ -25,12 +56,6 @@ function optionHtml(option, siteSettings = {}) {
return new RawHtml({ html: `<span>${el.innerHTML}</span>` });
}
function infoTextHtml(text) {
return new RawHtml({
html: `<span class="info-text">${text}</span>`,
});
}
function checkUserGroups(user, poll) {
const pollGroups =
poll && poll.groups && poll.groups.split(",").map((g) => g.toLowerCase());
@ -407,14 +432,18 @@ createWidget("discourse-poll-info", {
},
html(attrs) {
const { poll } = attrs;
const { poll, post } = attrs;
const closed = attrs.isClosed;
const isStaff = this.currentUser && this.currentUser.staff;
const isMe = this.currentUser && post.user_id === this.currentUser.id;
const count = poll.voters;
const contents = [
h("p", [
h("div.poll-info_counts-count", [
h("span.info-number", count.toString()),
h("span.info-label", I18n.t("poll.voters", { count })),
]),
];
const instructions = [];
if (attrs.isMultiple) {
if (attrs.showResults || attrs.isClosed) {
@ -423,7 +452,7 @@ createWidget("discourse-poll-info", {
}, 0);
contents.push(
h("p", [
h("div.poll-info_counts-count", [
h("span.info-number", totalVotes.toString()),
h(
"span.info-label",
@ -438,21 +467,94 @@ createWidget("discourse-poll-info", {
poll.options.length
);
if (help) {
contents.push(infoTextHtml(help));
instructions.push(
new RawHtml({
html: `<li>
${iconHTML("list-ul")}
<span>${help}</span>
</li>`,
})
);
}
}
}
if (poll.close) {
const closeDate = moment.utc(poll.close, "YYYY-MM-DD HH:mm:ss Z");
if (closeDate.isValid()) {
const title = closeDate.format("LLL");
let label;
let icon;
if (attrs.isAutomaticallyClosed) {
const age = relativeAge(closeDate.toDate(), { addAgo: true });
label = I18n.t("poll.automatic_close.age", { age });
icon = "lock";
} else {
const timeLeft = moment().to(closeDate, true);
label = I18n.t("poll.automatic_close.closes_in", { timeLeft });
icon = "far-clock";
}
instructions.push(
new RawHtml({
html: `<li title="${title}">
${iconHTML(icon)}
<span>${label}</span>
</li>`,
})
);
}
}
let infoText;
if (poll.results === "on_vote" && !attrs.hasVoted && !isMe) {
infoText = new RawHtml({
html: `<li>
${iconHTML("check")}
<span>${I18n.t("poll.results.vote.title")}</span>
</li>`,
});
} else if (poll.results === "on_close" && !closed) {
infoText = new RawHtml({
html: `<li>
${iconHTML("lock")}
<span>${I18n.t("poll.results.closed.title")}</span>
</li>`,
});
} else if (poll.results === "staff_only" && !isStaff) {
infoText = new RawHtml({
html: `<li>
${iconHTML("shield-alt")}
<span>${I18n.t("poll.results.staff.title")}</span>
</li>`,
});
}
if (infoText) {
instructions.push(infoText);
}
if (
!attrs.isClosed &&
!attrs.showResults &&
poll.public &&
poll.results !== "staff_only"
) {
contents.push(infoTextHtml(I18n.t("poll.public.title")));
instructions.push(
new RawHtml({
html: `<li>
${iconHTML("far-eye")}
<span>${I18n.t("poll.public.title")}</span>
</li>`,
})
);
}
return contents;
return [
h("div.poll-info_counts", contents),
h("ul.poll-info_instructions", instructions),
];
},
});
@ -595,6 +697,82 @@ function stripHtml(html) {
return doc.body.textContent || "";
}
createWidget("discourse-poll-buttons-dropdown", {
tagName: "div.poll-buttons-dropdown",
buildId(attrs) {
return `poll-buttons-dropdown-${attrs.id}`;
},
transform(attrs) {
return {
content: this._buildContent(attrs),
onChange: (item) => this.sendWidgetAction(item.id, item.param),
};
},
template: hbs`
{{attach
widget="widget-dropdown"
attrs=(hash
id=this.attrs.id
icon="cog"
label="poll.options.label"
content=this.transformed.content
onChange=this.transformed.onChange
options=this.transformed.options
)
}}
`,
optionsCount(attrs) {
return this._buildContent(attrs).length;
},
_buildContent(attrs) {
const contents = [];
const isAdmin = this.currentUser && this.currentUser.admin;
const dataExplorerEnabled = this.siteSettings.data_explorer_enabled;
const exportQueryID = this.siteSettings.poll_export_data_explorer_query_id;
const { poll, post } = attrs;
const closed = attrs.isClosed;
const isStaff = this.currentUser && this.currentUser.staff;
const topicArchived = post.get("topic.archived");
if (attrs.groupableUserFields.length && poll.voters > 0) {
const option = { ...buttonOptionsMap.showBreakdown };
option.id = option.action;
contents.push(option);
}
if (isAdmin && dataExplorerEnabled && poll.voters > 0 && exportQueryID) {
const option = { ...buttonOptionsMap.exportResults };
option.id = option.action;
contents.push(option);
}
if (
this.currentUser &&
(this.currentUser.id === post.user_id || isStaff) &&
!topicArchived
) {
if (closed) {
if (!attrs.isAutomaticallyClosed) {
const option = { ...buttonOptionsMap.openPoll };
option.id = option.action;
contents.push(option);
}
} else {
const option = { ...buttonOptionsMap.closePoll };
option.id = option.action;
contents.push(option);
}
}
return contents;
},
});
createWidget("discourse-poll-buttons", {
tagName: "div.poll-buttons",
@ -605,13 +783,12 @@ createWidget("discourse-poll-buttons", {
const closed = attrs.isClosed;
const staffOnly = poll.results === "staff_only";
const isStaff = this.currentUser && this.currentUser.staff;
const isAdmin = this.currentUser && this.currentUser.admin;
const isMe = this.currentUser && post.user_id === this.currentUser.id;
const dataExplorerEnabled = this.siteSettings.data_explorer_enabled;
const hideResultsDisabled = !staffOnly && (closed || topicArchived);
const exportQueryID = this.siteSettings.poll_export_data_explorer_query_id;
const dropdown = this.attach("discourse-poll-buttons-dropdown", attrs);
const dropdownOptionsCount = dropdown.optionsCount(attrs);
if (attrs.isMultiple && !hideResultsDisabled) {
if (attrs.isMultiple && !hideResultsDisabled && !attrs.showResults) {
const castVotesDisabled = !attrs.canCastVotes;
contents.push(
this.attach("button", {
@ -620,144 +797,75 @@ createWidget("discourse-poll-buttons", {
}`,
label: "poll.cast-votes.label",
title: "poll.cast-votes.title",
icon: castVotesDisabled ? "far-square" : "check",
disabled: castVotesDisabled,
action: "castVotes",
})
);
contents.push(" ");
}
if (attrs.showResults || hideResultsDisabled) {
if (attrs.showResults && !hideResultsDisabled) {
contents.push(
this.attach("button", {
className: "btn-default toggle-results",
label: "poll.hide-results.label",
title: "poll.hide-results.title",
icon: "far-eye-slash",
disabled: hideResultsDisabled,
icon: "chevron-left",
action: "toggleResults",
})
);
} else {
let showResultsButton;
let infoText;
}
if (poll.results === "on_vote" && !attrs.hasVoted && !isMe) {
infoText = infoTextHtml(I18n.t("poll.results.vote.title"));
} else if (poll.results === "on_close" && !closed) {
infoText = infoTextHtml(I18n.t("poll.results.closed.title"));
} else if (poll.results === "staff_only" && !isStaff) {
infoText = infoTextHtml(I18n.t("poll.results.staff.title"));
} else {
if (!attrs.showResults && !hideResultsDisabled) {
let showResultsButton;
if (
!(poll.results === "on_vote" && !attrs.hasVoted && !isMe) &&
!(poll.results === "on_close" && !closed) &&
!(poll.results === "staff_only" && !isStaff) &&
poll.voters > 0
) {
showResultsButton = this.attach("button", {
className: "btn-default toggle-results",
label: "poll.show-results.label",
title: "poll.show-results.title",
icon: "far-eye",
disabled: poll.voters === 0,
icon: "chart-bar",
action: "toggleResults",
});
}
if (showResultsButton) {
contents.push(showResultsButton);
}
if (attrs.hasSavedVote) {
contents.push(
this.attach("button", {
className: "btn-default remove-vote",
label: "poll.remove-vote.label",
title: "poll.remove-vote.title",
icon: "trash-alt",
icon: "undo",
action: "removeVote",
})
);
}
if (infoText) {
contents.push(infoText);
if (showResultsButton) {
contents.push(showResultsButton);
}
}
if (attrs.groupableUserFields.length && poll.voters > 0) {
const button = this.attach("button", {
className: "btn-default poll-show-breakdown",
label: "poll.group-results.label",
title: "poll.group-results.title",
icon: "far-eye",
action: "showBreakdown",
});
contents.push(button);
}
if (isAdmin && dataExplorerEnabled && poll.voters > 0 && exportQueryID) {
contents.push(
this.attach("button", {
className: "btn btn-default export-results",
label: "poll.export-results.label",
title: "poll.export-results.title",
icon: "download",
disabled: poll.voters === 0,
action: "exportResults",
})
);
}
if (poll.close) {
const closeDate = moment(poll.close);
if (closeDate.isValid()) {
const title = closeDate.format("LLL");
let label;
if (attrs.isAutomaticallyClosed) {
const age = relativeAge(closeDate.toDate(), { addAgo: true });
label = I18n.t("poll.automatic_close.age", { age });
} else {
const timeLeft = moment().to(closeDate, true);
label = I18n.t("poll.automatic_close.closes_in", { timeLeft });
}
contents.push(
new RawHtml({
html: `<span class="info-text" title="${title}">${label}</span>`,
})
);
// only show the dropdown if there's more than 1 button
// otherwise just show the button
if (dropdownOptionsCount > 1) {
contents.push(dropdown);
} else if (dropdownOptionsCount === 1) {
const singleOptionId = dropdown._buildContent(attrs)[0].id;
let singleOption = buttonOptionsMap[singleOptionId];
if (singleOptionId === "toggleStatus") {
singleOption = closed
? buttonOptionsMap.openPoll
: buttonOptionsMap.closePoll;
}
contents.push(this.attach("button", singleOption));
}
if (
this.currentUser &&
(this.currentUser.id === post.user_id || isStaff) &&
!topicArchived
) {
if (closed) {
if (!attrs.isAutomaticallyClosed) {
contents.push(
this.attach("button", {
className: "btn-default toggle-status",
label: "poll.open.label",
title: "poll.open.title",
icon: "unlock-alt",
action: "toggleStatus",
})
);
}
} else {
contents.push(
this.attach("button", {
className: "toggle-status btn-danger",
label: "poll.close.label",
title: "poll.close.title",
icon: "lock",
action: "toggleStatus",
})
);
}
}
return contents;
return [contents];
},
});
@ -806,11 +914,11 @@ export default createWidget("discourse-poll", {
showResults,
});
return h("div", [
return [
this.attach("discourse-poll-container", newAttrs),
this.attach("discourse-poll-info", newAttrs),
this.attach("discourse-poll-buttons", newAttrs),
]);
];
},
min() {
@ -833,7 +941,9 @@ export default createWidget("discourse-poll", {
isAutomaticallyClosed() {
const { poll } = this.attrs;
return poll.close && moment.utc(poll.close) <= moment();
return (
poll.close && moment.utc(poll.close, "YYYY-MM-DD HH:mm:ss Z") <= moment()
);
},
isClosed() {

View File

@ -158,10 +158,6 @@ const rule = {
token.attrs = attributes;
header.push(token);
token = new state.Token("poll_open", "div", 1);
token.block = true;
header.push(token);
token = new state.Token("poll_open", "div", 1);
token.attrs = [["class", "poll-container"]];
header.push(token);
@ -236,7 +232,11 @@ const rule = {
token = state.push("poll_open", "div", 1);
token.attrs = [["class", "poll-info"]];
state.push("paragraph_open", "p", 1);
token = state.push("poll_open", "div", 1);
token.attrs = [["class", "poll-info_counts"]];
token = state.push("poll_open", "div", 1);
token.attrs = [["class", "poll-info_counts-count"]];
token = state.push("span_open", "span", 1);
token.block = false;
@ -252,8 +252,7 @@ const rule = {
token.content = I18n.t("poll.voters", { count: 0 });
state.push("span_close", "span", -1);
state.push("paragraph_close", "p", -1);
state.push("poll_close", "div", -1);
state.push("poll_close", "div", -1);
state.push("poll_close", "div", -1);
state.push("poll_close", "div", -1);
@ -277,6 +276,8 @@ export function setup(helper) {
helper.allowList([
"div.poll",
"div.poll-info",
"div.poll-info_counts",
"div.poll-info_counts-count",
"div.poll-container",
"div.poll-title",
"div.poll-buttons",

View File

@ -1,6 +1,15 @@
div.poll {
> * {
box-sizing: border-box;
}
margin: 1em 0;
border: 1px solid var(--primary-low);
display: grid;
grid-template-areas: "poll" "info" "buttons";
@include breakpoint("mobile-extra-large", min-width) {
grid-template-columns: 1fr 10em;
grid-template-areas: "poll info" "buttons buttons";
}
ul,
ol {
@ -11,11 +20,6 @@ div.poll {
width: 100%;
}
li {
cursor: pointer;
font-size: var(--font-up-1);
}
li[data-poll-option-id] {
color: var(--primary);
padding: 0.5em 0;
@ -34,38 +38,228 @@ div.poll {
}
.poll-info {
grid-area: info;
display: flex;
line-height: var(--line-height-medium);
color: var(--primary-medium);
vertical-align: middle;
padding: 1em 0;
.info-label {
font-size: var(--font-up-4);
line-height: var(--line-height-medium);
@include breakpoint("mobile-extra-large") {
border-top: 1px solid var(--primary-low);
flex-direction: row-reverse;
&_counts,
&_instructions {
padding: 1em;
}
}
@include breakpoint("mobile-extra-large", min-width) {
gap: 0 1em;
padding: 1em;
border-left: 1px solid var(--primary-low);
flex-direction: column;
justify-content: center;
align-items: center;
}
&_counts {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.25em 0;
@include breakpoint("mobile-extra-large", min-width) {
justify-content: center;
}
@include breakpoint("mobile-extra-large") {
flex: 1 1 auto;
}
&-count {
gap: 0.25em;
line-height: 1;
white-space: nowrap;
text-align: left;
.info-label,
.info-number {
display: inline;
margin-right: 0.25em;
text-align: center;
}
@include breakpoint("mobile-extra-large") {
&:not(:last-child) {
margin-right: 0.75em;
}
}
@include breakpoint("mobile-extra-large", min-width) {
&:not(:last-child) {
margin-bottom: 0.25em;
}
display: flex;
flex-direction: column;
align-items: center;
+ .poll-info_counts-count {
margin-top: 0.5em;
display: block;
.info-number {
margin-right: 0.33em;
}
.info-number,
.info-label {
font-size: var(--font-up-1);
}
}
}
}
@include breakpoint("mobile-extra-large", min-width) {
+ .poll-info_instructions:not(:empty) {
margin-top: 1.25em;
}
}
}
&_instructions {
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
align-self: start;
&:empty {
display: none;
}
@include breakpoint("mobile-extra-large", min-width) {
padding-top: 1.25em;
&:not(:empty) {
border-top: 1px solid var(--primary-low);
}
}
@include breakpoint("mobile-extra-large") {
padding-right: 1em;
height: 100%;
flex: 1 1 auto;
&:not(:empty) {
border-right: 1px solid var(--primary-low);
}
}
li {
display: flex;
gap: 0.5em;
&:not(:last-child) {
margin-bottom: 0.5em;
}
@include breakpoint("mobile-extra-large", min-width) {
&:not(:last-child) {
margin-bottom: 1em;
}
&:not(:first-child:last-child) {
// only applied when there are multiple items
.d-icon {
width: 15%;
}
span {
width: 85%;
}
}
&:first-child:last-child {
// when there's a single item, it looks better centered
display: inline;
text-align: center;
}
}
}
.d-icon {
font-size: var(--font-down-1);
margin-top: 0.2em;
}
}
.info-text {
margin: 0.25em 0;
display: block;
}
@include breakpoint("mobile-extra-large", min-width) {
.info-label {
font-size: var(--font-up-2);
}
.info-number {
font-size: var(--font-up-6);
}
}
}
.poll-container {
vertical-align: middle;
padding: 0.5em 1em;
grid-area: poll;
padding: 1em;
width: 100%;
overflow: hidden;
align-self: center;
li {
cursor: pointer;
font-size: var(--font-up-1);
}
.poll-results-number-rating {
font-size: var(--font-up-5);
}
}
.poll-title {
border-bottom: 1px solid var(--primary-low);
margin-bottom: 0.5em;
padding-bottom: 0.5em;
}
.poll-buttons {
.info-text {
margin: 0.25em 0;
color: var(--primary-medium);
grid-area: buttons;
display: flex;
flex-wrap: wrap;
gap: 0.5em;
width: 100%;
padding: 1em;
border-top: 1px solid var(--primary-low);
button {
white-space: nowrap;
align-self: start;
.d-button-label {
@include ellipsis;
}
@include breakpoint("tablet") {
flex: 1 1 0;
&:first-child:last-child {
// if there's only one button,
// don't expand the width
flex: 0 1 auto;
}
&.toggle-results:first-child {
// don't expand the back button
flex: 0 1 auto;
margin-right: auto;
}
}
@include breakpoint("mobile-large") {
&:first-child:last-child,
&.cast-votes {
// ok to expand button width on smaller screens
flex: 1 1 100%;
}
}
}
.info-text + .info-text,
button + .info-text {
margin-left: 0.5em;
&:empty {
display: none;
}
}
@ -87,6 +281,33 @@ div.poll {
}
}
.poll-buttons-dropdown {
align-self: stretch;
.label {
display: none;
}
.widget-dropdown {
height: 100%;
&-header {
height: 100%;
.d-icon {
margin: 0;
}
}
}
}
.poll-buttons-dropdown,
.export-results,
.toggle-status,
.show-breakdown {
// we want these controls to be separated
// from voting controls
margin-left: auto;
}
.results {
> li {
cursor: default;
@ -160,19 +381,27 @@ div.poll {
overflow-y: auto;
overflow-x: hidden;
}
.poll-show-breakdown {
margin-bottom: 0.25em;
}
}
div.poll.pie {
.poll-container {
display: inline-block;
}
.poll-info {
display: inline-block;
width: 150px;
.d-editor-preview {
.poll {
li[data-poll-option-id]:before {
position: relative;
vertical-align: baseline;
border: 2px solid var(--primary);
border-radius: 50%;
display: inline-block;
margin-right: 0.5em;
width: 12px;
height: 12px;
content: "";
}
&[data-poll-type="multiple"] {
li[data-poll-option-id]:before {
border-radius: 3px;
}
}
}
}

View File

@ -1,94 +0,0 @@
div.poll {
display: table;
width: 100%;
box-sizing: border-box;
.poll-info {
min-width: 150px;
width: 100%;
display: table-cell;
text-align: center;
.info-number {
font-size: 3.5em;
}
p {
margin: 0.5em 0;
}
.info-label {
display: block;
}
}
.poll-container {
display: table-cell;
width: 100%;
border-right: 1px solid var(--primary-low);
}
.poll-title {
border-bottom: 1px solid var(--primary-low);
margin-bottom: 0.5em;
padding: 0.5em 0;
}
.poll-buttons {
border-top: 1px solid var(--primary-low);
padding: 1em;
display: flex;
flex-direction: row;
.info-text {
line-height: 2em;
}
button:not(:first-child) {
margin-left: 0.5em;
}
.btn-danger.toggle-status {
margin-left: auto;
}
}
}
div.poll.pie {
.poll-container {
width: calc(100% - 190px);
}
.poll-info {
display: inline-block;
width: 150px;
}
}
.d-editor-preview {
.poll-buttons {
a:not(:first-child) {
margin-left: 0.25em;
}
}
.poll {
li[data-poll-option-id]:before {
position: relative;
vertical-align: baseline;
border: 2px solid var(--primary);
border-radius: 50%;
display: inline-block;
margin-right: 0.5em;
width: 12px;
height: 12px;
content: "";
}
&[data-poll-type="multiple"] {
li[data-poll-option-id]:before {
border-radius: 3px;
}
}
}
}

View File

@ -1,46 +0,0 @@
div.poll {
.poll-buttons {
display: inline-flex;
flex-wrap: wrap;
padding: 0.5em 1em 0.5em 1em;
button {
margin: 0 0.5em 0.5em 0;
}
button + .info-text {
margin: 0.4em 0 0 0.5em;
}
}
.poll-info {
padding: 0 1em;
display: flex;
flex-wrap: wrap;
flex-direction: column;
.info-text {
display: inline;
}
.info-number {
font-size: var(--font-up-6);
}
p {
margin: 0;
width: 100%;
}
.info-label {
margin-left: 0.25em;
}
}
.poll-show-breakdown {
display: none;
}
}
div.poll.pie {
.poll-container {
width: calc(100% - 30px);
border-bottom: 1px solid var(--primary-low);
}
}

View File

@ -26,15 +26,15 @@ en:
multiple:
help:
at_least_min_options:
one: "Choose at least <strong>%{count}</strong> option."
other: "Choose at least <strong>%{count}</strong> options."
one: "Choose at least <strong>%{count} option</strong>."
other: "Choose at least <strong>%{count} options</strong>."
up_to_max_options:
one: "Choose up to <strong>%{count}</strong> option."
other: "Choose up to <strong>%{count}</strong> options."
one: "Choose up to <strong>%{count} option</strong>."
other: "Choose up to <strong>%{count} options</strong>."
x_options:
one: "Choose <strong>%{count}</strong> option."
other: "Choose <strong>%{count}</strong> options."
between_min_and_max_options: "Choose between <strong>%{min}</strong> and <strong>%{max}</strong> options."
one: "Choose <strong>%{count} option</strong>."
other: "Choose <strong>%{count} options</strong>."
between_min_and_max_options: "Choose between <strong>%{min} and %{max} options</strong>."
cast-votes:
title: "Cast your votes"
@ -42,15 +42,15 @@ en:
show-results:
title: "Display the poll results"
label: "Show results"
label: "Results"
remove-vote:
title: "Remove your vote"
label: "Remove vote"
label: "Undo vote"
hide-results:
title: "Back to your votes"
label: "Show vote"
label: "Vote"
group-results:
title: "Group votes by user field"
@ -80,6 +80,9 @@ en:
breakdown: "Breakdown"
percentage: "Percentage"
count: "Count"
options:
label: "Options"
error_while_toggling_status: "Sorry, there was an error toggling the status of this poll."
error_while_casting_votes: "Sorry, there was an error casting your votes."

View File

@ -7,8 +7,6 @@
# url: https://github.com/discourse/discourse/tree/main/plugins/poll
register_asset "stylesheets/common/poll.scss"
register_asset "stylesheets/desktop/poll.scss", :desktop
register_asset "stylesheets/mobile/poll.scss", :mobile
register_asset "stylesheets/common/poll-ui-builder.scss"
register_asset "stylesheets/desktop/poll-ui-builder.scss", :desktop
register_asset "stylesheets/common/poll-breakdown.scss"

View File

@ -93,17 +93,17 @@ RSpec.describe PrettyText do
expected = <<~HTML
<div class="poll" data-poll-status="open" data-poll-type="multiple" data-poll-name="poll">
<div>
<div class="poll-container"><ol>
<li data-poll-option-id="b6475cbf6acb8676b20c60582cfc487a">test 1 <img src="/images/emoji/twitter/slight_smile.png?v=#{Emoji::EMOJI_VERSION}" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"> <b>test</b></li>
<li data-poll-option-id="7158af352698eb1443d709818df097d4">test 2</li>
</ol>
</div>
<div class="poll-info">
<p>
<div class="poll-info_counts">
<div class="poll-info_counts-count">
<span class="info-number">0</span>
<span class="info-label">voters</span>
</p>
</div>
</div>
</div>
</div>

View File

@ -66,13 +66,14 @@ acceptance("Poll breakdown", function (needs) {
test("Displaying the poll breakdown modal", async function (assert) {
await visit("/t/-/topic_with_pie_chart_poll");
await click(".widget-dropdown-header");
assert.ok(
exists(".poll-show-breakdown"),
exists(".item-showBreakdown"),
"shows the breakdown button when poll_groupable_user_fields is non-empty"
);
await click(".poll-show-breakdown");
await click(".item-showBreakdown");
assert.ok(exists(".poll-breakdown-total-votes"), "displays the vote count");
@ -90,7 +91,8 @@ acceptance("Poll breakdown", function (needs) {
test("Changing the display mode from percentage to count", async function (assert) {
await visit("/t/-/topic_with_pie_chart_poll");
await click(".poll-show-breakdown");
await click(".widget-dropdown-header");
await click(".item-showBreakdown");
assert.strictEqual(
query(".poll-breakdown-option-count").textContent.trim(),

View File

@ -1,8 +1,8 @@
import {
acceptance,
count,
exists,
publishToMessageBus,
query,
} from "discourse/tests/helpers/qunit-helpers";
import { test } from "qunit";
import { clearPopupMenuOptionsCallback } from "discourse/controllers/composer";
@ -1156,8 +1156,9 @@ acceptance("Poll results - no voters", function (needs) {
});
});
test("disables show results button", async function (assert) {
test("does not show results button", async function (assert) {
await visit("/t/-/load-more-poll-voters");
assert.ok(query(".toggle-results").disabled);
assert.ok(!exists(".toggle-results"));
});
});