Skip to content

Commit

Permalink
FIX: Quoting local dates bbcode regeneration (#17141)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
martin-brennan committed Jun 21, 2022
1 parent fd294a6 commit 54a518b
Show file tree
Hide file tree
Showing 7 changed files with 331 additions and 44 deletions.
57 changes: 51 additions & 6 deletions app/assets/javascripts/discourse/app/lib/to-markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ const MSO_LIST_CLASSES = [

let tagDecorateCallbacks = [];
let blockDecorateCallbacks = [];
let textDecorateCallbacks = [];

/**
* Allows to add support for custom inline markdown/bbcode
* Allows to add support for custom inline markdown/bbcode prefixes
* to convert nodes back to bbcode.
*
* ```
* addTagDecorateCallback(function (text) {
Expand All @@ -29,7 +31,8 @@ export function clearTagDecorateCallbacks() {
}

/**
* Allows to add support for custom block markdown/bbcode
* Allows to add support for custom block markdown/bbcode prefixes
* to convert nodes back to bbcode.
*
* ```
* addBlockDecorateCallback(function (text) {
Expand All @@ -48,6 +51,30 @@ export function clearBlockDecorateCallbacks() {
blockDecorateCallbacks = [];
}

/**
* Allows to add support for custom text node transformations
* based on the next/previous elements.
*
* ```
* addTextDecorateCallback(function (text, nextElement, previousElement) {
* if (
* startRangeOpts &&
* nextElement?.attributes.class?.includes("discourse-local-date") &&
* text === "→"
* ) {
* return "";
* }
* });
* ```
*/
export function addTextDecorateCallback(callback) {
textDecorateCallbacks.push(callback);
}

export function clearTextDecorateCallbacks() {
textDecorateCallbacks = [];
}

export class Tag {
static named(name) {
const klass = class NamedTag extends Tag {};
Expand Down Expand Up @@ -657,9 +684,10 @@ function tagByName(name) {
}

class Element {
constructor(element, parent, previous, next) {
constructor(element, parent, previous, next, metadata) {
this.name = element.name;
this.data = element.data;
this.metadata = metadata;
this.children = element.children;
this.attributes = element.attributes;

Expand All @@ -682,6 +710,7 @@ class Element {
tag() {
const tag = new (tagByName(this.name) || Tag)();
tag.element = this;
tag.metadata = this.metadata;
return tag;
}

Expand Down Expand Up @@ -709,6 +738,19 @@ class Element {
}

text = text.replace(/[\s\t]+/g, " ");
textDecorateCallbacks.forEach((callback) => {
const result = callback.call(
this,
text,
this.next,
this.previous,
this.metadata
);

if (typeof result !== "undefined") {
text = result;
}
});

return text;
}
Expand All @@ -721,8 +763,8 @@ class Element {
return this.parentNames.filter((p) => names.includes(p));
}

static toMarkdown(element, parent, prev, next) {
return new Element(element, parent, prev, next).toMarkdown();
static toMarkdown(element, parent, prev, next, metadata) {
return new Element(element, parent, prev, next, metadata).toMarkdown();
}

static parseChildren(parent) {
Expand All @@ -732,12 +774,15 @@ class Element {
static parse(elements, parent = null) {
if (elements) {
let result = [];
let metadata = {};

for (let i = 0; i < elements.length; i++) {
const prev = i === 0 ? null : elements[i - 1];
const next = i === elements.length ? null : elements[i + 1];

result.push(Element.toMarkdown(elements[i], parent, prev, next));
result.push(
Element.toMarkdown(elements[i], parent, prev, next, metadata)
);
}

return result.join("");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import { resetDefaultSectionLinks as resetTopicsSectionLinks } from "discourse/l
import {
clearBlockDecorateCallbacks,
clearTagDecorateCallbacks,
clearTextDecorateCallbacks,
} from "discourse/lib/to-markdown";

const LEGACY_ENV = !setupApplicationTest;
Expand Down Expand Up @@ -194,6 +195,7 @@ function testCleanup(container, app) {
resetTopicsSectionLinks();
clearTagDecorateCallbacks();
clearBlockDecorateCallbacks();
clearTextDecorateCallbacks();
}

export function discourseModule(name, options) {
Expand Down
2 changes: 1 addition & 1 deletion docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Adds `beforeToMarkdownTagDecorate` and `beforeToMarkdownBlockDecorate` that allow to modify to-markdown behavior.
- N/A - Mistakenly bumped.

## [1.2.0] - 2022-03-18

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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 [];
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
Loading

0 comments on commit 54a518b

Please sign in to comment.