DEV: Move calendar date + time picker from local dates into core component (#23023)
This commit moves the calendar date and time picker shown in the local dates modal into a core component that can be reused in other places. Also add system specs to make sure there isn't any breakages with this feature, and a section to the styleguide.
This commit is contained in:
parent
0187ad0d37
commit
fb36af7799
|
@ -0,0 +1,24 @@
|
|||
<div
|
||||
class="calendar-date-time-input"
|
||||
{{did-insert this.setupInternalDateTime}}
|
||||
{{did-insert this.setupPikaday}}
|
||||
{{did-update this.changeMinDate @minDate}}
|
||||
{{did-update this.changeDate @date}}
|
||||
{{did-update this.changeTime @time}}
|
||||
>
|
||||
<Input class="fake-input" />
|
||||
|
||||
<div class="date-picker" id="picker-container-{{@datePickerId}}"></div>
|
||||
|
||||
<div class="time-pickers">
|
||||
{{d-icon "far-clock"}}
|
||||
<Input
|
||||
maxlength={{5}}
|
||||
placeholder="hh:mm"
|
||||
@type="time"
|
||||
@value={{this._time}}
|
||||
class="time-picker"
|
||||
{{on "input" (action this.onChangeTime)}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,109 @@
|
|||
/* global Pikaday:true */
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import Component from "@glimmer/component";
|
||||
import I18n from "I18n";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import { Promise } from "rsvp";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default class CalendarDateTimeInput extends Component {
|
||||
_timeFormat = this.args.timeFormat || "HH:mm:ss";
|
||||
_dateFormat = this.args.dateFormat || "YYYY-MM-DD";
|
||||
_dateTimeFormat = this.args.dateTimeFormat || "YYYY-MM-DD HH:mm:ss";
|
||||
_picker = null;
|
||||
|
||||
@tracked _time;
|
||||
@tracked _date;
|
||||
|
||||
@action
|
||||
setupInternalDateTime() {
|
||||
this._time = this.args.time;
|
||||
this._date = this.args.date;
|
||||
}
|
||||
|
||||
@action
|
||||
setupPikaday(element) {
|
||||
this.#setupPicker(element).then((picker) => {
|
||||
this._picker = picker;
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
onChangeTime(event) {
|
||||
this._time = event.target.value;
|
||||
this.args.onChangeTime(this._time);
|
||||
}
|
||||
|
||||
@action
|
||||
changeDate() {
|
||||
if (moment(this.args.date, this._dateFormat).isValid()) {
|
||||
this._date = this.args.date;
|
||||
this._picker.setDate(
|
||||
moment.utc(this._date).format(this._dateFormat),
|
||||
true
|
||||
);
|
||||
} else {
|
||||
this._date = null;
|
||||
this._picker.setDate(null);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
changeTime() {
|
||||
if (isEmpty(this.args.time)) {
|
||||
this._time = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (/^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/.test(this.args.time)) {
|
||||
this._time = this.args.time;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
changeMinDate() {
|
||||
if (
|
||||
this.args.minDate &&
|
||||
moment(this.args.minDate, this._dateFormat).isValid()
|
||||
) {
|
||||
this._picker.setMinDate(
|
||||
moment(this.args.minDate, this._dateFormat).toDate()
|
||||
);
|
||||
} else {
|
||||
this._picker.setMinDate(null);
|
||||
}
|
||||
}
|
||||
|
||||
#setupPicker(element) {
|
||||
return new Promise((resolve) => {
|
||||
loadScript("/javascripts/pikaday.js").then(() => {
|
||||
const options = {
|
||||
field: element.querySelector(".fake-input"),
|
||||
container: element.querySelector(
|
||||
`#picker-container-${this.args.datePickerId}`
|
||||
),
|
||||
bound: false,
|
||||
format: "YYYY-MM-DD",
|
||||
reposition: false,
|
||||
firstDay: 1,
|
||||
setDefaultDate: true,
|
||||
keyboardInput: false,
|
||||
i18n: {
|
||||
previousMonth: I18n.t("dates.previous_month"),
|
||||
nextMonth: I18n.t("dates.next_month"),
|
||||
months: moment.months(),
|
||||
weekdays: moment.weekdays(),
|
||||
weekdaysShort: moment.weekdaysMin(),
|
||||
},
|
||||
onSelect: (date) => {
|
||||
const formattedDate = moment(date).format("YYYY-MM-DD");
|
||||
this.args.onChangeDate(formattedDate);
|
||||
},
|
||||
};
|
||||
|
||||
resolve(new Pikaday(options));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
@import "color-input";
|
||||
@import "char-counter";
|
||||
@import "conditional-loading-section";
|
||||
@import "calendar-date-time-input";
|
||||
@import "convert-to-public-topic-modal";
|
||||
@import "d-lightbox";
|
||||
@import "d-tooltip";
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
.calendar-date-time-input {
|
||||
.fake-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
padding: 5px;
|
||||
border: 1px solid var(--primary-low);
|
||||
z-index: 1;
|
||||
background: var(--secondary);
|
||||
width: 200px;
|
||||
box-sizing: border-box;
|
||||
margin-left: 1em;
|
||||
|
||||
.date-picker {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: auto;
|
||||
box-sizing: border-box;
|
||||
|
||||
.pika-single {
|
||||
position: relative !important;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.time-pickers {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
margin-top: 1em;
|
||||
align-items: center;
|
||||
padding: 0.25em;
|
||||
border-top: 1px solid var(--primary-low-mid);
|
||||
box-sizing: border-box;
|
||||
|
||||
.d-icon {
|
||||
color: var(--primary-medium);
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.time-picker {
|
||||
box-shadow: none;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
/* global Pikaday:true */
|
||||
import computed, {
|
||||
debounce,
|
||||
observes,
|
||||
|
@ -7,10 +6,7 @@ import Component from "@ember/component";
|
|||
import EmberObject, { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||
import { Promise } from "rsvp";
|
||||
import { cookAsync } from "discourse/lib/text";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import { notEmpty } from "@ember/object/computed";
|
||||
import { propertyNotEqual } from "discourse/lib/computed";
|
||||
import { schedule } from "@ember/runloop";
|
||||
|
@ -46,18 +42,14 @@ export default Component.extend({
|
|||
formats: (this.siteSettings.discourse_local_dates_default_formats || "")
|
||||
.split("|")
|
||||
.filter((f) => f),
|
||||
timezone: moment.tz.guess(),
|
||||
timezone: this.currentUserTimezone,
|
||||
date: moment().format(this.dateFormat),
|
||||
});
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
this._setupPicker().then((picker) => {
|
||||
this._picker = picker;
|
||||
this.send("focusFrom");
|
||||
});
|
||||
this.send("focusFrom");
|
||||
},
|
||||
|
||||
@observes("computedConfig.{from,to,options}", "options", "isValid", "isRange")
|
||||
|
@ -194,7 +186,7 @@ export default Component.extend({
|
|||
|
||||
@computed
|
||||
currentUserTimezone() {
|
||||
return moment.tz.guess();
|
||||
return this.currentUser.user_option.timezone || moment.tz.guess();
|
||||
},
|
||||
|
||||
@computed
|
||||
|
@ -312,118 +304,79 @@ export default Component.extend({
|
|||
this.set("format", format);
|
||||
},
|
||||
|
||||
actions: {
|
||||
setTime(event) {
|
||||
this._setTimeIfValid(event.target.value, "time");
|
||||
},
|
||||
@computed("fromSelected", "toSelected")
|
||||
selectedDate(fromSelected) {
|
||||
return fromSelected ? this.date : this.toDate;
|
||||
},
|
||||
|
||||
setToTime(event) {
|
||||
this._setTimeIfValid(event.target.value, "toTime");
|
||||
},
|
||||
@computed("fromSelected", "toSelected")
|
||||
selectedTime(fromSelected) {
|
||||
return fromSelected ? this.time : this.toTime;
|
||||
},
|
||||
|
||||
eraseToDateTime() {
|
||||
this.setProperties({ toDate: null, toTime: null });
|
||||
this._setPickerDate(null);
|
||||
},
|
||||
@action
|
||||
changeSelectedDate(date) {
|
||||
if (this.fromSelected) {
|
||||
this.set("date", date);
|
||||
} else {
|
||||
this.set("toDate", date);
|
||||
}
|
||||
},
|
||||
|
||||
focusFrom() {
|
||||
this.setProperties({ fromSelected: true, toSelected: false });
|
||||
this._setPickerDate(this.get("fromConfig.date"));
|
||||
this._setPickerMinDate(null);
|
||||
},
|
||||
@action
|
||||
changeSelectedTime(time) {
|
||||
if (this.fromSelected) {
|
||||
this.set("time", time);
|
||||
} else {
|
||||
this.set("toTime", time);
|
||||
}
|
||||
},
|
||||
|
||||
focusTo() {
|
||||
this.setProperties({ toSelected: true, fromSelected: false });
|
||||
this._setPickerDate(this.get("toConfig.date"));
|
||||
this._setPickerMinDate(this.get("fromConfig.date"));
|
||||
},
|
||||
@action
|
||||
eraseToDateTime() {
|
||||
this.setProperties({
|
||||
toDate: null,
|
||||
toTime: null,
|
||||
});
|
||||
this.focusFrom();
|
||||
},
|
||||
|
||||
advancedMode() {
|
||||
this.toggleProperty("advancedMode");
|
||||
},
|
||||
@action
|
||||
focusFrom() {
|
||||
this.setProperties({
|
||||
fromSelected: true,
|
||||
toSelected: false,
|
||||
minDate: null,
|
||||
});
|
||||
},
|
||||
|
||||
save() {
|
||||
const markup = this.markup;
|
||||
@action
|
||||
focusTo() {
|
||||
this.setProperties({
|
||||
toSelected: true,
|
||||
fromSelected: false,
|
||||
minDate: this.get("fromConfig.date"),
|
||||
});
|
||||
},
|
||||
|
||||
if (markup) {
|
||||
this._closeModal();
|
||||
this.insertDate(markup);
|
||||
}
|
||||
},
|
||||
@action
|
||||
toggleAdvancedMode() {
|
||||
this.toggleProperty("advancedMode");
|
||||
},
|
||||
|
||||
cancel() {
|
||||
@action
|
||||
save() {
|
||||
const markup = this.markup;
|
||||
|
||||
if (markup) {
|
||||
this._closeModal();
|
||||
},
|
||||
},
|
||||
|
||||
_setTimeIfValid(time, key) {
|
||||
if (isEmpty(time)) {
|
||||
this.set(key, null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (/^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/.test(time)) {
|
||||
this.set(key, time);
|
||||
this.insertDate(markup);
|
||||
}
|
||||
},
|
||||
|
||||
_setupPicker() {
|
||||
return new Promise((resolve) => {
|
||||
loadScript("/javascripts/pikaday.js").then(() => {
|
||||
const options = {
|
||||
field: this.element.querySelector(".fake-input"),
|
||||
container: this.element.querySelector(
|
||||
`#picker-container-${this.elementId}`
|
||||
),
|
||||
bound: false,
|
||||
format: "YYYY-MM-DD",
|
||||
reposition: false,
|
||||
firstDay: 1,
|
||||
setDefaultDate: true,
|
||||
keyboardInput: false,
|
||||
i18n: {
|
||||
previousMonth: I18n.t("dates.previous_month"),
|
||||
nextMonth: I18n.t("dates.next_month"),
|
||||
months: moment.months(),
|
||||
weekdays: moment.weekdays(),
|
||||
weekdaysShort: moment.weekdaysMin(),
|
||||
},
|
||||
onSelect: (date) => {
|
||||
const formattedDate = moment(date).format("YYYY-MM-DD");
|
||||
|
||||
if (this.fromSelected) {
|
||||
this.set("date", formattedDate);
|
||||
}
|
||||
|
||||
if (this.toSelected) {
|
||||
this.set("toDate", formattedDate);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
resolve(new Pikaday(options));
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_setPickerMinDate(date) {
|
||||
schedule("afterRender", () => {
|
||||
if (moment(date, this.dateFormat).isValid()) {
|
||||
this._picker.setMinDate(moment(date, this.dateFormat).toDate());
|
||||
} else {
|
||||
this._picker.setMinDate(null);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_setPickerDate(date) {
|
||||
schedule("afterRender", () => {
|
||||
if (moment(date, this.dateFormat).isValid()) {
|
||||
this._picker.setDate(moment.utc(date), true);
|
||||
} else {
|
||||
this._picker.setDate(null);
|
||||
}
|
||||
});
|
||||
@action
|
||||
cancel() {
|
||||
this._closeModal();
|
||||
},
|
||||
|
||||
_closeModal() {
|
||||
|
|
|
@ -66,38 +66,16 @@
|
|||
</div>
|
||||
|
||||
<div class="picker-panel">
|
||||
<Input class="fake-input" />
|
||||
<div class="date-picker" id="picker-container-{{this.elementId}}"></div>
|
||||
|
||||
{{#if this.fromSelected}}
|
||||
<div class="time-pickers">
|
||||
{{d-icon "far-clock"}}
|
||||
<Input
|
||||
maxlength={{5}}
|
||||
placeholder="hh:mm"
|
||||
@type="time"
|
||||
@value={{this.time}}
|
||||
class="time-picker"
|
||||
{{on "input" (action "setTime")}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.toSelected}}
|
||||
{{#if this.toDate}}
|
||||
<div class="time-pickers">
|
||||
{{d-icon "far-clock"}}
|
||||
<Input
|
||||
maxlength={{5}}
|
||||
placeholder="hh:mm"
|
||||
@type="time"
|
||||
@value={{this.toTime}}
|
||||
class="time-picker"
|
||||
{{on "input" (action "setToTime")}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<CalendarDateTimeInput
|
||||
@datePickerId="local-date-create-form"
|
||||
@date={{this.selectedDate}}
|
||||
@time={{this.selectedTime}}
|
||||
@minDate={{this.minDate}}
|
||||
@timeFormat={{this.timeFormat}}
|
||||
@dateFormat={{this.dateFormat}}
|
||||
@onChangeDate={{action this.changeSelectedDate}}
|
||||
@onChangeTime={{action this.changeSelectedTime}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{{#if this.site.mobileView}}
|
||||
|
@ -210,7 +188,7 @@
|
|||
|
||||
<DButton
|
||||
@class="btn-default advanced-mode-btn"
|
||||
@action={{action "advancedMode"}}
|
||||
@action={{action "toggleAdvancedMode"}}
|
||||
@icon="cog"
|
||||
@label={{this.toggleModeBtnLabel}}
|
||||
/>
|
||||
|
|
|
@ -70,25 +70,6 @@ div[data-tippy-root] {
|
|||
flex-direction: row;
|
||||
padding: 0.5em;
|
||||
|
||||
.picker-panel {
|
||||
padding: 5px;
|
||||
border: 1px solid var(--primary-low);
|
||||
}
|
||||
|
||||
.date-picker {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: auto;
|
||||
box-sizing: border-box;
|
||||
|
||||
.pika-single {
|
||||
position: relative !important;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.form {
|
||||
flex: 1 0 0px;
|
||||
|
||||
|
@ -210,37 +191,6 @@ div[data-tippy-root] {
|
|||
.inputs-panel {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.picker-panel {
|
||||
z-index: 1;
|
||||
background: var(--secondary);
|
||||
width: 200px;
|
||||
box-sizing: border-box;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.time-pickers {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
margin-top: 1em;
|
||||
align-items: center;
|
||||
padding: 0.25em;
|
||||
border-top: 1px solid var(--primary-low-mid);
|
||||
box-sizing: border-box;
|
||||
|
||||
.d-icon {
|
||||
color: var(--primary-medium);
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.time-picker {
|
||||
box-shadow: none;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.preview {
|
||||
|
@ -318,17 +268,17 @@ html.mobile-view {
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.picker-panel {
|
||||
.calendar-date-time-input {
|
||||
width: 100%;
|
||||
margin: 0 0 1em 0;
|
||||
|
||||
.pika-single {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.time-picker {
|
||||
padding-top: 6px;
|
||||
.time-picker {
|
||||
padding-top: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,10 @@ describe "Local dates", type: :system do
|
|||
fab!(:topic) { Fabricate(:topic) }
|
||||
fab!(:current_user) { Fabricate(:user) }
|
||||
let(:year) { Time.zone.now.year + 1 }
|
||||
let(:month) { Time.zone.now.month }
|
||||
let(:bookmark_modal) { PageObjects::Modals::Bookmark.new }
|
||||
let(:composer) { PageObjects::Components::Composer.new }
|
||||
let(:insert_datetime_modal) { PageObjects::Modals::InsertDateTime.new }
|
||||
|
||||
before do
|
||||
create_post(user: current_user, topic: topic, title: "Date range test post", raw: <<~RAW)
|
||||
|
@ -69,6 +72,85 @@ describe "Local dates", type: :system do
|
|||
end
|
||||
end
|
||||
|
||||
describe "insert modal" do
|
||||
let(:timezone) { "Australia/Brisbane" }
|
||||
|
||||
before do
|
||||
current_user.user_option.update!(timezone: timezone)
|
||||
sign_in(current_user)
|
||||
end
|
||||
|
||||
it "allows selecting a date without a time and inserts into the post" do
|
||||
topic_page.visit_topic_and_open_composer(topic)
|
||||
expect(topic_page).to have_expanded_composer
|
||||
composer.click_toolbar_button("local-dates")
|
||||
expect(insert_datetime_modal).to be_open
|
||||
insert_datetime_modal.calendar_date_time_picker.select_year(year)
|
||||
insert_datetime_modal.calendar_date_time_picker.select_day(16)
|
||||
insert_datetime_modal.click_primary_button
|
||||
expect(composer.composer_input.value).to have_content(
|
||||
"[date=#{Date.parse("#{year}-#{month}-16").strftime("%Y-%m-%d")} timezone=\"#{timezone}\"]",
|
||||
)
|
||||
end
|
||||
|
||||
it "allows selecting a date with a time and inserts into the post" do
|
||||
topic_page.visit_topic_and_open_composer(topic)
|
||||
expect(topic_page).to have_expanded_composer
|
||||
composer.click_toolbar_button("local-dates")
|
||||
expect(insert_datetime_modal).to be_open
|
||||
insert_datetime_modal.calendar_date_time_picker.select_year(year)
|
||||
insert_datetime_modal.calendar_date_time_picker.select_day(16)
|
||||
insert_datetime_modal.calendar_date_time_picker.fill_time("11:45am")
|
||||
insert_datetime_modal.click_primary_button
|
||||
|
||||
expect(composer.composer_input.value).to have_content(
|
||||
"[date=#{Date.parse("#{year}-#{month}-16").strftime("%Y-%m-%d")} time=11:45:00 timezone=\"#{timezone}\"]",
|
||||
)
|
||||
end
|
||||
|
||||
it "allows selecting a start date and time and an end date and time" do
|
||||
topic_page.visit_topic_and_open_composer(topic)
|
||||
expect(topic_page).to have_expanded_composer
|
||||
composer.click_toolbar_button("local-dates")
|
||||
expect(insert_datetime_modal).to be_open
|
||||
insert_datetime_modal.calendar_date_time_picker.select_year(year)
|
||||
insert_datetime_modal.calendar_date_time_picker.select_day(16)
|
||||
insert_datetime_modal.calendar_date_time_picker.fill_time("11:45am")
|
||||
insert_datetime_modal.select_to
|
||||
|
||||
insert_datetime_modal.calendar_date_time_picker.select_year(year)
|
||||
insert_datetime_modal.calendar_date_time_picker.select_day(23)
|
||||
insert_datetime_modal.calendar_date_time_picker.fill_time("12:45pm")
|
||||
|
||||
insert_datetime_modal.click_primary_button
|
||||
expect(composer.composer_input.value).to have_content(
|
||||
"[date-range from=#{Date.parse("#{year}-#{month}-16").strftime("%Y-%m-%d")}T11:45:00 to=#{Date.parse("#{year}-#{month}-23").strftime("%Y-%m-%d")}T12:45:00 timezone=\"#{timezone}\"]",
|
||||
)
|
||||
end
|
||||
|
||||
it "allows clearing the end date and time" do
|
||||
topic_page.visit_topic_and_open_composer(topic)
|
||||
expect(topic_page).to have_expanded_composer
|
||||
composer.click_toolbar_button("local-dates")
|
||||
expect(insert_datetime_modal).to be_open
|
||||
|
||||
insert_datetime_modal.calendar_date_time_picker.select_year(year)
|
||||
insert_datetime_modal.calendar_date_time_picker.select_day(16)
|
||||
insert_datetime_modal.calendar_date_time_picker.fill_time("11:45am")
|
||||
insert_datetime_modal.select_to
|
||||
|
||||
insert_datetime_modal.calendar_date_time_picker.select_year(year)
|
||||
insert_datetime_modal.calendar_date_time_picker.select_day(23)
|
||||
insert_datetime_modal.calendar_date_time_picker.fill_time("12:45pm")
|
||||
insert_datetime_modal.delete_to
|
||||
|
||||
insert_datetime_modal.click_primary_button
|
||||
expect(composer.composer_input.value).to have_content(
|
||||
"[date=#{Date.parse("#{year}-#{month}-16").strftime("%Y-%m-%d")} time=11:45:00 timezone=\"#{timezone}\"]",
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "bookmarks" do
|
||||
before do
|
||||
current_user.user_option.update!(timezone: "Asia/Singapore")
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module PageObjects
|
||||
module Modals
|
||||
class InsertDateTime < PageObjects::Modals::Base
|
||||
MODAL_CSS_CLASS = ".discourse-local-dates-create-modal"
|
||||
|
||||
def calendar_date_time_picker
|
||||
@calendar_date_time_picker ||=
|
||||
PageObjects::Components::CalendarDateTimePicker.new(MODAL_CSS_CLASS)
|
||||
end
|
||||
|
||||
def select_to
|
||||
find(".date-time-control.to").click
|
||||
end
|
||||
|
||||
def select_from
|
||||
find(".date-time-control.from").click
|
||||
end
|
||||
|
||||
def delete_to
|
||||
find(".delete-to-date").click
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -130,7 +130,7 @@ acceptance("Local Dates - composer", function (needs) {
|
|||
await click(".delete-to-date");
|
||||
|
||||
assert.notOk(
|
||||
query(".pika-table .is-selected"),
|
||||
query(".date-time-control.to.is-selected"),
|
||||
"deleting selected TO date works"
|
||||
);
|
||||
|
||||
|
|
|
@ -24,4 +24,6 @@
|
|||
|
||||
<StyleguideExample @title="<DatePicker>">
|
||||
<DatePicker @defaultDate="YYYY-MM-DD" />
|
||||
</StyleguideExample>
|
||||
</StyleguideExample>
|
||||
|
||||
<Styleguide::CalendarDateTimeInput />
|
|
@ -0,0 +1,34 @@
|
|||
<StyleguideExample @title="<CalendarDateTimeInput>">
|
||||
<Styleguide::Component>
|
||||
<CalendarDateTimeInput
|
||||
@datePickerId="styleguide"
|
||||
@date={{this.date}}
|
||||
@time={{this.time}}
|
||||
@minDate={{this.minDate}}
|
||||
@timeFormat={{this.timeFormat}}
|
||||
@dateFormat={{this.dateFormat}}
|
||||
@onChangeDate={{action this.changeDate}}
|
||||
@onChangeTime={{action this.changeTime}}
|
||||
/>
|
||||
</Styleguide::Component>
|
||||
|
||||
<Styleguide::Controls>
|
||||
<Styleguide::Controls::Row @name="Min date">
|
||||
<DatePicker @defaultDate="YYYY-MM-DD" @value={{this.minDate}} />
|
||||
</Styleguide::Controls::Row>
|
||||
|
||||
<Styleguide::Controls::Row @name="Date">
|
||||
<DatePicker @defaultDate="YYYY-MM-DD" @value={{this.date}} />
|
||||
</Styleguide::Controls::Row>
|
||||
|
||||
<Styleguide::Controls::Row @name="Time">
|
||||
<Input
|
||||
maxlength={{5}}
|
||||
placeholder="hh:mm"
|
||||
@type="time"
|
||||
@value={{this.time}}
|
||||
class="time-picker"
|
||||
/>
|
||||
</Styleguide::Controls::Row>
|
||||
</Styleguide::Controls>
|
||||
</StyleguideExample>
|
|
@ -0,0 +1,24 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class StyleguideCalendarDateTimeInput extends Component {
|
||||
@service currentUser;
|
||||
|
||||
@tracked dateFormat = "YYYY-MM-DD";
|
||||
@tracked timeFormat = "HH:mm:ss";
|
||||
@tracked date = null;
|
||||
@tracked time = null;
|
||||
@tracked minDate = null;
|
||||
|
||||
@action
|
||||
changeDate(date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
@action
|
||||
changeTime(time) {
|
||||
this.time = time;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module PageObjects
|
||||
module Components
|
||||
class CalendarDateTimePicker < PageObjects::Components::Base
|
||||
def initialize(context)
|
||||
@context = context
|
||||
end
|
||||
|
||||
def component
|
||||
find(@context)
|
||||
end
|
||||
|
||||
def select_day(day_number)
|
||||
component.find("button.pika-button.pika-day[data-pika-day='#{day_number}']").click
|
||||
end
|
||||
|
||||
def select_year(year)
|
||||
component
|
||||
.find(".pika-select-year", visible: false)
|
||||
.find("option[value='#{year}']")
|
||||
.select_option
|
||||
end
|
||||
|
||||
def fill_time(time)
|
||||
component.find(".time-picker").fill_in(with: time)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue