mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 05:31:14 +08:00
FEATURE: refactoring and better handling of special cases (#6666)
This commit is contained in:
@ -1,141 +0,0 @@
|
||||
(function($) {
|
||||
$.fn.applyLocalDates = function(repeat) {
|
||||
function _formatTimezone(timezone) {
|
||||
return timezone.replace("_", " ").split("/");
|
||||
}
|
||||
|
||||
function processElement($element, options) {
|
||||
repeat = repeat || true;
|
||||
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
|
||||
var relativeTime;
|
||||
|
||||
var dateAndTime = options.date;
|
||||
if (options.time) {
|
||||
dateAndTime = dateAndTime + " " + options.time;
|
||||
}
|
||||
|
||||
if (options.timezone) {
|
||||
relativeTime = moment.tz(dateAndTime, options.timezone).utc();
|
||||
} else {
|
||||
relativeTime = moment.utc(dateAndTime);
|
||||
}
|
||||
|
||||
if (relativeTime < moment().utc()) {
|
||||
if (options.recurring) {
|
||||
var parts = options.recurring.split(".");
|
||||
var count = parseInt(parts[0], 10);
|
||||
var type = parts[1];
|
||||
var diff = moment().diff(relativeTime, type);
|
||||
var add = Math.ceil(diff + count);
|
||||
|
||||
relativeTime = relativeTime.add(add, type);
|
||||
} else {
|
||||
$element.addClass("past");
|
||||
}
|
||||
}
|
||||
|
||||
var previews = options.timezones.split("|").map(function(timezone) {
|
||||
var dateTime = relativeTime.tz(timezone).format(options.format);
|
||||
|
||||
var timezoneParts = _formatTimezone(timezone);
|
||||
|
||||
if (dateTime.match(/TZ/)) {
|
||||
return dateTime.replace("TZ", timezoneParts.join(": "));
|
||||
} else {
|
||||
var output = timezoneParts[0];
|
||||
if (timezoneParts[1]) {
|
||||
output += " (" + timezoneParts[1] + ")";
|
||||
}
|
||||
output += " " + dateTime;
|
||||
return output;
|
||||
}
|
||||
});
|
||||
|
||||
var relativeTime = relativeTime.tz(options.displayedZone);
|
||||
|
||||
var d = function(key) {
|
||||
var translated = I18n.t("discourse_local_dates.relative_dates." + key, {
|
||||
time: "LT"
|
||||
});
|
||||
|
||||
if (options.time) {
|
||||
return translated
|
||||
.split("LT")
|
||||
.map(function(w) {
|
||||
return "[" + w + "]";
|
||||
})
|
||||
.join("LT");
|
||||
} else {
|
||||
return "[" + translated.replace(" LT", "") + "]";
|
||||
}
|
||||
};
|
||||
|
||||
var relativeFormat = {
|
||||
sameDay: d("today"),
|
||||
nextDay: d("tomorrow"),
|
||||
lastDay: d("yesterday"),
|
||||
sameElse: "L"
|
||||
};
|
||||
|
||||
if (
|
||||
options.calendar &&
|
||||
relativeTime.isBetween(
|
||||
moment().subtract(1, "day"),
|
||||
moment().add(2, "day")
|
||||
)
|
||||
) {
|
||||
relativeTime = relativeTime.calendar(null, relativeFormat);
|
||||
} else {
|
||||
relativeTime = relativeTime.format(options.format);
|
||||
}
|
||||
|
||||
var html = "<span>";
|
||||
html += "<i class='fa fa-globe d-icon d-icon-globe'></i>";
|
||||
html += "<span class='relative-time'></span>";
|
||||
html += "</span>";
|
||||
|
||||
var joinedPreviews = previews.join("\n");
|
||||
|
||||
var displayedTime = relativeTime.replace(
|
||||
"TZ",
|
||||
_formatTimezone(options.displayedZone).join(": ")
|
||||
);
|
||||
|
||||
$element
|
||||
.html(html)
|
||||
.attr("title", joinedPreviews)
|
||||
.attr("data-tooltip", joinedPreviews)
|
||||
.addClass("cooked-date")
|
||||
.find(".relative-time")
|
||||
.text(displayedTime);
|
||||
|
||||
if (repeat) {
|
||||
this.timeout = setTimeout(function() {
|
||||
processElement($element, options);
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
return this.each(function() {
|
||||
var $this = $(this);
|
||||
|
||||
var options = {};
|
||||
options.time = $this.attr("data-time");
|
||||
options.format =
|
||||
$this.attr("data-format") || (options.time ? "LLL" : "LL");
|
||||
options.date = $this.attr("data-date");
|
||||
options.recurring = $this.attr("data-recurring");
|
||||
options.timezones = $this.attr("data-timezones") || "Etc/UTC";
|
||||
options.timezone = $this.attr("data-timezone");
|
||||
options.calendar = ($this.attr("data-calendar") || "on") === "on";
|
||||
options.displayedZone =
|
||||
$this.attr("data-displayed-zone") || moment.tz.guess();
|
||||
|
||||
processElement($this, options);
|
||||
});
|
||||
};
|
||||
})(jQuery);
|
@ -0,0 +1,283 @@
|
||||
(function($) {
|
||||
$.fn.applyLocalDates = function(repeat) {
|
||||
const processElement = ($element, options = {}) => {
|
||||
if (this.timeout) clearTimeout(this.timeout);
|
||||
|
||||
repeat = repeat || true;
|
||||
const utc = moment().utc();
|
||||
const dateTime = options.time
|
||||
? `${options.date} ${options.time}`
|
||||
: options.date;
|
||||
let utcDateTime;
|
||||
|
||||
let displayedTimezone;
|
||||
if (options.time) {
|
||||
displayedTimezone = options.displayedTimezone || moment.tz.guess();
|
||||
} else {
|
||||
displayedTimezone =
|
||||
options.displayedTimezone || options.timezone || moment.tz.guess();
|
||||
}
|
||||
|
||||
// if timezone given we convert date and time from given zone to Etc/UTC
|
||||
if (options.timezone) {
|
||||
utcDateTime = _applyZoneToDateTime(dateTime, options.timezone);
|
||||
} else {
|
||||
utcDateTime = moment.utc(dateTime);
|
||||
}
|
||||
|
||||
if (utcDateTime < utc) {
|
||||
// if event is in the past we want to bump it no next occurrence when
|
||||
// recurring is set
|
||||
if (options.recurring) {
|
||||
utcDateTime = _applyRecurrence(utcDateTime, options.recurring);
|
||||
} else {
|
||||
$element.addClass("past");
|
||||
}
|
||||
}
|
||||
|
||||
// once we have the correct UTC date we want
|
||||
// we adjust it to watching user timezone
|
||||
const adjustedDateTime = utcDateTime.tz(displayedTimezone);
|
||||
|
||||
const previews = _generatePreviews(
|
||||
adjustedDateTime.clone(),
|
||||
displayedTimezone,
|
||||
options
|
||||
);
|
||||
const textPreview = _generateTextPreview(previews);
|
||||
const htmlPreview = _generateHtmlPreview(previews);
|
||||
|
||||
const formatedDateTime = _applyFormatting(
|
||||
adjustedDateTime,
|
||||
displayedTimezone,
|
||||
options
|
||||
);
|
||||
|
||||
const $dateTemplate = `
|
||||
<span>
|
||||
<i class="fa fa-globe d-icon d-icon-globe"></i>
|
||||
<span class="relative-time"></span>
|
||||
</span>
|
||||
`;
|
||||
|
||||
$element
|
||||
.html($dateTemplate)
|
||||
.attr("title", textPreview)
|
||||
.attr("data-html-tooltip", `<div class="previews">${htmlPreview}</div>`)
|
||||
.addClass("cooked-date")
|
||||
.find(".relative-time")
|
||||
.text(formatedDateTime);
|
||||
|
||||
if (repeat) {
|
||||
this.timeout = setTimeout(
|
||||
() => processElement($element, options),
|
||||
10000
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const _formatTimezone = timezone =>
|
||||
timezone
|
||||
.replace("_", " ")
|
||||
.replace("Etc/", "")
|
||||
.split("/");
|
||||
|
||||
const _applyZoneToDateTime = (dateTime, timezone) => {
|
||||
return moment.tz(dateTime, timezone).utc();
|
||||
};
|
||||
|
||||
const _calendarFormats = time => {
|
||||
const _translate = key => {
|
||||
const translated = I18n.t(
|
||||
`discourse_local_dates.relative_dates.${key}`,
|
||||
{
|
||||
time: "LT"
|
||||
}
|
||||
);
|
||||
|
||||
if (time) {
|
||||
return translated
|
||||
.split("LT")
|
||||
.map(w => `[${w}]`)
|
||||
.join("LT");
|
||||
} else {
|
||||
return `[${translated.replace(" LT", "")}]`;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
sameDay: _translate("today"),
|
||||
nextDay: _translate("tomorrow"),
|
||||
lastDay: _translate("yesterday"),
|
||||
sameElse: "L"
|
||||
};
|
||||
};
|
||||
|
||||
const _applyFormatting = (dateTime, displayedTimezone, options) => {
|
||||
const sameTimezone = displayedTimezone === moment.tz.guess();
|
||||
const inCalendarRange = dateTime.isBetween(
|
||||
moment().subtract(2, "days"),
|
||||
moment().add(2, "days")
|
||||
);
|
||||
|
||||
if (options.calendar && inCalendarRange) {
|
||||
if (sameTimezone) {
|
||||
if (options.time) {
|
||||
dateTime = dateTime.calendar(null, _calendarFormats(options.time));
|
||||
} else {
|
||||
dateTime = dateTime.calendar(null, _calendarFormats(null));
|
||||
}
|
||||
} else {
|
||||
dateTime = dateTime.format(options.format);
|
||||
dateTime = dateTime.replace("TZ", "");
|
||||
dateTime = `${dateTime} (${_formatTimezone(displayedTimezone).join(
|
||||
": "
|
||||
)})`;
|
||||
}
|
||||
} else {
|
||||
if (options.time) {
|
||||
dateTime = dateTime.format(options.format);
|
||||
|
||||
if (options.displayedTimezone && !sameTimezone) {
|
||||
dateTime = dateTime.replace("TZ", "");
|
||||
dateTime = `${dateTime} (${_formatTimezone(displayedTimezone).join(
|
||||
": "
|
||||
)})`;
|
||||
} else {
|
||||
dateTime = dateTime.replace(
|
||||
"TZ",
|
||||
_formatTimezone(displayedTimezone).join(": ")
|
||||
);
|
||||
}
|
||||
} else {
|
||||
dateTime = dateTime.format(options.format);
|
||||
|
||||
if (!sameTimezone) {
|
||||
dateTime = dateTime.replace("TZ", "");
|
||||
dateTime = `${dateTime} (${_formatTimezone(displayedTimezone).join(
|
||||
": "
|
||||
)})`;
|
||||
} else {
|
||||
dateTime = dateTime.replace(
|
||||
"TZ",
|
||||
_formatTimezone(displayedTimezone).join(": ")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dateTime;
|
||||
};
|
||||
|
||||
const _applyRecurrence = (dateTime, recurring) => {
|
||||
const parts = recurring.split(".");
|
||||
const count = parseInt(parts[0], 10);
|
||||
const type = parts[1];
|
||||
const diff = moment().diff(dateTime, type);
|
||||
const add = Math.ceil(diff + count);
|
||||
|
||||
return dateTime.add(add, type);
|
||||
};
|
||||
|
||||
const createDateTimeRange = (dateTime, timezone) => {
|
||||
const startRange = dateTime.tz(timezone).format("LLL");
|
||||
const separator = "→";
|
||||
const endRange = dateTime
|
||||
.add(24, "hours")
|
||||
.tz(timezone)
|
||||
.format("LLL");
|
||||
|
||||
return `${startRange} ${separator} ${endRange}`;
|
||||
};
|
||||
|
||||
const _generatePreviews = (dateTime, displayedTimezone, options) => {
|
||||
const previewedTimezones = [];
|
||||
const watchingUserTimezone = moment.tz.guess();
|
||||
|
||||
if (displayedTimezone !== watchingUserTimezone) {
|
||||
previewedTimezones.push({
|
||||
timezone: watchingUserTimezone,
|
||||
current: true,
|
||||
dateTime: options.time
|
||||
? dateTime.tz(watchingUserTimezone).format("LLL")
|
||||
: createDateTimeRange(dateTime, watchingUserTimezone)
|
||||
});
|
||||
}
|
||||
|
||||
options.timezones
|
||||
.filter(x => x !== watchingUserTimezone)
|
||||
.forEach(timezone => {
|
||||
previewedTimezones.push({
|
||||
timezone,
|
||||
dateTime: options.time
|
||||
? dateTime.tz(timezone).format("LLL")
|
||||
: createDateTimeRange(dateTime, timezone)
|
||||
});
|
||||
});
|
||||
|
||||
return previewedTimezones;
|
||||
};
|
||||
|
||||
const _generateTextPreview = previews => {
|
||||
return previews
|
||||
.map(preview => {
|
||||
const timezoneParts = _formatTimezone(preview.timezone);
|
||||
|
||||
if (preview.dateTime.match(/TZ/)) {
|
||||
return preview.dateTime.replace(/TZ/, timezoneParts.join(": "));
|
||||
} else {
|
||||
let output = timezoneParts[0];
|
||||
if (timezoneParts[1]) output += ` (${timezoneParts[1]})`;
|
||||
return (output += ` ${preview.dateTime}`);
|
||||
}
|
||||
})
|
||||
.join(", ");
|
||||
};
|
||||
|
||||
const _generateHtmlPreview = previews => {
|
||||
const $htmlTooltip = $("<div></div>");
|
||||
|
||||
const $previewTemplate = $(`
|
||||
<div class='preview'>
|
||||
<span class='timezone'></span>
|
||||
<span class='date-time'></span>
|
||||
</div>
|
||||
`);
|
||||
|
||||
previews.forEach(preview => {
|
||||
const $template = $previewTemplate.clone();
|
||||
|
||||
if (preview.current) $template.addClass("current");
|
||||
|
||||
$template
|
||||
.find(".timezone")
|
||||
.text(_formatTimezone(preview.timezone).join(": "));
|
||||
$template.find(".date-time").text(preview.dateTime);
|
||||
$htmlTooltip.append($template);
|
||||
});
|
||||
|
||||
return $htmlTooltip.html();
|
||||
};
|
||||
|
||||
return this.each(function() {
|
||||
const $element = $(this);
|
||||
|
||||
const options = {};
|
||||
options.time = $element.attr("data-time");
|
||||
options.date = $element.attr("data-date");
|
||||
options.recurring = $element.attr("data-recurring");
|
||||
options.timezones = (
|
||||
$element.attr("data-timezones") ||
|
||||
Discourse.SiteSettings.discourse_local_dates_default_timezones ||
|
||||
"Etc/UTC"
|
||||
).split("|");
|
||||
options.timezone = $element.attr("data-timezone");
|
||||
options.calendar = ($element.attr("data-calendar") || "on") === "on";
|
||||
options.displayedTimezone = $element.attr("data-displayed-timezone");
|
||||
options.format =
|
||||
$element.attr("data-format") || (options.time ? "LLL" : "LL");
|
||||
|
||||
processElement($element, options);
|
||||
});
|
||||
};
|
||||
})(jQuery);
|
@ -14,18 +14,13 @@ export default Ember.Component.extend({
|
||||
formats: null,
|
||||
recurring: null,
|
||||
advancedMode: false,
|
||||
isValid: true,
|
||||
|
||||
init() {
|
||||
this._super();
|
||||
|
||||
this.set("date", moment().format(this.dateFormat));
|
||||
this.set("format", `LLL`);
|
||||
this.set(
|
||||
"timezones",
|
||||
(this.siteSettings.discourse_local_dates_default_timezones || "")
|
||||
.split("|")
|
||||
.filter(f => f)
|
||||
);
|
||||
this.set("timezones", []);
|
||||
this.set(
|
||||
"formats",
|
||||
(this.siteSettings.discourse_local_dates_default_formats || "")
|
||||
@ -34,10 +29,9 @@ export default Ember.Component.extend({
|
||||
);
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super();
|
||||
|
||||
this._setConfig();
|
||||
@observes("date", "time", "toDate", "toTime")
|
||||
_resetFormValidity() {
|
||||
this.set("isValid", true);
|
||||
},
|
||||
|
||||
@computed
|
||||
@ -74,44 +68,30 @@ export default Ember.Component.extend({
|
||||
return moment.tz.names();
|
||||
},
|
||||
|
||||
@observes(
|
||||
"date",
|
||||
"time",
|
||||
"toDate",
|
||||
"toTime",
|
||||
"recurring",
|
||||
"format",
|
||||
"timezones"
|
||||
)
|
||||
_setConfig() {
|
||||
const toTime = this.get("toTime");
|
||||
getConfig(range) {
|
||||
const endOfRange = range && range === "end";
|
||||
const time = endOfRange ? this.get("toTime") : this.get("time");
|
||||
let date = endOfRange ? this.get("toDate") : this.get("date");
|
||||
|
||||
if (toTime && !this.get("toDate")) {
|
||||
this.set("toDate", moment().format(this.dateFormat));
|
||||
if (endOfRange && time && !date) {
|
||||
date = moment().format(this.dateFormat);
|
||||
}
|
||||
|
||||
const date = this.get("date");
|
||||
const toDate = this.get("toDate");
|
||||
const time = this.get("time");
|
||||
const recurring = this.get("recurring");
|
||||
const format = this.get("format");
|
||||
const timezones = this.get("timezones");
|
||||
const timeInferred = time ? false : true;
|
||||
const toTimeInferred = toTime ? false : true;
|
||||
const timezone = this.get("currentUserTimezone");
|
||||
|
||||
let dateTime;
|
||||
if (!timeInferred) {
|
||||
dateTime = moment.tz(`${date} ${time}`, timezone).utc();
|
||||
dateTime = moment.tz(`${date} ${time}`, timezone);
|
||||
} else {
|
||||
dateTime = moment.tz(date, timezone).utc();
|
||||
}
|
||||
|
||||
let toDateTime;
|
||||
if (!toTimeInferred) {
|
||||
toDateTime = moment.tz(`${toDate} ${toTime}`, timezone);
|
||||
} else {
|
||||
toDateTime = moment.tz(toDate, timezone).endOf("day");
|
||||
if (endOfRange) {
|
||||
dateTime = moment.tz(date, timezone).endOf("day");
|
||||
} else {
|
||||
dateTime = moment.tz(date, timezone);
|
||||
}
|
||||
}
|
||||
|
||||
let config = {
|
||||
@ -127,82 +107,64 @@ export default Ember.Component.extend({
|
||||
config.time = dateTime.format(this.timeFormat);
|
||||
}
|
||||
|
||||
if (!toTimeInferred) {
|
||||
config.toTime = toDateTime.format(this.timeFormat);
|
||||
if (timeInferred) {
|
||||
config.displayedTimezone = this.get("currentUserTimezone");
|
||||
}
|
||||
|
||||
if (toDate) {
|
||||
config.toDate = toDateTime.format(this.dateFormat);
|
||||
}
|
||||
|
||||
if (
|
||||
timeInferred &&
|
||||
toTimeInferred &&
|
||||
this.get("formats").includes(format)
|
||||
) {
|
||||
if (timeInferred && this.get("formats").includes(format)) {
|
||||
config.format = "LL";
|
||||
}
|
||||
|
||||
if (toDate) {
|
||||
config.toDateTime = toDateTime;
|
||||
}
|
||||
|
||||
if (
|
||||
!timeInferred &&
|
||||
!toTimeInferred &&
|
||||
date === moment().format(this.dateFormat) &&
|
||||
date === toDate &&
|
||||
this.get("formats").includes(format)
|
||||
) {
|
||||
config.format = "LT";
|
||||
}
|
||||
|
||||
this.set("config", config);
|
||||
return config;
|
||||
},
|
||||
|
||||
getTextConfig(config) {
|
||||
let text = `[date=${config.date} `;
|
||||
if (config.recurring) text += `recurring=${config.recurring} `;
|
||||
_generateDateMarkup(config) {
|
||||
let text = `[date=${config.date}`;
|
||||
|
||||
if (config.time) {
|
||||
text += `time=${config.time} `;
|
||||
text += ` time=${config.time} `;
|
||||
}
|
||||
|
||||
if (config.format && config.format.length) {
|
||||
text += ` format="${config.format}" `;
|
||||
}
|
||||
|
||||
if (config.timezone) {
|
||||
text += ` timezone="${config.timezone}"`;
|
||||
}
|
||||
|
||||
if (config.timezones && config.timezones.length) {
|
||||
text += ` timezones="${config.timezones.join("|")}"`;
|
||||
}
|
||||
|
||||
text += `format="${config.format}" `;
|
||||
text += `timezones="${config.timezones.join("|")}"`;
|
||||
text += `]`;
|
||||
|
||||
if (config.toDate) {
|
||||
text += ` → `;
|
||||
text += `[date=${config.toDate} `;
|
||||
|
||||
if (config.toTime) {
|
||||
text += `time=${config.toTime} `;
|
||||
}
|
||||
|
||||
text += `format="${config.format}" `;
|
||||
text += `timezones="${config.timezones.join("|")}"`;
|
||||
text += `]`;
|
||||
}
|
||||
|
||||
return text;
|
||||
},
|
||||
|
||||
@computed("config.dateTime", "config.toDateTime")
|
||||
validDate(dateTime, toDateTime) {
|
||||
if (!dateTime) return false;
|
||||
valid(isRange) {
|
||||
const fromConfig = this.getConfig(isRange ? "start" : null);
|
||||
|
||||
if (toDateTime) {
|
||||
if (!toDateTime.isValid()) {
|
||||
return false;
|
||||
}
|
||||
if (!fromConfig.dateTime || !fromConfig.dateTime.isValid()) {
|
||||
this.set("isValid", false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (toDateTime.diff(dateTime) < 0) {
|
||||
if (isRange) {
|
||||
const toConfig = this.getConfig("end");
|
||||
|
||||
if (
|
||||
!toConfig.dateTime ||
|
||||
!toConfig.dateTime.isValid() ||
|
||||
toConfig.dateTime.diff(fromConfig.dateTime) < 0
|
||||
) {
|
||||
this.set("isValid", false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return dateTime.isValid();
|
||||
this.set("isValid", true);
|
||||
return true;
|
||||
},
|
||||
|
||||
@computed("advancedMode")
|
||||
@ -218,10 +180,23 @@ export default Ember.Component.extend({
|
||||
},
|
||||
|
||||
save() {
|
||||
this._closeModal();
|
||||
const isRange =
|
||||
this.get("date") && (this.get("toDate") || this.get("toTime"));
|
||||
|
||||
const textConfig = this.getTextConfig(this.get("config"));
|
||||
this.get("toolbarEvent").addText(textConfig);
|
||||
if (this.valid(isRange)) {
|
||||
this._closeModal();
|
||||
|
||||
let text = this._generateDateMarkup(
|
||||
this.getConfig(isRange ? "start" : null)
|
||||
);
|
||||
|
||||
if (isRange) {
|
||||
text += ` → `;
|
||||
text += this._generateDateMarkup(this.getConfig("end"));
|
||||
}
|
||||
|
||||
this.get("toolbarEvent").addText(text);
|
||||
}
|
||||
},
|
||||
|
||||
fillFormat(format) {
|
||||
|
@ -53,7 +53,7 @@
|
||||
<span class="preview">{{currentUserTimezone}}</span>
|
||||
</div>
|
||||
|
||||
{{#unless validDate}}
|
||||
{{#unless isValid}}
|
||||
<span class="validation-error">{{i18n "discourse_local_dates.create.form.invalid_date"}}</span>
|
||||
{{/unless}}
|
||||
|
||||
@ -111,7 +111,7 @@
|
||||
{{/d-modal-body}}
|
||||
|
||||
<div class="modal-footer discourse-local-dates-create-modal-footer">
|
||||
{{#if validDate}}
|
||||
{{#if isValid}}
|
||||
{{d-button class="btn btn-default"
|
||||
action="save"
|
||||
label="discourse_local_dates.create.form.insert"}}
|
||||
|
@ -9,7 +9,7 @@ function addLocalDate(buffer, matches, state) {
|
||||
timezone: null,
|
||||
format: null,
|
||||
timezones: null,
|
||||
displayedZone: null
|
||||
displayedTimezone: null
|
||||
};
|
||||
|
||||
let parsed = parseBBCodeTag(
|
||||
@ -25,13 +25,20 @@ function addLocalDate(buffer, matches, state) {
|
||||
config.timezone = parsed.attrs.timezone;
|
||||
config.recurring = parsed.attrs.recurring;
|
||||
config.timezones = parsed.attrs.timezones;
|
||||
config.displayedZone = parsed.attrs.displayedZone;
|
||||
config.displayedTimezone = parsed.attrs.displayedTimezone;
|
||||
|
||||
token = new state.Token("span_open", "span", 1);
|
||||
token.attrs = [
|
||||
["class", "discourse-local-date"],
|
||||
["data-date", state.md.utils.escapeHtml(config.date)]
|
||||
];
|
||||
token.attrs = [["data-date", state.md.utils.escapeHtml(config.date)]];
|
||||
|
||||
if (!config.date.match(/\d{4}-\d{2}-\d{2}/)) {
|
||||
closeBuffer(buffer, state, moment.invalid().format());
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.time && !config.time.match(/\d{2}:\d{2}(?::\d{2})?/)) {
|
||||
closeBuffer(buffer, state, moment.invalid().format());
|
||||
return;
|
||||
}
|
||||
|
||||
let dateTime = config.date;
|
||||
if (config.time) {
|
||||
@ -39,6 +46,13 @@ function addLocalDate(buffer, matches, state) {
|
||||
dateTime = `${dateTime} ${config.time}`;
|
||||
}
|
||||
|
||||
if (!moment(dateTime).isValid()) {
|
||||
closeBuffer(buffer, state, moment.invalid().format());
|
||||
return;
|
||||
}
|
||||
|
||||
token.attrs.push(["class", "discourse-local-date"]);
|
||||
|
||||
if (config.format) {
|
||||
token.attrs.push(["data-format", state.md.utils.escapeHtml(config.format)]);
|
||||
}
|
||||
@ -50,21 +64,28 @@ function addLocalDate(buffer, matches, state) {
|
||||
]);
|
||||
}
|
||||
|
||||
if (config.displayedZone) {
|
||||
if (
|
||||
config.displayedTimezone &&
|
||||
moment.tz.names().includes(config.displayedTimezone)
|
||||
) {
|
||||
token.attrs.push([
|
||||
"data-displayed-zone",
|
||||
state.md.utils.escapeHtml(config.displayedZone)
|
||||
"data-displayed-timezone",
|
||||
state.md.utils.escapeHtml(config.displayedTimezone)
|
||||
]);
|
||||
}
|
||||
|
||||
if (config.timezones) {
|
||||
const timezones = config.timezones.split("|").filter(timezone => {
|
||||
return moment.tz.names().includes(timezone);
|
||||
});
|
||||
|
||||
token.attrs.push([
|
||||
"data-timezones",
|
||||
state.md.utils.escapeHtml(config.timezones)
|
||||
state.md.utils.escapeHtml(timezones.join("|"))
|
||||
]);
|
||||
}
|
||||
|
||||
if (config.timezone) {
|
||||
if (config.timezone && moment.tz.names().includes(config.timezone)) {
|
||||
token.attrs.push([
|
||||
"data-timezone",
|
||||
state.md.utils.escapeHtml(config.timezone)
|
||||
@ -95,8 +116,14 @@ function addLocalDate(buffer, matches, state) {
|
||||
}
|
||||
token.attrs.push(["data-email-preview", emailPreview]);
|
||||
|
||||
closeBuffer(buffer, state, dateTime.utc().format(config.format));
|
||||
}
|
||||
|
||||
function closeBuffer(buffer, state, text) {
|
||||
let token;
|
||||
|
||||
token = new state.Token("text", "", 0);
|
||||
token.content = dateTime.utc().format(config.format);
|
||||
token.content = text;
|
||||
buffer.push(token);
|
||||
|
||||
token = new state.Token("span_close", "span", -1);
|
||||
|
@ -18,6 +18,29 @@
|
||||
}
|
||||
}
|
||||
|
||||
.discourse-local-date + #discourse-tooltip {
|
||||
.tooltip-content {
|
||||
max-width: 360px;
|
||||
padding: 0.5em;
|
||||
|
||||
.previews {
|
||||
.preview {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 5px;
|
||||
|
||||
.timezone {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
&.current {
|
||||
background: $tertiary-low;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.discourse-local-dates-create-modal-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
Reference in New Issue
Block a user