Skip to content

Commit

Permalink
Merge pull request #2351 from drgrice1/empty-date-fill
Browse files Browse the repository at this point in the history
Fill in empty dates with valid dates for date picker groups.
  • Loading branch information
pstaabp authored Mar 20, 2024
2 parents a0584d1 + aefa295 commit 07e6c7b
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 38 deletions.
68 changes: 37 additions & 31 deletions htdocs/js/DatePicker/datepicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,39 +24,48 @@
const name = open_rule.name.replace('.open_date', '');

const groupRules = [
open_rule,
document.querySelector('input[id="' + name + '.due_date_id"]'),
document.querySelector('input[id="' + name + '.answer_date_id"]')
[open_rule],
[document.getElementById(`${name}.due_date_id`)],
[document.getElementById(`${name}.answer_date_id`)]
];

const reduced_rule = document.querySelector('input[id="' + name + '.reduced_scoring_date_id"]');
if (reduced_rule) groupRules.splice(1, 0, reduced_rule);
const reduced_rule = document.getElementById(`${name}.reduced_scoring_date_id`);
if (reduced_rule) groupRules.splice(1, 0, [reduced_rule]);

// Compute the time difference between the current browser timezone and the course timezone.
// flatpickr gives the time in the browser's timezone, and this is used to adjust to the course timezone.
// Note that this is in seconds.
const timezoneAdjustment =
new Date(new Date().toLocaleString('en-US')).getTime() -
new Date(
new Date().toLocaleString('en-US', { timeZone: open_rule.dataset.timezone ?? 'America/New_York' })
).getTime();

for (const rule of groupRules) {
const value =
rule[0].value || document.getElementsByName(`${rule[0].name}.class_value`)[0]?.dataset.classValue;
rule.push(value ? parseInt(value) * 1000 - timezoneAdjustment : 0);
}

const update = () => {
for (let i = 1; i < groupRules.length; ++i) {
const prevFieldDate = groupRules[i - 1].parentNode._flatpickr.selectedDates[0];
const thisFieldDate = groupRules[i].parentNode._flatpickr.selectedDates[0];
const prevFieldDate =
groupRules[i - 1][0]?.parentNode._flatpickr.selectedDates[0]?.getTime() || groupRules[i - 1][1];
const thisFieldDate =
groupRules[i][0]?.parentNode._flatpickr.selectedDates[0]?.getTime() || groupRules[i][1];
if (prevFieldDate && thisFieldDate && prevFieldDate > thisFieldDate) {
groupRules[i].parentNode._flatpickr.setDate(prevFieldDate, true);
groupRules[i][0].parentNode._flatpickr.setDate(prevFieldDate, true);
}
}
};

for (const rule of groupRules) {
const orig_value = rule.value;

luxon.Settings.defaultLocale = rule.dataset.locale ?? 'en';
const orig_value = rule[0].value;
let fallbackDate = rule[1] ? new Date(rule[1]) : new Date();

// Compute the time difference between the current browser timezone and the course timezone.
// flatpickr gives the time in the browser's timezone, and this is used to adjust to the course timezone.
// Note that this is in seconds.
const timezoneAdjustment =
new Date(new Date().toLocaleString('en-US')).getTime() -
new Date(
new Date().toLocaleString('en-US', { timeZone: rule.dataset.timezone ?? 'America/New_York' })
).getTime();
luxon.Settings.defaultLocale = rule[0].dataset.locale ?? 'en';

const fp = flatpickr(rule.parentNode, {
const fp = flatpickr(rule[0].parentNode, {
allowInput: true,
enableTime: true,
minuteIncrement: 1,
Expand All @@ -74,15 +83,15 @@
disableMobile: true,
wrap: true,
plugins: [
new confirmDatePlugin({ confirmText: rule.dataset.doneText ?? 'Done', showAlways: true }),
new confirmDatePlugin({ confirmText: rule[0].dataset.doneText ?? 'Done', showAlways: true }),
new ShortcutButtonsPlugin({
button: [
{
label: rule.dataset.todayText ?? 'Today',
label: rule[0].dataset.todayText ?? 'Today',
attributes: { class: 'btn btn-sm btn-secondary ms-auto me-1 mb-1' }
},
{
label: rule.dataset.nowText ?? 'Now',
label: rule[0].dataset.nowText ?? 'Now',
attributes: { class: 'btn btn-sm btn-secondary me-auto mb-1' }
}
],
Expand All @@ -101,12 +110,12 @@
}
})
],
onChange(selectedDates) {
onChange() {
if (this.input.value === orig_value) this.altInput.classList.remove('changed');
else this.altInput.classList.add('changed');
},
onClose: update,
onReady(selectedDates) {
onReady() {
// Flatpickr hides the original input and adds the alternate input after it. That messes up the
// bootstrap input group styling. So move the now hidden original input after the created alternate
// input to fix that.
Expand All @@ -133,17 +142,14 @@
// Next attempt to parse the datestr with the current format. This should not be adjusted. It is
// for display only.
const date = luxon.DateTime.fromFormat(datestr.replaceAll(/\u202F/g, ' ').trim(), format);
if (date.isValid) return date.toJSDate();
if (date.isValid) fallbackDate = date.toJSDate();

// Finally, fall back to the previous value in the original input if that failed. This is the case
// that the user typed a time that isn't in the valid format. So fallback to the last valid time
// that was displayed. This also should not be adjusted.
return new Date(this.lastFormattedDate.getTime());
return fallbackDate;
},
formatDate(date, format) {
// Save this date for the fallback in parseDate.
this.lastFormattedDate = date;

// In this case the date provided is in the browser's time zone. So it needs to be adjusted to the
// timezone of the course.
if (format === 'U') return (date.getTime() + timezoneAdjustment) / 1000;
Expand All @@ -154,7 +160,7 @@
}
});

rule.nextElementSibling.addEventListener('keydown', (e) => {
rule[0].nextElementSibling.addEventListener('keydown', (e) => {
if (e.key === ' ' || e.key === 'Enter') {
e.preventDefault();
fp.open();
Expand Down
11 changes: 6 additions & 5 deletions htdocs/js/ProblemSetList/problemsetlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@
new Date().toLocaleString('en-US', { timeZone: importDateShift.dataset.timezone ?? 'America/New_York' })
).getTime();

let fallbackDate = importDateShift.value
? new Date(parseInt(importDateShift.value) * 1000 - timezoneAdjustment)
: new Date();

const fp = flatpickr(importDateShift.parentNode, {
allowInput: true,
enableTime: true,
Expand Down Expand Up @@ -248,17 +252,14 @@
// Next attempt to parse the datestr with the current format. This should not be adjusted. It is
// for display only.
const date = luxon.DateTime.fromFormat(datestr.replaceAll(/\u202F/g, ' ').trim(), format);
if (date.isValid) return date.toJSDate();
if (date.isValid) fallbackDate = date.toJSDate();

// Finally, fall back to the previous value in the original input if that failed. This is the case
// that the user typed a time that isn't in the valid format. So fallback to the last valid time
// that was displayed. This also should not be adjusted.
return new Date(this.lastFormattedDate.getTime());
return fallbackDate;
},
formatDate(date, format) {
// Save this date for the fallback in parseDate.
this.lastFormattedDate = date;

// In this case the date provided is in the browser's time zone. So it needs to be adjusted to the
// timezone of the course.
if (format === 'U') return (date.getTime() + timezoneAdjustment) / 1000;
Expand Down
3 changes: 2 additions & 1 deletion lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1015,7 +1015,8 @@ sub fieldHTML ($c, $userID, $setID, $problemID, $globalRecord, $userRecord, $fie
size => $properties{size} || 5,
class => 'form-control-plaintext form-control-sm',
'aria-labelledby' => "$recordType.$recordID.$field.label",
$field =~ /date/ || $field eq 'restricted_release' || $field eq 'source_file' ? (dir => 'ltr') : ()
$field =~ /date/ || $field eq 'restricted_release' || $field eq 'source_file' ? (dir => 'ltr') : (),
data => { class_value => $globalValue }
)
: ''
) if $forUsers;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
id => "set.$setID.$field.class_value", readonly => undef, dir => 'ltr',
class => 'form-control-plaintext form-control-sm w-auto',
size => 16,
defined $userRecord ? ('aria-labelledby' => "set.$setID.${field}_id") : () =%>
defined $userRecord ? ('aria-labelledby' => "set.$setID.${field}_id") : (),
data => { class_value => $globalRecord->$field } =%>
</td>
% }
% if (defined $userRecord) {
Expand Down

0 comments on commit 07e6c7b

Please sign in to comment.