mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 05:41:15 +08:00
FIX: Quoting local dates bbcode regeneration (#17141)
This commit allows quoting of discourse-local-date elements and converts the quoted tags back into bbcode so that the rendered quote will also render the discourse-local-date HTML. This works on single dates as well as date ranges, and supports all of the options used by discourse-local-date. This also necessitated adding addTextDecorateCallback to the to-markdown core lib (similar to addBlockDecorateCallback and addTagDecorateCallback) to transform the text nodes between date ranges to remove the -> in the final quote. c.f. https://meta.discourse.org/t/quotes-that-contain-date-time/101999
This commit is contained in:
@ -14,6 +14,7 @@ import { propertyNotEqual } from "discourse/lib/computed";
|
||||
import { schedule } from "@ember/runloop";
|
||||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
import { applyLocalDates } from "discourse/lib/local-dates";
|
||||
import generateDateMarkup from "discourse/plugins/discourse-local-dates/lib/local-date-markup-generator";
|
||||
|
||||
export default Component.extend({
|
||||
timeFormat: "HH:mm:ss",
|
||||
@ -262,43 +263,7 @@ export default Component.extend({
|
||||
},
|
||||
|
||||
_generateDateMarkup(fromDateTime, options, isRange, toDateTime) {
|
||||
let text = ``;
|
||||
|
||||
if (isRange) {
|
||||
let from = [fromDateTime.date, fromDateTime.time]
|
||||
.filter((element) => !isEmpty(element))
|
||||
.join("T");
|
||||
let to = [toDateTime.date, toDateTime.time]
|
||||
.filter((element) => !isEmpty(element))
|
||||
.join("T");
|
||||
text += `[date-range from=${from} to=${to}`;
|
||||
} else {
|
||||
text += `[date=${fromDateTime.date}`;
|
||||
}
|
||||
|
||||
if (fromDateTime.time && !isRange) {
|
||||
text += ` time=${fromDateTime.time}`;
|
||||
}
|
||||
|
||||
if (fromDateTime.format && fromDateTime.format.length) {
|
||||
text += ` format="${fromDateTime.format}"`;
|
||||
}
|
||||
|
||||
if (options.timezone) {
|
||||
text += ` timezone="${options.timezone}"`;
|
||||
}
|
||||
|
||||
if (options.timezones && options.timezones.length) {
|
||||
text += ` timezones="${options.timezones.join("|")}"`;
|
||||
}
|
||||
|
||||
if (options.recurring && !isRange) {
|
||||
text += ` recurring="${options.recurring}"`;
|
||||
}
|
||||
|
||||
text += `]`;
|
||||
|
||||
return text;
|
||||
return generateDateMarkup(fromDateTime, options, isRange, toDateTime);
|
||||
},
|
||||
|
||||
@computed("advancedMode")
|
||||
|
@ -7,6 +7,11 @@ import { downloadCalendar } from "discourse/lib/download-calendar";
|
||||
import { renderIcon } from "discourse-common/lib/icon-library";
|
||||
import I18n from "I18n";
|
||||
import { hidePopover, showPopover } from "discourse/lib/d-popover";
|
||||
import {
|
||||
addTagDecorateCallback,
|
||||
addTextDecorateCallback,
|
||||
} from "discourse/lib/to-markdown";
|
||||
import generateDateMarkup from "discourse/plugins/discourse-local-dates/lib/local-date-markup-generator";
|
||||
|
||||
// Import applyLocalDates from discourse/lib/local-dates instead
|
||||
export function applyLocalDates(dates, siteSettings) {
|
||||
@ -66,6 +71,24 @@ function buildOptionsFromElement(element, siteSettings) {
|
||||
return opts;
|
||||
}
|
||||
|
||||
function buildOptionsFromMarkdownTag(element) {
|
||||
const opts = {};
|
||||
|
||||
// siteSettings defaults as used by buildOptionsFromElement are purposefully
|
||||
// ommitted to reproduce exactly what was on the original element
|
||||
opts.time = element.attributes["data-time"];
|
||||
opts.date = element.attributes["data-date"];
|
||||
opts.recurring = element.attributes["data-recurring"];
|
||||
opts.timezones = element.attributes["data-timezones"];
|
||||
opts.timezone = element.attributes["data-timezone"];
|
||||
opts.calendar = (element.attributes["data-calendar"] || "on") === "on";
|
||||
opts.displayedTimezone = element.attributes["data-displayed-timezone"];
|
||||
opts.format = element.attributes["data-format"];
|
||||
opts.countdown = element.attributes["data-countdown"];
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
function _rangeElements(element) {
|
||||
if (!element.parentElement) {
|
||||
return [];
|
||||
@ -128,6 +151,60 @@ function initializeDiscourseLocalDates(api) {
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
addTextDecorateCallback(function (
|
||||
text,
|
||||
nextElement,
|
||||
_previousElement,
|
||||
metadata
|
||||
) {
|
||||
if (
|
||||
metadata.discourseLocalDateStartRangeOpts &&
|
||||
nextElement?.attributes.class?.includes("discourse-local-date") &&
|
||||
text === "→"
|
||||
) {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
addTagDecorateCallback(function () {
|
||||
if (this.element.attributes.class?.includes("discourse-local-date")) {
|
||||
if (this.metadata.discourseLocalDateStartRangeOpts) {
|
||||
const startRangeOpts = this.metadata.discourseLocalDateStartRangeOpts;
|
||||
const endRangeOpts = buildOptionsFromMarkdownTag(this.element);
|
||||
const markup = generateDateMarkup(
|
||||
{
|
||||
date: startRangeOpts.date,
|
||||
time: startRangeOpts.time,
|
||||
format: startRangeOpts.format,
|
||||
},
|
||||
endRangeOpts,
|
||||
true,
|
||||
{
|
||||
date: endRangeOpts.date,
|
||||
time: endRangeOpts.time,
|
||||
format: endRangeOpts.format,
|
||||
}
|
||||
);
|
||||
this.prefix = markup;
|
||||
this.metadata.discourseLocalDateStartRangeOpts = null;
|
||||
return "";
|
||||
}
|
||||
if (this.element.attributes["data-range"] === "true") {
|
||||
this.metadata.discourseLocalDateStartRangeOpts = buildOptionsFromMarkdownTag(
|
||||
this.element
|
||||
);
|
||||
return "";
|
||||
}
|
||||
const opts = buildOptionsFromMarkdownTag(this.element, siteSettings);
|
||||
const markup = generateDateMarkup(
|
||||
{ date: opts.date, time: opts.time, format: opts.format },
|
||||
opts,
|
||||
false
|
||||
);
|
||||
this.prefix = markup;
|
||||
return "";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function buildHtmlPreview(element, siteSettings) {
|
||||
|
@ -0,0 +1,58 @@
|
||||
import { isEmpty } from "@ember/utils";
|
||||
|
||||
export default function generateDateMarkup(
|
||||
fromDateTime,
|
||||
options,
|
||||
isRange,
|
||||
toDateTime
|
||||
) {
|
||||
let text = ``;
|
||||
|
||||
if (isRange) {
|
||||
let from = [fromDateTime.date, fromDateTime.time]
|
||||
.filter((element) => !isEmpty(element))
|
||||
.join("T");
|
||||
let to = [toDateTime.date, toDateTime.time]
|
||||
.filter((element) => !isEmpty(element))
|
||||
.join("T");
|
||||
text += `[date-range from=${from} to=${to}`;
|
||||
} else {
|
||||
text += `[date=${fromDateTime.date}`;
|
||||
}
|
||||
|
||||
if (fromDateTime.time && !isRange) {
|
||||
text += ` time=${fromDateTime.time}`;
|
||||
}
|
||||
|
||||
if (fromDateTime.format && fromDateTime.format.length) {
|
||||
text += ` format="${fromDateTime.format}"`;
|
||||
}
|
||||
|
||||
if (options.timezone) {
|
||||
text += ` timezone="${options.timezone}"`;
|
||||
}
|
||||
|
||||
if (options.countdown) {
|
||||
text += ` countdown="${options.countdown}"`;
|
||||
}
|
||||
|
||||
if (options.displayedTimezone) {
|
||||
text += ` displayedTimezone="${options.displayedTimezone}"`;
|
||||
}
|
||||
|
||||
if (options.timezones && options.timezones.length) {
|
||||
if (Array.isArray(options.timezones)) {
|
||||
text += ` timezones="${options.timezones.join("|")}"`;
|
||||
} else {
|
||||
text += ` timezones="${options.timezones}"`;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.recurring && !isRange) {
|
||||
text += ` recurring="${options.recurring}"`;
|
||||
}
|
||||
|
||||
text += `]`;
|
||||
|
||||
return text;
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
import { cloneJSON } from "discourse-common/lib/object";
|
||||
import topicFixtures from "discourse/tests/fixtures/topic";
|
||||
import {
|
||||
acceptance,
|
||||
queryAll,
|
||||
selectText,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { click, visit } from "@ember/test-helpers";
|
||||
|
||||
acceptance("Local Dates - quoting", function (needs) {
|
||||
needs.user();
|
||||
needs.settings({ discourse_local_dates_enabled: true });
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
const topicResponse = cloneJSON(topicFixtures["/t/280/1.json"]);
|
||||
const firstPost = topicResponse.post_stream.posts[0];
|
||||
firstPost.cooked += `<div class='select-local-date-test'>This is a test <span data-date="2022-06-17" data-time="10:00:00" class="discourse-local-date cooked-date past" data-displayed-timezone="Australia/Perth" data-timezone="Australia/Brisbane" data-email-preview="2022-06-17T00:00:00Z UTC" aria-label="Brisbane Friday, June 17, 2022
|
||||
<br />
|
||||
<svg class='fa d-icon d-icon-clock svg-icon svg-string'
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<use href="#clock" />
|
||||
</svg> 10:00 AM, Paris Friday, June 17, 2022
|
||||
<br />
|
||||
<svg class='fa d-icon d-icon-clock svg-icon svg-string'
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<use href="#clock" />
|
||||
</svg> 2:00 AM, Los Angeles Thursday, June 16, 2022
|
||||
<br />
|
||||
<svg class='fa d-icon d-icon-clock svg-icon svg-string'
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<use href="#clock" />
|
||||
</svg> 5:00 PM" data-title="This is a new topic to check on chat quote issues">
|
||||
<svg class="fa d-icon d-icon-globe-americas svg-icon" xmlns="http://www.w3.org/2000/svg">
|
||||
<use href="#globe-americas"></use>
|
||||
</svg>
|
||||
<span class="relative-time">June 17, 2022 8:00 AM (Perth)</span>
|
||||
</span></div>`;
|
||||
|
||||
server.get("/t/280.json", () => helper.response(topicResponse));
|
||||
server.get("/t/280/:post_number.json", () => {
|
||||
helper.response(topicResponse);
|
||||
});
|
||||
});
|
||||
|
||||
test("quoting single local dates with basic options", async function (assert) {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await selectText("#post_1 .select-local-date-test");
|
||||
await click(".insert-quote");
|
||||
assert.strictEqual(
|
||||
queryAll(".d-editor-input").val().trim(),
|
||||
`[quote=\"Uwe Keim, post:1, topic:280, username:uwe_keim\"]
|
||||
This is a test [date=2022-06-17 time=10:00:00 timezone="Australia/Brisbane" displayedTimezone="Australia/Perth"]
|
||||
[/quote]`,
|
||||
"converts the date to markdown with all options correctly"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
acceptance("Local Dates - quoting range", function (needs) {
|
||||
needs.user();
|
||||
needs.settings({ discourse_local_dates_enabled: true });
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
const topicResponse = cloneJSON(topicFixtures["/t/280/1.json"]);
|
||||
const firstPost = topicResponse.post_stream.posts[0];
|
||||
firstPost.cooked += `<div class='select-local-date-test'><p dir="ltr">Some text <span data-date="2022-06-17" data-time="09:30:00" class="discourse-local-date cooked-date past" data-format="LL" data-range="true" data-timezones="Africa/Accra|Australia/Brisbane|Europe/Paris" data-timezone="Australia/Brisbane" data-email-preview="2022-06-16T23:30:00Z UTC" aria-label="Brisbane Friday, June 17, 2022 9:30 AM → Saturday, June 18, 2022 10:30 AM, Accra Thursday, June 16, 2022 11:30 PM → Saturday, June 18, 2022 12:30 AM, Paris Friday, June 17, 2022 1:30 AM → Saturday, June 18, 2022 2:30 AM" data-title="This is a new topic to check on chat quote issues">
|
||||
<svg class="fa d-icon d-icon-globe-americas svg-icon" xmlns="http://www.w3.org/2000/svg">
|
||||
<use href="#globe-americas"></use>
|
||||
</svg>
|
||||
<span class="relative-time">June 17, 2022</span>
|
||||
</span>→<span data-date="2022-06-18" data-time="10:30:00" class="discourse-local-date cooked-date past" data-format="LL" data-range="true" data-timezones="Africa/Accra|Australia/Brisbane|Europe/Paris" data-timezone="Australia/Brisbane" data-email-preview="2022-06-18T00:30:00Z UTC" aria-label="Brisbane Friday, June 17, 2022 9:30 AM → Saturday, June 18, 2022 10:30 AM, Accra Thursday, June 16, 2022 11:30 PM → Saturday, June 18, 2022 12:30 AM, Paris Friday, June 17, 2022 1:30 AM → Saturday, June 18, 2022 2:30 AM" data-title="This is a new topic to check on chat quote issues">
|
||||
<svg class="fa d-icon d-icon-globe-americas svg-icon" xmlns="http://www.w3.org/2000/svg">
|
||||
<use href="#globe-americas"></use>
|
||||
</svg>
|
||||
<span class="relative-time">June 18, 2022</span>
|
||||
</span></p></div>`;
|
||||
|
||||
server.get("/t/280.json", () => helper.response(topicResponse));
|
||||
server.get("/t/280/:post_number.json", () => {
|
||||
helper.response(topicResponse);
|
||||
});
|
||||
});
|
||||
|
||||
test("quoting a range of local dates", async function (assert) {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await selectText("#post_1 .select-local-date-test");
|
||||
await click(".insert-quote");
|
||||
assert.strictEqual(
|
||||
queryAll(".d-editor-input").val().trim(),
|
||||
`[quote=\"Uwe Keim, post:1, topic:280, username:uwe_keim\"]
|
||||
Some text [date-range from=2022-06-17T09:30:00 to=2022-06-18T10:30:00 format="LL" timezone="Australia/Brisbane" timezones="Africa/Accra|Australia/Brisbane|Europe/Paris"]
|
||||
[/quote]`,
|
||||
"converts the date range to markdown with all options correctly"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
acceptance("Local Dates - quoting with recurring and countdown", function (needs) {
|
||||
needs.user();
|
||||
needs.settings({ discourse_local_dates_enabled: true });
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
const topicResponse = cloneJSON(topicFixtures["/t/280/1.json"]);
|
||||
const firstPost = topicResponse.post_stream.posts[0];
|
||||
firstPost.cooked += `<div class='select-local-date-test'><p dir="ltr">Testing countdown <span data-date="2022-06-21" data-time="09:30:00" class="discourse-local-date cooked-date" data-format="LL" data-countdown="true" data-timezone="Australia/Brisbane" data-email-preview="2022-06-20T23:30:00Z UTC" aria-label="Brisbane Tuesday, June 21, 2022 <br /><svg class='fa d-icon d-icon-clock svg-icon svg-string' xmlns="http://www.w3.org/2000/svg"><use href="#clock" /></svg> 9:30 AM, Paris Tuesday, June 21, 2022 <br /><svg class='fa d-icon d-icon-clock svg-icon svg-string' xmlns="http://www.w3.org/2000/svg"><use href="#clock" /></svg> 1:30 AM, Los Angeles Monday, June 20, 2022 <br /><svg class='fa d-icon d-icon-clock svg-icon svg-string' xmlns="http://www.w3.org/2000/svg"><use href="#clock" /></svg> 4:30 PM" data-title="This is a new topic to check on chat quote issues">
|
||||
<svg class="fa d-icon d-icon-globe-americas svg-icon" xmlns="http://www.w3.org/2000/svg">
|
||||
<use href="#globe-americas"></use>
|
||||
</svg>
|
||||
<span class="relative-time">21 hours</span>
|
||||
</span></p>
|
||||
<p dir="ltr">Testing recurring <span data-date="2022-06-22" class="discourse-local-date cooked-date" data-timezone="Australia/Brisbane" data-recurring="2.weeks" data-email-preview="2022-06-21T14:00:00Z UTC" aria-label="Brisbane Wednesday, June 22, 2022 12:00 AM → Thursday, June 23, 2022 12:00 AM, Paris Tuesday, June 21, 2022 4:00 PM → Wednesday, June 22, 2022 4:00 PM, Los Angeles Tuesday, June 21, 2022 7:00 AM → Wednesday, June 22, 2022 7:00 AM" data-title="This is a new topic to check on chat quote issues">
|
||||
<svg class="fa d-icon d-icon-globe-americas svg-icon" xmlns="http://www.w3.org/2000/svg">
|
||||
<use href="#globe-americas"></use>
|
||||
</svg>
|
||||
<span class="relative-time">Wednesday</span>
|
||||
</span></p></div>`;
|
||||
|
||||
server.get("/t/280.json", () => helper.response(topicResponse));
|
||||
server.get("/t/280/:post_number.json", () => {
|
||||
helper.response(topicResponse);
|
||||
});
|
||||
});
|
||||
|
||||
test("quoting single local dates with recurring and countdown options", async function (assert) {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await selectText("#post_1 .select-local-date-test");
|
||||
await click(".insert-quote");
|
||||
assert.strictEqual(
|
||||
queryAll(".d-editor-input").val().trim(),
|
||||
`[quote=\"Uwe Keim, post:1, topic:280, username:uwe_keim\"]
|
||||
Testing countdown [date=2022-06-21 time=09:30:00 format="LL" timezone="Australia/Brisbane" countdown="true"]
|
||||
|
||||
Testing recurring [date=2022-06-22 timezone="Australia/Brisbane" recurring="2.weeks"]
|
||||
[/quote]`,
|
||||
"converts the dates to markdown with all options correctly"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user