2000s
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
(function () {
|
||||
var currentScript = document.currentScript;
|
||||
var source = currentScript && currentScript.getAttribute("data-notice-src");
|
||||
|
||||
if (!source && currentScript && currentScript.src) {
|
||||
source = currentScript.src.replace(/js\/notice-banner\.js(?:\?.*)?$/, "notices.json");
|
||||
}
|
||||
|
||||
if (!source) {
|
||||
source = "notices.json";
|
||||
}
|
||||
|
||||
var cacheKey = Math.floor(Date.now() / (5 * 60 * 1000));
|
||||
var joiner = source.indexOf("?") === -1 ? "?" : "&";
|
||||
|
||||
fetch(source + joiner + "v=" + cacheKey, { cache: "no-store" })
|
||||
.then(function (response) {
|
||||
if (!response.ok) {
|
||||
throw new Error("Notice source unavailable");
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(function (payload) {
|
||||
var notice = selectNotice(payload);
|
||||
if (notice) {
|
||||
renderNotice(notice);
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
// The page should stay quiet when the optional notice source is missing.
|
||||
});
|
||||
|
||||
function selectNotice(payload) {
|
||||
var notices = Array.isArray(payload) ? payload : payload && payload.notices;
|
||||
|
||||
if (!Array.isArray(notices)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var now = Date.now();
|
||||
var path = normalizePath(window.location.pathname);
|
||||
|
||||
return notices.find(function (notice) {
|
||||
if (!notice || notice.enabled === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (notice.startsAt && Date.parse(notice.startsAt) > now) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (notice.endsAt && Date.parse(notice.endsAt) < now) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (notice.pages && notice.pages.length) {
|
||||
return notice.pages.some(function (page) {
|
||||
return pathMatches(path, normalizePath(page));
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function renderNotice(notice) {
|
||||
var dismissedId = window.localStorage.getItem("dismissedNoticeId");
|
||||
var noticeId = String(notice.id || "");
|
||||
|
||||
if (notice.dismissible !== false && noticeId && dismissedId === noticeId) {
|
||||
return;
|
||||
}
|
||||
|
||||
var body = document.body;
|
||||
var originalPadding = window.getComputedStyle(body).paddingTop || "0px";
|
||||
body.style.setProperty("--notice-body-pad-top", originalPadding);
|
||||
|
||||
var banner = document.createElement("div");
|
||||
banner.className = "notice-banner";
|
||||
banner.setAttribute("role", "status");
|
||||
banner.setAttribute("aria-live", "polite");
|
||||
banner.dataset.level = notice.level || "info";
|
||||
|
||||
var inner = document.createElement("div");
|
||||
inner.className = "notice-banner__inner";
|
||||
|
||||
var badge = document.createElement("span");
|
||||
badge.className = "notice-banner__badge";
|
||||
badge.textContent = notice.badge || levelLabel(notice.level);
|
||||
|
||||
var content = document.createElement("div");
|
||||
content.className = "notice-banner__content";
|
||||
|
||||
if (notice.title) {
|
||||
var title = document.createElement("span");
|
||||
title.className = "notice-banner__title";
|
||||
title.textContent = notice.title;
|
||||
content.appendChild(title);
|
||||
}
|
||||
|
||||
var message = document.createElement("span");
|
||||
message.className = "notice-banner__message";
|
||||
message.textContent = notice.message || "";
|
||||
content.appendChild(message);
|
||||
|
||||
inner.appendChild(badge);
|
||||
inner.appendChild(content);
|
||||
|
||||
if (notice.url) {
|
||||
var link = document.createElement("a");
|
||||
link.className = "notice-banner__link";
|
||||
link.href = resolveUrl(notice.url, source);
|
||||
link.textContent = notice.linkText || "查看详情";
|
||||
inner.appendChild(link);
|
||||
}
|
||||
|
||||
var close = document.createElement("button");
|
||||
close.className = "notice-banner__close";
|
||||
close.type = "button";
|
||||
close.setAttribute("aria-label", "关闭通知");
|
||||
close.textContent = "×";
|
||||
close.addEventListener("click", function () {
|
||||
if (notice.dismissible !== false && noticeId) {
|
||||
window.localStorage.setItem("dismissedNoticeId", noticeId);
|
||||
}
|
||||
banner.remove();
|
||||
body.classList.remove("has-notice-banner");
|
||||
body.style.removeProperty("--notice-banner-height");
|
||||
});
|
||||
|
||||
inner.appendChild(close);
|
||||
banner.appendChild(inner);
|
||||
body.insertBefore(banner, body.firstChild);
|
||||
|
||||
requestAnimationFrame(function () {
|
||||
banner.classList.add("is-visible");
|
||||
body.style.setProperty("--notice-banner-height", banner.offsetHeight + "px");
|
||||
body.classList.add("has-notice-banner");
|
||||
});
|
||||
}
|
||||
|
||||
function levelLabel(level) {
|
||||
var labels = {
|
||||
warning: "提醒",
|
||||
error: "紧急",
|
||||
success: "完成"
|
||||
};
|
||||
|
||||
return labels[level] || "通知";
|
||||
}
|
||||
|
||||
function normalizePath(path) {
|
||||
return String(path || "").replace(/\\/g, "/").replace(/^.*?:\/\/[^/]+/, "");
|
||||
}
|
||||
|
||||
function resolveUrl(url, base) {
|
||||
try {
|
||||
return new URL(url, new URL(base, window.location.href)).href;
|
||||
} catch (error) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
function pathMatches(path, pattern) {
|
||||
if (!pattern || pattern === "*") {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pattern.charAt(pattern.length - 1) === "*") {
|
||||
return path.indexOf(pattern.slice(0, -1)) === 0;
|
||||
}
|
||||
|
||||
return path === pattern || path.endsWith(pattern);
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user