REFACTOR: improve poll info layout (#22353)
This commit is contained in:
parent
d75d64bf16
commit
4cec091f1a
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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."
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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"));
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue