Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 123 additions & 18 deletions django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*global Calendar, findPosX, findPosY, get_format, gettext, gettext_noop, interpolate, ngettext, quickElement*/
/*global Calendar, CalendarNamespace, findPosX, findPosY, get_format, gettext, gettext_noop, interpolate, ngettext, quickElement*/
// Inserts shortcut buttons after all of the following:
// <input type="text" class="vDateField">
// <input type="text" class="vTimeField">
Expand Down Expand Up @@ -156,15 +156,19 @@
DateTimeShortcuts.openClock(num);
});

const clockIconId = DateTimeShortcuts.clockLinkName + num + "_icon";
quickElement(
"span",
clock_link,
"",
"id",
clockIconId,
"class",
"clock-icon",
"title",
gettext("Choose a Time"),
);
clock_link.setAttribute("aria-labelledby", clockIconId);
shortcuts_span.appendChild(document.createTextNode("\u00A0"));
shortcuts_span.appendChild(now_link);
shortcuts_span.appendChild(
Expand All @@ -175,23 +179,28 @@
// Create clock link div
//
// Markup looks like:
// <div id="clockbox1" class="clockbox module">
// <div id="clockbox1" class="clockbox module" role="dialog"
// aria-label="Choose a time">
// <h2>Choose a time</h2>
// <ul class="timelist">
// <li><a href="#">Now</a></li>
// <li><a href="#">Midnight</a></li>
// <li><a href="#">6 a.m.</a></li>
// <li><a href="#">Noon</a></li>
// <li><a href="#">6 p.m.</a></li>
// <li><a href="#" role="button">Now</a></li>
// <li><a href="#" role="button">Midnight</a></li>
// <li><a href="#" role="button">6 a.m.</a></li>
// <li><a href="#" role="button">Noon</a></li>
// <li><a href="#" role="button">6 p.m.</a></li>
// </ul>
// <p class="calendar-cancel"><a href="#">Cancel</a></p>
// <p class="calendar-cancel">
// <a href="#" role="button" aria-label="Close Clock">Cancel</a>
// </p>
// </div>

const clock_box = document.createElement("div");
clock_box.style.display = "none";
clock_box.style.position = "absolute";
clock_box.className = "clockbox module";
clock_box.id = DateTimeShortcuts.clockDivName + num;
clock_box.setAttribute("role", "dialog");
clock_box.setAttribute("aria-labelledby", clockIconId);
document.body.appendChild(clock_box);
clock_box.addEventListener("click", function (e) {
e.stopPropagation();
Expand Down Expand Up @@ -305,6 +314,15 @@
return true;
};

function getFormattedDate(offset) {
const d = DateTimeShortcuts.now();
d.setDate(d.getDate() + offset);
return CalendarNamespace.formatDate(
d.getDate(),
d.getMonth() + 1,
d.getFullYear(),
);
}
// Shortcut links (calendar icon and "Today" link)
const shortcuts_span = document.createElement("span");
shortcuts_span.className = DateTimeShortcuts.shortCutsClass;
Expand All @@ -313,6 +331,14 @@
today_link.href = "#";
today_link.role = "button";
today_link.appendChild(document.createTextNode(gettext("Today")));
today_link.setAttribute(
"aria-label",
interpolate(
gettext("Today (%(date)s)"),
{ date: getFormattedDate(0) },
true,
),
);
today_link.addEventListener("click", function (e) {
e.preventDefault();
DateTimeShortcuts.handleCalendarQuickLink(num, 0);
Expand All @@ -326,15 +352,20 @@
e.stopPropagation();
DateTimeShortcuts.openCalendar(num);
});
const calIconId =
DateTimeShortcuts.calendarLinkName + num + "_icon";
quickElement(
"span",
cal_link,
"",
"id",
calIconId,
"class",
"date-icon",
"title",
gettext("Choose a Date"),
);
cal_link.setAttribute("aria-labelledby", calIconId);
shortcuts_span.appendChild(document.createTextNode("\u00A0"));
shortcuts_span.appendChild(today_link);
shortcuts_span.appendChild(
Expand All @@ -346,24 +377,38 @@
//
// Markup looks like:
//
// <div id="calendarbox3" class="calendarbox module">
// <h2>
// <a href="#" class="link-previous">&lsaquo;</a>
// <a href="#" class="link-next">&rsaquo;</a> February 2003
// </h2>
// <div id="calendarbox3" class="calendarbox module"
// role="dialog" aria-label="Choose a Date">
// <div>
// <a href="#" class="calendarnav-previous"
// aria-label="Previous May">&lsaquo;</a>
// <a href="#" class="calendarnav-next"
// aria-label="Next July">&rsaquo;</a>
// </div>
// <div class="calendar" id="calendarin3">
// <!-- (cal) -->
// </div>
// <div class="calendar-shortcuts">
// <a href="#">Yesterday</a> | <a href="#">Today</a> | <a href="#">Tomorrow</a>
// <a href="#" role="button"
// aria-label="Yesterday (June 14, 2025)">Yesterday</a>
// |
// <a href="#" role="button"
// aria-label="Today (June 15, 2025)">Today</a>
// |
// <a href="#" role="button"
// aria-label="Tomorrow (June 16, 2025)">Tomorrow</a>
// </div>
// <p class="calendar-cancel"><a href="#">Cancel</a></p>
// <p class="calendar-cancel">
// <a href="#" role="button" aria-label="Close Calendar">Cancel</a>
// </p>
// </div>
const cal_box = document.createElement("div");
cal_box.style.display = "none";
cal_box.style.position = "absolute";
cal_box.className = "calendarbox module";
cal_box.id = DateTimeShortcuts.calendarDivName1 + num;
cal_box.setAttribute("role", "dialog");
cal_box.setAttribute("aria-labelledby", calIconId);
document.body.appendChild(cal_box);
cal_box.addEventListener("click", function (e) {
e.stopPropagation();
Expand Down Expand Up @@ -412,6 +457,14 @@
"href",
"#",
);
day_link.setAttribute(
"aria-label",
interpolate(
gettext("Yesterday (%(date)s)"),
{ date: getFormattedDate(-1) },
true,
),
);
day_link.addEventListener("click", function (e) {
e.preventDefault();
DateTimeShortcuts.handleCalendarQuickLink(num, -1);
Expand All @@ -426,6 +479,14 @@
"href",
"#",
);
day_link.setAttribute(
"aria-label",
interpolate(
gettext("Today (%(date)s)"),
{ date: getFormattedDate(0) },
true,
),
);
day_link.addEventListener("click", function (e) {
e.preventDefault();
DateTimeShortcuts.handleCalendarQuickLink(num, 0);
Expand All @@ -440,6 +501,14 @@
"href",
"#",
);
day_link.setAttribute(
"aria-label",
interpolate(
gettext("Tomorrow (%(date)s)"),
{ date: getFormattedDate(1) },
true,
),
);
day_link.addEventListener("click", function (e) {
e.preventDefault();
DateTimeShortcuts.handleCalendarQuickLink(num, +1);
Expand Down Expand Up @@ -469,6 +538,41 @@
}
});
},
updateNavAriaLabels: function (num) {
const cal = DateTimeShortcuts.calendars[num];
const cal_box = document.getElementById(
DateTimeShortcuts.calendarDivName1 + num,
);
const prevMonth =
CalendarNamespace.monthsOfYear[(cal.currentMonth + 10) % 12];
const prevYear =
cal.currentMonth === 1 ? cal.currentYear - 1 : cal.currentYear;
cal_box
.querySelector(".calendarnav-previous")
.setAttribute(
"aria-label",
interpolate(
gettext("Previous (%(month)s %(year)s)"),
{ month: prevMonth, year: prevYear },
true,
),
);

const nextMonth =
CalendarNamespace.monthsOfYear[cal.currentMonth % 12];
const nextYear =
cal.currentMonth === 12 ? cal.currentYear + 1 : cal.currentYear;
cal_box
.querySelector(".calendarnav-next")
.setAttribute(
"aria-label",
interpolate(
gettext("Next (%(month)s %(year)s)"),
{ month: nextMonth, year: nextYear },
true,
),
);
},
openCalendar: function (num) {
const cal_box = document.getElementById(
DateTimeShortcuts.calendarDivName1 + num,
Expand Down Expand Up @@ -507,6 +611,7 @@
cal_box.style.top = Math.max(0, findPosY(cal_link) - 75) + "px";

cal_box.style.display = "block";
DateTimeShortcuts.updateNavAriaLabels(num);
document.addEventListener(
"click",
DateTimeShortcuts.dismissCalendarFunc[num],
Expand All @@ -523,9 +628,11 @@
},
drawPrev: function (num) {
DateTimeShortcuts.calendars[num].drawPreviousMonth();
DateTimeShortcuts.updateNavAriaLabels(num);
},
drawNext: function (num) {
DateTimeShortcuts.calendars[num].drawNextMonth();
DateTimeShortcuts.updateNavAriaLabels(num);
},
handleCalendarCallback: function (num) {
const format = get_format("DATE_INPUT_FORMATS")[0];
Expand All @@ -536,9 +643,7 @@
d,
).strftime(format);
DateTimeShortcuts.calendarInputs[num].focus();
document.getElementById(
DateTimeShortcuts.calendarDivName1 + num,
).style.display = "none";
DateTimeShortcuts.dismissCalendar(num);
};
},
handleCalendarQuickLink: function (num, offset) {
Expand Down
50 changes: 44 additions & 6 deletions django/contrib/admin/static/admin/js/calendar.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*global gettext, pgettext, get_format, quickElement, removeChildren*/
/*global gettext, pgettext, get_format, interpolate, quickElement, removeChildren*/
/*
calendar.js - Calendar functions by Adrian Holovaty
depends on core.js for utility functions like removeChildren or quickElement
Expand Down Expand Up @@ -92,6 +92,17 @@ depends on core.js for utility functions like removeChildren or quickElement
}
return days;
},
formatDate: function (day, month, year) {
return interpolate(
gettext("%(month)s %(day)s, %(year)s"),
{
month: CalendarNamespace.monthsOfYear[month - 1],
day: day,
year: year,
},
true,
);
},
draw: function (month, year, div_id, callback, selected) {
// month = 1-12, year = 1-9999
const today = new Date();
Expand Down Expand Up @@ -133,13 +144,16 @@ depends on core.js for utility functions like removeChildren or quickElement
// Draw days-of-week header
let tableRow = quickElement("tr", tableBody);
for (let i = 0; i < 7; i++) {
quickElement(
"th",
tableRow,
const dayAbbrev =
CalendarNamespace.daysOfWeekAbbrev[
(i + CalendarNamespace.firstDayOfWeek) % 7
];
const dayInitial =
CalendarNamespace.daysOfWeekInitial[
(i + CalendarNamespace.firstDayOfWeek) % 7
],
);
];
const th = quickElement("th", tableRow, dayInitial);
th.setAttribute("aria-label", dayAbbrev);
}

const startingPos = new Date(
Expand Down Expand Up @@ -206,6 +220,30 @@ depends on core.js for utility functions like removeChildren or quickElement
"href",
"#",
);
let ariaLabel = CalendarNamespace.formatDate(
currentDay,
month,
year,
);
const isToday =
currentDay === todayDay &&
month === todayMonth &&
year === todayYear;
const isSelected =
isSelectedMonth && currentDay === selected.getUTCDate();
if (isToday && isSelected) {
ariaLabel = interpolate(
gettext("%s (today, current selection)"),
[ariaLabel],
);
} else if (isToday) {
ariaLabel = interpolate(gettext("%s (today)"), [ariaLabel]);
} else if (isSelected) {
ariaLabel = interpolate(gettext("%s (current selection)"), [
ariaLabel,
]);
}
link.setAttribute("aria-label", ariaLabel);
link.addEventListener("click", calendarMonth(year, month));
currentDay++;
}
Expand Down
10 changes: 8 additions & 2 deletions django/contrib/auth/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from django.contrib.auth.backends import RemoteUserBackend
from django.contrib.auth.views import redirect_to_login
from django.core.exceptions import ImproperlyConfigured
from django.core.handlers.asgi import ASGIRequest
from django.shortcuts import resolve_url
from django.utils.deprecation import MiddlewareMixin
from django.utils.functional import SimpleLazyObject
Expand Down Expand Up @@ -141,7 +142,7 @@ def process_request(self, request):
f" before the {self.__class__.__name__} class."
)
try:
username = request.META[self.header]
username = self.get_username(request)
except KeyError:
# If specified header doesn't exist then remove any existing
# authenticated remote-user, or return (leaving request.user set to
Expand Down Expand Up @@ -183,7 +184,7 @@ async def aprocess_request(self, request):
f" before the {self.__class__.__name__} class."
)
try:
username = request.META["HTTP_" + self.header]
username = self.get_username(request)
except KeyError:
# If specified header doesn't exist then remove any existing
# authenticated remote-user, or return (leaving request.user set to
Expand Down Expand Up @@ -236,6 +237,11 @@ async def aclean_username(self, username, request):
pass
return username

def get_username(self, request):
if isinstance(request, ASGIRequest):
return request.META["HTTP_" + self.header]
return request.META[self.header]

def _remove_invalid_user(self, request):
"""
Remove the current authenticated user in the request which is invalid
Expand Down
Loading
Loading