style(web): polish native date, time and file inputs
This commit is contained in:
@@ -554,6 +554,271 @@
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
* { transition: none !important; }
|
||||
}
|
||||
|
||||
/* --- Native form control polish (date / time / file) --- */
|
||||
/* HTML5 date and time inputs have a native popup that is drawn by
|
||||
the OS and cannot be themed. We polish the input itself so it
|
||||
matches the rest of the design and replace the OS picker
|
||||
indicator with a themed one. The JS below replaces the popup
|
||||
with a fully custom one when JavaScript runs. */
|
||||
input[type="date"],
|
||||
input[type="time"],
|
||||
input[type="datetime-local"] {
|
||||
font: inherit;
|
||||
font-size: 0.85rem;
|
||||
color: var(--fg);
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
padding: 0.55rem 0.75rem;
|
||||
width: 100%;
|
||||
font-feature-settings: normal;
|
||||
transition: border-color 0.12s, box-shadow 0.12s;
|
||||
}
|
||||
input[type="date"]:focus,
|
||||
input[type="time"]:focus,
|
||||
input[type="datetime-local"]:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent);
|
||||
box-shadow: var(--ring);
|
||||
}
|
||||
input[type="date"]::-webkit-calendar-picker-indicator,
|
||||
input[type="time"]::-webkit-calendar-picker-indicator,
|
||||
input[type="datetime-local"]::-webkit-calendar-picker-indicator {
|
||||
opacity: 0.5;
|
||||
cursor: pointer;
|
||||
padding: 0 0.2rem;
|
||||
margin: 0;
|
||||
filter: invert(0.45);
|
||||
transition: opacity 0.12s;
|
||||
}
|
||||
input[type="date"]:hover::-webkit-calendar-picker-indicator,
|
||||
input[type="time"]:hover::-webkit-calendar-picker-indicator,
|
||||
input[type="datetime-local"]:hover::-webkit-calendar-picker-indicator {
|
||||
opacity: 1;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
input[type="date"]::-webkit-calendar-picker-indicator,
|
||||
input[type="time"]::-webkit-calendar-picker-indicator,
|
||||
input[type="datetime-local"]::-webkit-calendar-picker-indicator {
|
||||
filter: invert(0.85);
|
||||
}
|
||||
}
|
||||
/* Firefox draws a small inner "X" clear button — tone it down. */
|
||||
input[type="date"]::-moz-clear,
|
||||
input[type="time"]::-moz-clear { opacity: 0.5; }
|
||||
|
||||
input[type="file"] {
|
||||
font: inherit;
|
||||
font-size: 0.82rem;
|
||||
color: var(--fg-muted);
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
padding: 0.5rem 0.75rem;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.12s, box-shadow 0.12s;
|
||||
}
|
||||
input[type="file"]:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent);
|
||||
box-shadow: var(--ring);
|
||||
}
|
||||
input[type="file"]::file-selector-button {
|
||||
font: inherit;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 550;
|
||||
padding: 0.4rem 0.75rem;
|
||||
margin-right: 0.7rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--surface-2);
|
||||
color: var(--fg);
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: background 0.12s, border-color 0.12s, color 0.12s;
|
||||
}
|
||||
input[type="file"]::file-selector-button:hover {
|
||||
background: var(--surface);
|
||||
border-color: var(--border-strong);
|
||||
}
|
||||
input[type="file"]::file-selector-button:active { transform: translateY(1px); }
|
||||
/* Firefox variant of the file selector button pseudo-element. */
|
||||
input[type="file"]::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 550;
|
||||
padding: 0.4rem 0.75rem;
|
||||
margin-right: 0.7rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--surface-2);
|
||||
color: var(--fg);
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
/* --- Custom date picker (progressive enhancement) --- */
|
||||
.date-input { position: relative; }
|
||||
.date-input__native { display: none; }
|
||||
.date-input__btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.55rem;
|
||||
width: 100%;
|
||||
font: inherit;
|
||||
font-size: 0.85rem;
|
||||
text-align: left;
|
||||
background: var(--surface);
|
||||
color: var(--fg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
padding: 0.55rem 0.75rem;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: border-color 0.12s, box-shadow 0.12s, background 0.12s;
|
||||
}
|
||||
.date-input__btn:hover { border-color: var(--border-strong); }
|
||||
.date-input__btn:focus-visible {
|
||||
outline: none;
|
||||
border-color: var(--accent);
|
||||
box-shadow: var(--ring);
|
||||
}
|
||||
.date-input__btn[data-empty="1"] { color: var(--fg-subtle); }
|
||||
.date-input__label { flex: 1; min-width: 0; }
|
||||
.date-input__icon {
|
||||
display: inline-flex;
|
||||
color: var(--fg-muted);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.date-input__icon svg { width: 16px; height: 16px; display: block; }
|
||||
|
||||
.date-input__popover {
|
||||
position: absolute;
|
||||
z-index: 20;
|
||||
top: calc(100% + 6px);
|
||||
left: 0;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 0.85rem;
|
||||
box-shadow: var(--shadow-lg);
|
||||
min-width: 280px;
|
||||
user-select: none;
|
||||
}
|
||||
.date-input__nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.date-input__nav-title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
color: var(--fg);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
.date-input__nav-btn {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: transparent;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--fg-muted);
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: background 0.12s, color 0.12s, border-color 0.12s;
|
||||
}
|
||||
.date-input__nav-btn:hover {
|
||||
background: var(--surface-2);
|
||||
color: var(--fg);
|
||||
border-color: var(--border-strong);
|
||||
}
|
||||
.date-input__nav-btn svg { width: 14px; height: 14px; }
|
||||
.date-input__weekdays,
|
||||
.date-input__days {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
gap: 2px;
|
||||
}
|
||||
.date-input__weekday {
|
||||
font-size: 0.68rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
color: var(--fg-subtle);
|
||||
text-align: center;
|
||||
padding: 0.35rem 0 0.4rem;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
.date-input__day {
|
||||
height: 32px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font: inherit;
|
||||
font-size: 0.82rem;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--fg);
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: background 0.1s, color 0.1s;
|
||||
}
|
||||
.date-input__day:hover { background: var(--surface-2); }
|
||||
.date-input__day[data-other-month="1"] { color: var(--fg-subtle); }
|
||||
.date-input__day[data-today="1"] {
|
||||
border: 1px solid var(--border-strong);
|
||||
}
|
||||
.date-input__day[data-selected="1"] {
|
||||
background: var(--accent);
|
||||
color: var(--on-accent);
|
||||
}
|
||||
.date-input__day[data-selected="1"]:hover { background: var(--accent-hover); }
|
||||
.date-input__day:focus-visible {
|
||||
outline: none;
|
||||
box-shadow: var(--ring);
|
||||
}
|
||||
.date-input__footer {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
margin-top: 0.85rem;
|
||||
padding-top: 0.65rem;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
.date-input__footer-btn {
|
||||
font: inherit;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 550;
|
||||
flex: 1;
|
||||
padding: 0.4rem 0.6rem;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
color: var(--fg-muted);
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: background 0.12s, color 0.12s, border-color 0.12s;
|
||||
}
|
||||
.date-input__footer-btn:hover {
|
||||
background: var(--surface-2);
|
||||
color: var(--fg);
|
||||
border-color: var(--border-strong);
|
||||
}
|
||||
.date-input__footer-btn--primary {
|
||||
background: var(--accent);
|
||||
color: var(--on-accent);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
.date-input__footer-btn--primary:hover {
|
||||
background: var(--accent-hover);
|
||||
border-color: var(--accent-hover);
|
||||
color: var(--on-accent);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -660,5 +925,333 @@
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<script>
|
||||
/* Custom date picker — replaces <input type="date" class="input"> with
|
||||
a styled trigger that opens a popover calendar matching the design
|
||||
system. The native input is hidden but kept in the DOM so form
|
||||
submission works the same way with or without JavaScript. */
|
||||
(function () {
|
||||
var MONTH_CACHE = {};
|
||||
var WEEK_CACHE = {};
|
||||
var FIRSTDAY_CACHE = {};
|
||||
|
||||
function langFor(node) {
|
||||
var n = node;
|
||||
while (n && n.nodeType === 1) {
|
||||
var l = n.getAttribute("lang");
|
||||
if (l) return l;
|
||||
n = n.parentNode;
|
||||
}
|
||||
return document.documentElement.lang || "en";
|
||||
}
|
||||
|
||||
function monthNames(lang) {
|
||||
if (!MONTH_CACHE[lang]) {
|
||||
try {
|
||||
var fmt = new Intl.DateTimeFormat(lang, { month: "long" });
|
||||
MONTH_CACHE[lang] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].map(function (i) {
|
||||
return fmt.format(new Date(2000, i, 15));
|
||||
});
|
||||
} catch (e) {
|
||||
MONTH_CACHE[lang] = [
|
||||
"January", "February", "March", "April", "May", "June",
|
||||
"July", "August", "September", "October", "November", "December"
|
||||
];
|
||||
}
|
||||
}
|
||||
return MONTH_CACHE[lang];
|
||||
}
|
||||
|
||||
function weekdayNames(lang, firstDay) {
|
||||
var key = lang + "|" + firstDay;
|
||||
if (!WEEK_CACHE[key]) {
|
||||
try {
|
||||
var fmt = new Intl.DateTimeFormat(lang, { weekday: "short" });
|
||||
var base = [1, 2, 3, 4, 5, 6, 7]; // 2001-01-01 was Monday, so 1..7 = Mon..Sun
|
||||
var all = base.map(function (d) { return fmt.format(new Date(2001, 0, d)); });
|
||||
var offset = firstDay - 1;
|
||||
WEEK_CACHE[key] = all.slice(offset).concat(all.slice(0, offset));
|
||||
} catch (e) {
|
||||
WEEK_CACHE[key] = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
|
||||
}
|
||||
}
|
||||
return WEEK_CACHE[key];
|
||||
}
|
||||
|
||||
function firstDay(lang) {
|
||||
if (!FIRSTDAY_CACHE[lang]) {
|
||||
try {
|
||||
var info = new Intl.Locale(lang).getWeekInfo();
|
||||
FIRSTDAY_CACHE[lang] = (info && typeof info.firstDay === "number")
|
||||
? info.firstDay : 1;
|
||||
} catch (e) {
|
||||
var monFirst = {
|
||||
cs: 1, sk: 1, sl: 1, hr: 1, sr: 1, bs: 1, de: 1, fr: 1, es: 1,
|
||||
it: 1, nl: 1, pl: 1, pt: 1, ru: 1, uk: 1, sq: 1, sv: 1, no: 1, da: 1
|
||||
};
|
||||
FIRSTDAY_CACHE[lang] = monFirst[lang] || 7;
|
||||
}
|
||||
}
|
||||
return FIRSTDAY_CACHE[lang];
|
||||
}
|
||||
|
||||
function formatDate(lang, d) {
|
||||
try {
|
||||
return new Intl.DateTimeFormat(lang, {
|
||||
day: "numeric", month: "long", year: "numeric"
|
||||
}).format(d);
|
||||
} catch (e) {
|
||||
return d.toDateString();
|
||||
}
|
||||
}
|
||||
|
||||
function parseISO(s) {
|
||||
if (!s || !/^\d{4}-\d{2}-\d{2}$/.test(s)) return null;
|
||||
var p = s.split("-");
|
||||
var d = new Date(Number(p[0]), Number(p[1]) - 1, Number(p[2]));
|
||||
return isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
|
||||
function toISO(d) {
|
||||
var y = d.getFullYear();
|
||||
var m = String(d.getMonth() + 1).padStart(2, "0");
|
||||
var dd = String(d.getDate()).padStart(2, "0");
|
||||
return y + "-" + m + "-" + dd;
|
||||
}
|
||||
|
||||
function sameDay(a, b) {
|
||||
return !!a && !!b &&
|
||||
a.getFullYear() === b.getFullYear() &&
|
||||
a.getMonth() === b.getMonth() &&
|
||||
a.getDate() === b.getDate();
|
||||
}
|
||||
|
||||
function todayMidnight() {
|
||||
var n = new Date();
|
||||
return new Date(n.getFullYear(), n.getMonth(), n.getDate());
|
||||
}
|
||||
|
||||
function svg(icon) {
|
||||
var paths = {
|
||||
chevronLeft: '<polyline points="15 18 9 12 15 6"/>',
|
||||
chevronRight: '<polyline points="9 18 15 12 9 6"/>',
|
||||
calendar:
|
||||
'<rect x="3" y="4" width="18" height="18" rx="2" ry="2"/>' +
|
||||
'<line x1="16" y1="2" x2="16" y2="6"/>' +
|
||||
'<line x1="8" y1="2" x2="8" y2="6"/>' +
|
||||
'<line x1="3" y1="10" x2="21" y2="10"/>'
|
||||
};
|
||||
return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" '
|
||||
+ 'stroke-width="2" stroke-linecap="round" stroke-linejoin="round" '
|
||||
+ 'aria-hidden="true">' + (paths[icon] || "") + "</svg>";
|
||||
}
|
||||
|
||||
function buildPicker(input) {
|
||||
if (input.dataset.volumenPicker === "1") return;
|
||||
input.dataset.volumenPicker = "1";
|
||||
|
||||
var lang = langFor(input);
|
||||
var initial = parseISO(input.value || "");
|
||||
var weekdayStart = firstDay(lang);
|
||||
|
||||
var wrap = document.createElement("div");
|
||||
wrap.className = "date-input";
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className = "date-input__btn";
|
||||
button.setAttribute("aria-haspopup", "dialog");
|
||||
button.setAttribute("aria-expanded", "false");
|
||||
|
||||
var labelEl = document.createElement("span");
|
||||
labelEl.className = "date-input__label";
|
||||
button.appendChild(labelEl);
|
||||
|
||||
var iconEl = document.createElement("span");
|
||||
iconEl.className = "date-input__icon";
|
||||
iconEl.innerHTML = svg("calendar");
|
||||
button.appendChild(iconEl);
|
||||
|
||||
var pop = document.createElement("div");
|
||||
pop.className = "date-input__popover";
|
||||
pop.setAttribute("role", "dialog");
|
||||
pop.setAttribute("aria-label", "Pick a date");
|
||||
pop.hidden = true;
|
||||
pop.innerHTML =
|
||||
'<div class="date-input__nav">' +
|
||||
'<button type="button" class="date-input__nav-btn" data-prev '
|
||||
+ 'aria-label="Previous month">' + svg("chevronLeft") + "</button>" +
|
||||
'<div class="date-input__nav-title"></div>' +
|
||||
'<button type="button" class="date-input__nav-btn" data-next '
|
||||
+ 'aria-label="Next month">' + svg("chevronRight") + "</button>" +
|
||||
"</div>" +
|
||||
'<div class="date-input__weekdays"></div>' +
|
||||
'<div class="date-input__days"></div>' +
|
||||
'<div class="date-input__footer">' +
|
||||
'<button type="button" class="date-input__footer-btn" data-clear>'
|
||||
+ (lang === "cs" ? "Vymazat" : "Clear") + "</button>" +
|
||||
'<button type="button" class="date-input__footer-btn '
|
||||
+ 'date-input__footer-btn--primary" data-today>'
|
||||
+ (lang === "cs" ? "Dnes" : "Today") + "</button>" +
|
||||
"</div>";
|
||||
|
||||
var weekdaysEl = pop.querySelector(".date-input__weekdays");
|
||||
var daysEl = pop.querySelector(".date-input__days");
|
||||
var titleEl = pop.querySelector(".date-input__nav-title");
|
||||
|
||||
var viewYear, viewMonth, selected = initial;
|
||||
|
||||
function resetView() {
|
||||
var ref = selected || todayMidnight();
|
||||
viewYear = ref.getFullYear();
|
||||
viewMonth = ref.getMonth();
|
||||
}
|
||||
resetView();
|
||||
|
||||
function renderLabel() {
|
||||
if (selected) {
|
||||
labelEl.textContent = formatDate(lang, selected);
|
||||
button.dataset.empty = "0";
|
||||
} else {
|
||||
labelEl.textContent = input.placeholder || (lang === "cs" ? "Vyberte datum" : "Pick a date");
|
||||
button.dataset.empty = "1";
|
||||
}
|
||||
}
|
||||
|
||||
function renderMonth() {
|
||||
titleEl.textContent = monthNames(lang)[viewMonth] + " " + viewYear;
|
||||
weekdaysEl.innerHTML = weekdayNames(lang, weekdayStart)
|
||||
.map(function (w) { return '<div class="date-input__weekday">' + w + "</div>"; })
|
||||
.join("");
|
||||
|
||||
var first = new Date(viewYear, viewMonth, 1);
|
||||
var firstWd = ((first.getDay() - weekdayStart + 7) % 7) + 1; // 1..7
|
||||
var start = new Date(viewYear, viewMonth, 1 - (firstWd - 1));
|
||||
var today = todayMidnight();
|
||||
var cells = [];
|
||||
for (var i = 0; i < 42; i++) {
|
||||
var d = new Date(start.getFullYear(), start.getMonth(), start.getDate() + i);
|
||||
var attrs = ' class="date-input__day" data-iso="' + toISO(d) + '"';
|
||||
if (d.getMonth() !== viewMonth) attrs += ' data-other-month="1"';
|
||||
if (sameDay(d, today)) attrs += ' data-today="1"';
|
||||
if (sameDay(d, selected)) attrs += ' data-selected="1"';
|
||||
attrs += ' tabindex="-1" type="button"';
|
||||
cells.push("<button" + attrs + ">" + d.getDate() + "</button>");
|
||||
}
|
||||
daysEl.innerHTML = cells.join("");
|
||||
}
|
||||
|
||||
function commit(d) {
|
||||
selected = d;
|
||||
input.value = toISO(d);
|
||||
renderLabel();
|
||||
renderMonth();
|
||||
input.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
}
|
||||
|
||||
function open() {
|
||||
if (!pop.hidden) return;
|
||||
resetView();
|
||||
renderMonth();
|
||||
pop.hidden = false;
|
||||
button.setAttribute("aria-expanded", "true");
|
||||
}
|
||||
|
||||
function close() {
|
||||
if (pop.hidden) return;
|
||||
pop.hidden = true;
|
||||
button.setAttribute("aria-expanded", "false");
|
||||
}
|
||||
|
||||
function onDocClick(e) {
|
||||
if (!wrap.contains(e.target)) close();
|
||||
}
|
||||
|
||||
function onDocKey(e) {
|
||||
if (e.key === "Escape" && !pop.hidden) {
|
||||
close();
|
||||
button.focus();
|
||||
}
|
||||
}
|
||||
|
||||
button.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
if (pop.hidden) open(); else close();
|
||||
});
|
||||
|
||||
pop.addEventListener("click", function (e) {
|
||||
var day = e.target.closest(".date-input__day");
|
||||
if (day && day.dataset.iso) {
|
||||
e.preventDefault();
|
||||
var d = parseISO(day.dataset.iso);
|
||||
if (d) { commit(d); close(); }
|
||||
return;
|
||||
}
|
||||
if (e.target.closest("[data-prev]")) {
|
||||
e.preventDefault();
|
||||
if (--viewMonth < 0) { viewMonth = 11; viewYear--; }
|
||||
renderMonth();
|
||||
return;
|
||||
}
|
||||
if (e.target.closest("[data-next]")) {
|
||||
e.preventDefault();
|
||||
if (++viewMonth > 11) { viewMonth = 0; viewYear++; }
|
||||
renderMonth();
|
||||
return;
|
||||
}
|
||||
if (e.target.closest("[data-clear]")) {
|
||||
e.preventDefault();
|
||||
selected = null;
|
||||
input.value = "";
|
||||
renderLabel();
|
||||
renderMonth();
|
||||
input.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
close();
|
||||
return;
|
||||
}
|
||||
if (e.target.closest("[data-today]")) {
|
||||
e.preventDefault();
|
||||
var t = todayMidnight();
|
||||
commit(t);
|
||||
close();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("mousedown", onDocClick, true);
|
||||
document.addEventListener("keydown", onDocKey, true);
|
||||
|
||||
input.parentNode.insertBefore(wrap, input);
|
||||
wrap.appendChild(input);
|
||||
input.classList.add("date-input__native");
|
||||
wrap.appendChild(button);
|
||||
wrap.appendChild(pop);
|
||||
renderLabel();
|
||||
}
|
||||
|
||||
function enhanceAll(root) {
|
||||
(root || document).querySelectorAll(
|
||||
'input.input[type="date"], input.input[type="datetime-local"]'
|
||||
).forEach(buildPicker);
|
||||
}
|
||||
|
||||
function init() {
|
||||
enhanceAll();
|
||||
// Re-scan on Turbolinks-style page swaps, should the admin adopt them.
|
||||
if (typeof MutationObserver !== "undefined") {
|
||||
var obs = new MutationObserver(function () {
|
||||
enhanceAll(document);
|
||||
});
|
||||
obs.observe(document.body, { childList: true, subtree: true });
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user