UX: improves local-dates form (#7268)
This commit is contained in:
parent
6e2e095b53
commit
9a56b398a1
|
@ -1,11 +1,11 @@
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
import { default as computed } from "ember-addons/ember-computed-decorators";
|
||||||
import { observes } from "ember-addons/ember-computed-decorators";
|
import { cookAsync } from "discourse/lib/text";
|
||||||
|
import debounce from "discourse/lib/debounce";
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
timeFormat: "HH:mm:ss",
|
timeFormat: "HH:mm:ss",
|
||||||
dateFormat: "YYYY-MM-DD",
|
dateFormat: "YYYY-MM-DD",
|
||||||
dateTimeFormat: "YYYY-MM-DD HH:mm:ss",
|
dateTimeFormat: "YYYY-MM-DD HH:mm:ss",
|
||||||
config: null,
|
|
||||||
date: null,
|
date: null,
|
||||||
toDate: null,
|
toDate: null,
|
||||||
time: null,
|
time: null,
|
||||||
|
@ -15,23 +15,152 @@ export default Ember.Component.extend({
|
||||||
recurring: null,
|
recurring: null,
|
||||||
advancedMode: false,
|
advancedMode: false,
|
||||||
isValid: true,
|
isValid: true,
|
||||||
|
timezone: null,
|
||||||
|
timezones: null,
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super();
|
this._super(...arguments);
|
||||||
|
|
||||||
this.set("date", moment().format(this.dateFormat));
|
this.setProperties({
|
||||||
this.set("timezones", []);
|
timezones: [],
|
||||||
this.set(
|
formats: (this.siteSettings.discourse_local_dates_default_formats || "")
|
||||||
"formats",
|
|
||||||
(this.siteSettings.discourse_local_dates_default_formats || "")
|
|
||||||
.split("|")
|
.split("|")
|
||||||
.filter(f => f)
|
.filter(f => f),
|
||||||
);
|
timezone: moment.tz.guess(),
|
||||||
|
date: moment().format(this.dateFormat)
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@observes("date", "time", "toDate", "toTime")
|
didInsertElement() {
|
||||||
_resetFormValidity() {
|
this._super(...arguments);
|
||||||
this.set("isValid", true);
|
|
||||||
|
this._renderPreview();
|
||||||
|
},
|
||||||
|
|
||||||
|
_renderPreview: debounce(function() {
|
||||||
|
const markup = this.get("markup");
|
||||||
|
|
||||||
|
if (markup) {
|
||||||
|
cookAsync(markup).then(result => {
|
||||||
|
this.set("currentPreview", result);
|
||||||
|
|
||||||
|
Ember.run.schedule("afterRender", () =>
|
||||||
|
this.$(".preview .discourse-local-date").applyLocalDates()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 250).observes("markup"),
|
||||||
|
|
||||||
|
@computed("date", "toDate", "toTime")
|
||||||
|
isRange(date, toDate, toTime) {
|
||||||
|
return date && (toDate || toTime);
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("computedConfig", "isRange")
|
||||||
|
isValid(config, isRange) {
|
||||||
|
const fromConfig = config.from;
|
||||||
|
if (!config.from.dateTime || !config.from.dateTime.isValid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRange) {
|
||||||
|
const toConfig = config.to;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!toConfig.dateTime ||
|
||||||
|
!toConfig.dateTime.isValid() ||
|
||||||
|
toConfig.dateTime.diff(fromConfig.dateTime) < 0
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("date", "time", "isRange", "options.{format,timezone}")
|
||||||
|
fromConfig(date, time, isRange, options = {}) {
|
||||||
|
const timeInferred = time ? false : true;
|
||||||
|
|
||||||
|
let dateTime;
|
||||||
|
if (!timeInferred) {
|
||||||
|
dateTime = moment.tz(`${date} ${time}`, options.timezone);
|
||||||
|
} else {
|
||||||
|
dateTime = moment.tz(date, options.timezone);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!timeInferred) {
|
||||||
|
time = dateTime.format(this.timeFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
let format = options.format;
|
||||||
|
if (timeInferred && this.get("formats").includes(format)) {
|
||||||
|
format = "LL";
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ember.Object.create({
|
||||||
|
date: dateTime.format(this.dateFormat),
|
||||||
|
time,
|
||||||
|
dateTime,
|
||||||
|
format,
|
||||||
|
range: isRange ? "start" : false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("toDate", "toTime", "isRange", "options.{timezone,format}")
|
||||||
|
toConfig(date, time, isRange, options = {}) {
|
||||||
|
const timeInferred = time ? false : true;
|
||||||
|
|
||||||
|
if (time && !date) {
|
||||||
|
date = moment().format(this.dateFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dateTime;
|
||||||
|
if (!timeInferred) {
|
||||||
|
dateTime = moment.tz(`${date} ${time}`, options.timezone);
|
||||||
|
} else {
|
||||||
|
dateTime = moment.tz(date, options.timezone).endOf("day");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!timeInferred) {
|
||||||
|
time = dateTime.format(this.timeFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
let format = options.format;
|
||||||
|
if (timeInferred && this.get("formats").includes(format)) {
|
||||||
|
format = "LL";
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ember.Object.create({
|
||||||
|
date: dateTime.format(this.dateFormat),
|
||||||
|
time,
|
||||||
|
dateTime,
|
||||||
|
format,
|
||||||
|
range: isRange ? "end" : false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("recurring", "timezones", "timezone", "format")
|
||||||
|
options(recurring, timezones, timezone, format) {
|
||||||
|
return Ember.Object.create({
|
||||||
|
recurring,
|
||||||
|
timezones,
|
||||||
|
timezone,
|
||||||
|
format
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed(
|
||||||
|
"fromConfig.{date}",
|
||||||
|
"toConfig.{date}",
|
||||||
|
"options.{recurring,timezones,timezone,format}"
|
||||||
|
)
|
||||||
|
computedConfig(fromConfig, toConfig, options) {
|
||||||
|
return Ember.Object.create({
|
||||||
|
from: fromConfig,
|
||||||
|
to: toConfig,
|
||||||
|
options
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
|
@ -51,15 +180,41 @@ export default Ember.Component.extend({
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
recurringOptions() {
|
recurringOptions() {
|
||||||
|
const key = "discourse_local_dates.create.form.recurring";
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{ name: "Every day", id: "1.days" },
|
{
|
||||||
{ name: "Every week", id: "1.weeks" },
|
name: I18n.t(`${key}.every_day`),
|
||||||
{ name: "Every two weeks", id: "2.weeks" },
|
id: "1.days"
|
||||||
{ name: "Every month", id: "1.months" },
|
},
|
||||||
{ name: "Every two months", id: "2.months" },
|
{
|
||||||
{ name: "Every three months", id: "3.months" },
|
name: I18n.t(`${key}.every_week`),
|
||||||
{ name: "Every six months", id: "6.months" },
|
id: "1.weeks"
|
||||||
{ name: "Every year", id: "1.years" }
|
},
|
||||||
|
{
|
||||||
|
name: I18n.t(`${key}.every_two_weeks`),
|
||||||
|
id: "2.weeks"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: I18n.t(`${key}.every_month`),
|
||||||
|
id: "1.months"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: I18n.t(`${key}.every_two_months`),
|
||||||
|
id: "2.months"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: I18n.t(`${key}.every_three_months`),
|
||||||
|
id: "3.months"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: I18n.t(`${key}.every_six_months`),
|
||||||
|
id: "6.months"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: I18n.t(`${key}.every_year`),
|
||||||
|
id: "1.years"
|
||||||
|
}
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -74,77 +229,27 @@ export default Ember.Component.extend({
|
||||||
return moment.tz.names();
|
return moment.tz.names();
|
||||||
},
|
},
|
||||||
|
|
||||||
getConfig(range) {
|
_generateDateMarkup(config, options, isRange) {
|
||||||
const endOfRange = range && range === "end";
|
|
||||||
const time = endOfRange ? this.get("toTime") : this.get("time");
|
|
||||||
let date = endOfRange ? this.get("toDate") : this.get("date");
|
|
||||||
|
|
||||||
if (endOfRange && time && !date) {
|
|
||||||
date = moment().format(this.dateFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
const recurring = this.get("recurring");
|
|
||||||
const format = this.get("format");
|
|
||||||
const timezones = this.get("timezones");
|
|
||||||
const timeInferred = time ? false : true;
|
|
||||||
const timezone = this.get("currentUserTimezone");
|
|
||||||
|
|
||||||
let dateTime;
|
|
||||||
if (!timeInferred) {
|
|
||||||
dateTime = moment.tz(`${date} ${time}`, timezone);
|
|
||||||
} else {
|
|
||||||
if (endOfRange) {
|
|
||||||
dateTime = moment.tz(date, timezone).endOf("day");
|
|
||||||
} else {
|
|
||||||
dateTime = moment.tz(date, timezone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let config = {
|
|
||||||
date: dateTime.format(this.dateFormat),
|
|
||||||
dateTime,
|
|
||||||
recurring,
|
|
||||||
format,
|
|
||||||
timezones,
|
|
||||||
timezone
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!timeInferred) {
|
|
||||||
config.time = dateTime.format(this.timeFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeInferred) {
|
|
||||||
config.displayedTimezone = this.get("currentUserTimezone");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeInferred && this.get("formats").includes(format)) {
|
|
||||||
config.format = "LL";
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
},
|
|
||||||
|
|
||||||
_generateDateMarkup(config) {
|
|
||||||
let text = `[date=${config.date}`;
|
let text = `[date=${config.date}`;
|
||||||
|
|
||||||
if (config.time) {
|
if (config.time) {
|
||||||
text += ` time=${config.time} `;
|
text += ` time=${config.time}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.format && config.format.length) {
|
if (config.format && config.format.length) {
|
||||||
text += ` format="${config.format}" `;
|
text += ` format="${config.format}"`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.timezone) {
|
if (options.timezone) {
|
||||||
text += ` timezone="${config.timezone}"`;
|
text += ` timezone="${options.timezone}"`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.timezones && config.timezones.length) {
|
if (options.timezones && options.timezones.length) {
|
||||||
text += ` timezones="${config.timezones.join("|")}"`;
|
text += ` timezones="${options.timezones.join("|")}"`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.recurring) {
|
if (options.recurring && !isRange) {
|
||||||
text += ` recurring="${config.recurring}"`;
|
text += ` recurring="${options.recurring}"`;
|
||||||
}
|
}
|
||||||
|
|
||||||
text += `]`;
|
text += `]`;
|
||||||
|
@ -152,31 +257,6 @@ export default Ember.Component.extend({
|
||||||
return text;
|
return text;
|
||||||
},
|
},
|
||||||
|
|
||||||
valid(isRange) {
|
|
||||||
const fromConfig = this.getConfig(isRange ? "start" : null);
|
|
||||||
|
|
||||||
if (!fromConfig.dateTime || !fromConfig.dateTime.isValid()) {
|
|
||||||
this.set("isValid", false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.set("isValid", true);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("advancedMode")
|
@computed("advancedMode")
|
||||||
toggleModeBtnLabel(advancedMode) {
|
toggleModeBtnLabel(advancedMode) {
|
||||||
return advancedMode
|
return advancedMode
|
||||||
|
@ -184,35 +264,36 @@ export default Ember.Component.extend({
|
||||||
: "discourse_local_dates.create.form.advanced_mode";
|
: "discourse_local_dates.create.form.advanced_mode";
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@computed("computedConfig.{from,to,options}", "options", "isValid", "isRange")
|
||||||
|
markup(config, options, isValid, isRange) {
|
||||||
|
let text;
|
||||||
|
|
||||||
|
if (isValid && config.from) {
|
||||||
|
text = this._generateDateMarkup(config.from, options, isRange);
|
||||||
|
|
||||||
|
if (config.to && config.to.range) {
|
||||||
|
text += ` → `;
|
||||||
|
text += this._generateDateMarkup(config.to, options, isRange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
advancedMode() {
|
advancedMode() {
|
||||||
this.toggleProperty("advancedMode");
|
this.toggleProperty("advancedMode");
|
||||||
},
|
},
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
const isRange =
|
const markup = this.get("markup");
|
||||||
this.get("date") && (this.get("toDate") || this.get("toTime"));
|
|
||||||
|
|
||||||
if (this.valid(isRange)) {
|
if (markup) {
|
||||||
this._closeModal();
|
this._closeModal();
|
||||||
|
this.get("toolbarEvent").addText(markup);
|
||||||
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) {
|
|
||||||
this.set("format", format);
|
|
||||||
},
|
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
this._closeModal();
|
this._closeModal();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,19 @@
|
||||||
style="overflow: auto"}}
|
style="overflow: auto"}}
|
||||||
|
|
||||||
<div class="form">
|
<div class="form">
|
||||||
|
{{#unless isValid}}
|
||||||
|
<div class="alert alert-error">
|
||||||
|
{{i18n "discourse_local_dates.create.form.invalid_date"}}
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="preview alert alert-info">
|
||||||
|
<b>{{i18n "discourse_local_dates.create.form.preview_for" timezone=currentUserTimezone}}</b>
|
||||||
|
<span>{{currentPreview}}</span>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
|
||||||
|
{{computeDate}}
|
||||||
|
|
||||||
<div class="date-time-configuration">
|
<div class="date-time-configuration">
|
||||||
<div class="range">
|
<div class="range">
|
||||||
<div class="from">
|
<div class="from">
|
||||||
|
@ -13,7 +26,11 @@
|
||||||
{{i18n "discourse_local_dates.create.form.date_title"}}
|
{{i18n "discourse_local_dates.create.form.date_title"}}
|
||||||
</label>
|
</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
{{date-picker class="date-input" value=date defaultDate="DD-MM-YYYY"}}
|
{{date-picker
|
||||||
|
onSelect=(action (mut date))
|
||||||
|
class="date-input"
|
||||||
|
value=date
|
||||||
|
defaultDate="DD-MM-YYYY"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -22,12 +39,14 @@
|
||||||
{{i18n "discourse_local_dates.create.form.time_title"}}
|
{{i18n "discourse_local_dates.create.form.time_title"}}
|
||||||
</label>
|
</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
{{input type="time" value=time class="time-input"}}
|
{{input input=(mut time) type="time" value=time class="time-input"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="to-indicator"><span>{{i18n "discourse_local_dates.create.form.to"}}</span></span>
|
<div class="to-indicator">
|
||||||
|
{{if site.mobileView "↓" "→"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="to">
|
<div class="to">
|
||||||
<div class="control-group date">
|
<div class="control-group date">
|
||||||
|
@ -35,7 +54,11 @@
|
||||||
{{i18n "discourse_local_dates.create.form.date_title"}}
|
{{i18n "discourse_local_dates.create.form.date_title"}}
|
||||||
</label>
|
</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
{{date-picker class="date-input" value=toDate defaultDate="DD-MM-YYYY"}}
|
{{date-picker
|
||||||
|
onSelect=(action (mut toDate))
|
||||||
|
class="date-input"
|
||||||
|
value=toDate
|
||||||
|
defaultDate="DD-MM-YYYY"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -44,33 +67,49 @@
|
||||||
{{i18n "discourse_local_dates.create.form.time_title"}}
|
{{i18n "discourse_local_dates.create.form.time_title"}}
|
||||||
</label>
|
</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
{{input type="time" value=toTime class="time-input"}}
|
{{input input=(mut toTime) type="time" value=toTime class="time-input"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="preview">{{currentUserTimezone}}</span>
|
<div class="timezone">
|
||||||
</div>
|
<div class="control-group time">
|
||||||
|
<label class="control-label">
|
||||||
|
{{i18n "discourse_local_dates.create.form.timezone"}}
|
||||||
|
</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{combo-box
|
||||||
|
class="timezone-input"
|
||||||
|
allowAny=false
|
||||||
|
content=allTimezones
|
||||||
|
value=timezone
|
||||||
|
onSelect=(action (mut timezone))}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{#unless isValid}}
|
|
||||||
<span class="validation-error">{{i18n "discourse_local_dates.create.form.invalid_date"}}</span>
|
|
||||||
{{/unless}}
|
|
||||||
|
|
||||||
<div class="control-group recurrence">
|
|
||||||
<label class="control-label">
|
|
||||||
{{i18n "discourse_local_dates.create.form.recurring_title"}}
|
|
||||||
</label>
|
|
||||||
{{#if advancedMode}}
|
|
||||||
<p>{{{i18n "discourse_local_dates.create.form.recurring_description"}}}</p>
|
|
||||||
{{/if}}
|
|
||||||
<div class="controls">
|
|
||||||
{{combo-box content=recurringOptions class="recurrence-input" value=recurring none="discourse_local_dates.create.form.recurring_none"}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if advancedMode}}
|
{{#if advancedMode}}
|
||||||
<div class="advanced-options">
|
<div class="advanced-options">
|
||||||
|
{{#unless isRange}}
|
||||||
|
<div class="control-group recurrence">
|
||||||
|
<label class="control-label">
|
||||||
|
{{i18n "discourse_local_dates.create.form.recurring_title"}}
|
||||||
|
</label>
|
||||||
|
<p>{{{i18n "discourse_local_dates.create.form.recurring_description"}}}</p>
|
||||||
|
<div class="controls">
|
||||||
|
{{combo-box
|
||||||
|
content=recurringOptions
|
||||||
|
class="recurrence-input"
|
||||||
|
value=recurring
|
||||||
|
onSelect=(action (mut recurring))
|
||||||
|
none="discourse_local_dates.create.form.recurring_none"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
|
||||||
<div class="control-group format">
|
<div class="control-group format">
|
||||||
<label>{{i18n "discourse_local_dates.create.form.format_title"}}</label>
|
<label>{{i18n "discourse_local_dates.create.form.format_title"}}</label>
|
||||||
<p>
|
<p>
|
||||||
|
@ -87,7 +126,7 @@
|
||||||
<ul class="formats">
|
<ul class="formats">
|
||||||
{{#each previewedFormats as |previewedFormat|}}
|
{{#each previewedFormats as |previewedFormat|}}
|
||||||
<li class="format">
|
<li class="format">
|
||||||
<a class="moment-format" href {{action "fillFormat" previewedFormat.format}}>
|
<a class="moment-format" href {{action (mut format) previewedFormat.format}}>
|
||||||
{{previewedFormat.format}}
|
{{previewedFormat.format}}
|
||||||
</a>
|
</a>
|
||||||
<span class="previewed-format">
|
<span class="previewed-format">
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.discourse-local-dates-create-modal {
|
.discourse-local-dates-create-modal {
|
||||||
min-height: 300px;
|
min-height: 200px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
||||||
|
@ -70,72 +70,69 @@
|
||||||
|
|
||||||
.date-time-configuration {
|
.date-time-configuration {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
.range {
|
.range,
|
||||||
|
.timezone {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
flex: 1;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
.from {
|
.from {
|
||||||
flex-direction: row;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.to {
|
.to {
|
||||||
flex-direction: row;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.to-indicator {
|
.to-indicator {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
flex-direction: row;
|
||||||
margin: 0.5em 0;
|
padding-top: 0.5em;
|
||||||
|
margin: 0 1em;
|
||||||
|
font-size: $font-up-2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.date {
|
.date {
|
||||||
|
margin-right: 0.5em;
|
||||||
.date-input {
|
.date-input {
|
||||||
margin-right: 1em;
|
width: 100px;
|
||||||
|
text-align: center;
|
||||||
.date-picker {
|
.date-picker {
|
||||||
padding-top: 5px;
|
padding: 0;
|
||||||
bottom: 5px;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
width: 120px;
|
width: 100%;
|
||||||
text-align: left;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timezone {
|
||||||
|
margin-left: 1em;
|
||||||
|
.timezone-input {
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.time {
|
.time {
|
||||||
.time-input {
|
.time-input {
|
||||||
margin: 0 0.5em 0 0;
|
width: 80px;
|
||||||
width: 120px;
|
margin: 0;
|
||||||
padding: 3.5px 10px;
|
padding: 0;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.preview {
|
.preview {
|
||||||
flex: 1 0 0px;
|
text-align: center;
|
||||||
margin-top: 16px;
|
margin-top: 0;
|
||||||
text-align: center;
|
margin-bottom: 1em;
|
||||||
}
|
|
||||||
|
|
||||||
@include breakpoint(medium) {
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
|
|
||||||
.range .from,
|
|
||||||
.range .to {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.date .date-input .date-picker {
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time .time-input {
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.validation-error {
|
.validation-error {
|
||||||
|
@ -176,3 +173,38 @@
|
||||||
width: 99%;
|
width: 99%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 700px) {
|
||||||
|
.discourse-local-dates-create-modal {
|
||||||
|
.form {
|
||||||
|
.date-time-configuration {
|
||||||
|
flex-direction: column;
|
||||||
|
.range,
|
||||||
|
.timezone {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.controls,
|
||||||
|
.control-group {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.to-indicator {
|
||||||
|
margin: 0.5em 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.timezone {
|
||||||
|
margin: 0.5em 0 0 0;
|
||||||
|
padding: 0.5em 0 0 0;
|
||||||
|
border-top: 1px solid $primary-low;
|
||||||
|
|
||||||
|
.timezone-input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ en:
|
||||||
modal_title: Insert date
|
modal_title: Insert date
|
||||||
modal_subtitle: "We will automatically convert the date and time to the viewer’s local time zone."
|
modal_subtitle: "We will automatically convert the date and time to the viewer’s local time zone."
|
||||||
form:
|
form:
|
||||||
to: "to"
|
|
||||||
insert: Insert
|
insert: Insert
|
||||||
advanced_mode: Advanced mode
|
advanced_mode: Advanced mode
|
||||||
simple_mode: Simple mode
|
simple_mode: Simple mode
|
||||||
|
@ -24,3 +23,14 @@ en:
|
||||||
date_title: Date
|
date_title: Date
|
||||||
time_title: Time
|
time_title: Time
|
||||||
format_title: Date format
|
format_title: Date format
|
||||||
|
timezone: Timezone
|
||||||
|
preview_for: Preview for %{timezone}
|
||||||
|
recurring:
|
||||||
|
every_day: "Every day"
|
||||||
|
every_week: "Every week"
|
||||||
|
every_two_weeks: "Every two weeks"
|
||||||
|
every_month: "Every month"
|
||||||
|
every_two_months: "Every two months"
|
||||||
|
every_three_months: "Every three months"
|
||||||
|
every_six_months: "Every six months"
|
||||||
|
every_year: "Every year"
|
||||||
|
|
|
@ -4,38 +4,39 @@
|
||||||
# author: Joffrey Jaffeux
|
# author: Joffrey Jaffeux
|
||||||
hide_plugin if self.respond_to?(:hide_plugin)
|
hide_plugin if self.respond_to?(:hide_plugin)
|
||||||
|
|
||||||
register_asset "javascripts/discourse-local-dates.js.no-module.es6"
|
register_asset 'javascripts/discourse-local-dates.js.no-module.es6'
|
||||||
register_asset "stylesheets/common/discourse-local-dates.scss"
|
register_asset 'stylesheets/common/discourse-local-dates.scss'
|
||||||
register_asset "moment.js", :vendored_core_pretty_text
|
register_asset 'moment.js', :vendored_core_pretty_text
|
||||||
register_asset "moment-timezone.js", :vendored_core_pretty_text
|
register_asset 'moment-timezone.js', :vendored_core_pretty_text
|
||||||
|
|
||||||
enabled_site_setting :discourse_local_dates_enabled
|
enabled_site_setting :discourse_local_dates_enabled
|
||||||
|
|
||||||
after_initialize do
|
after_initialize do
|
||||||
module ::DiscourseLocalDates
|
module ::DiscourseLocalDates
|
||||||
PLUGIN_NAME ||= "discourse-local-dates".freeze
|
PLUGIN_NAME ||= 'discourse-local-dates'.freeze
|
||||||
POST_CUSTOM_FIELD ||= "local_dates".freeze
|
POST_CUSTOM_FIELD ||= 'local_dates'.freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
[
|
%w[../lib/discourse_local_dates/engine.rb].each do |path|
|
||||||
"../lib/discourse_local_dates/engine.rb",
|
load File.expand_path(path, __FILE__)
|
||||||
].each { |path| load File.expand_path(path, __FILE__) }
|
end
|
||||||
|
|
||||||
register_post_custom_field_type(DiscourseLocalDates::POST_CUSTOM_FIELD, :json)
|
register_post_custom_field_type(DiscourseLocalDates::POST_CUSTOM_FIELD, :json)
|
||||||
|
|
||||||
on(:before_post_process_cooked) do |doc, post|
|
on(:before_post_process_cooked) do |doc, post|
|
||||||
dates = doc.css('span.discourse-local-date').map do |cooked_date|
|
dates =
|
||||||
date = {}
|
doc.css('span.discourse-local-date').map do |cooked_date|
|
||||||
cooked_date.attributes.values.each do |attribute|
|
date = {}
|
||||||
data_name = attribute.name&.gsub('data-', '')
|
cooked_date.attributes.values.each do |attribute|
|
||||||
if data_name && ['date', 'time', 'timezone', 'recurring'].include?(data_name)
|
data_name = attribute.name&.gsub('data-', '')
|
||||||
unless attribute.value == 'undefined'
|
if data_name && %w[date time timezone recurring].include?(data_name)
|
||||||
date[data_name] = CGI.escapeHTML(attribute.value || "")
|
unless attribute.value == 'undefined'
|
||||||
|
date[data_name] = CGI.escapeHTML(attribute.value || '')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
date
|
||||||
end
|
end
|
||||||
date
|
|
||||||
end
|
|
||||||
|
|
||||||
if dates.present?
|
if dates.present?
|
||||||
post.custom_fields[DiscourseLocalDates::POST_CUSTOM_FIELD] = dates
|
post.custom_fields[DiscourseLocalDates::POST_CUSTOM_FIELD] = dates
|
||||||
|
@ -51,9 +52,9 @@ after_initialize do
|
||||||
end
|
end
|
||||||
|
|
||||||
on(:reduce_cooked) do |fragment|
|
on(:reduce_cooked) do |fragment|
|
||||||
fragment.css(".discourse-local-date").each do |container|
|
fragment.css('.discourse-local-date').each do |container|
|
||||||
if container.attributes["data-email-preview"]
|
if container.attributes['data-email-preview']
|
||||||
preview = container.attributes["data-email-preview"].value
|
preview = container.attributes['data-email-preview'].value
|
||||||
container.content = preview
|
container.content = preview
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue