Skip to content

Commit 2b1e2d5

Browse files
committed
Maintanance: show banner for invalid licenses
1 parent 162f3da commit 2b1e2d5

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

Source/Blazorise/wwwroot/utilities.js

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,129 @@ export function verifyRsa(publicKey, content, signature) {
333333

334334
export function log(message, args) {
335335
console.log(message, args);
336+
337+
const HOST_ID = "blazorise-license-banner-host";
338+
const GLOBAL = "__blazoriseBannerState__";
339+
340+
// Global state (lives until full page refresh)
341+
const st = (window[GLOBAL] ||= {
342+
dismissed: false,
343+
bodyObserver: null,
344+
attrObserver: null
345+
});
346+
347+
// If user already dismissed (in this page lifetime), don't show again
348+
if (st.dismissed) {
349+
return;
350+
}
351+
352+
// Prepare message for HTML (strip %c and escape)
353+
let cleanMessage = typeof message === "string" ? message.replace(/%c/g, "") : String(message);
354+
cleanMessage = cleanMessage
355+
.replace(/&/g, "&")
356+
.replace(/</g, "&lt;")
357+
.replace(/>/g, "&gt;")
358+
.replace(/"/g, "&quot;")
359+
.replace(/'/g, "&#39;");
360+
361+
// If banner exists, just update the message
362+
let host = document.getElementById(HOST_ID);
363+
if (host && host.shadowRoot) {
364+
const msgEl = host.shadowRoot.querySelector(".msg");
365+
if (msgEl) msgEl.innerHTML = cleanMessage;
366+
return;
367+
}
368+
369+
// Create host + Shadow DOM (isolates styles)
370+
host = document.createElement("div");
371+
host.id = HOST_ID;
372+
const shadow = host.attachShadow({ mode: "open" });
373+
374+
// Styles: Blazorise purple, subtle sizing
375+
const style = document.createElement("style");
376+
style.textContent = `
377+
:host { all: initial !important; }
378+
.wrapper {
379+
position: fixed !important;
380+
left: 0 !important;
381+
right: 0 !important;
382+
bottom: 0 !important;
383+
z-index: 2147483647 !important;
384+
padding: 10px 14px !important;
385+
background: #6C63FF !important; /* Blazorise purple */
386+
color: #FFFFFF !important;
387+
font: 500 14px/1.4 -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif !important;
388+
box-shadow: 0 -4px 12px rgba(0,0,0,0.2) !important;
389+
display: flex !important;
390+
align-items: center !important;
391+
gap: .75rem !important;
392+
border-top-left-radius: 6px !important;
393+
border-top-right-radius: 6px !important;
394+
}
395+
.msg { flex: 1 1 auto !important; }
396+
.btn {
397+
appearance: none !important;
398+
border: 1px solid rgba(255,255,255,0.7) !important;
399+
background: transparent !important;
400+
color: #FFFFFF !important;
401+
padding: .3rem .6rem !important;
402+
border-radius: .3rem !important;
403+
font-size: 12px !important;
404+
cursor: pointer !important;
405+
transition: background .2s ease-in-out, color .2s ease-in-out !important;
406+
}
407+
.btn:hover { background: rgba(255,255,255,0.2) !important; }
408+
`.trim();
409+
410+
shadow.appendChild(style);
411+
412+
// Markup
413+
const wrapperElement = document.createElement("div");
414+
wrapperElement.className = "wrapper";
415+
416+
const messageElement = document.createElement("span");
417+
messageElement.className = "msg";
418+
messageElement.innerHTML = cleanMessage;
419+
420+
const button = document.createElement("button");
421+
button.className = "btn";
422+
button.type = "button";
423+
button.textContent = "Dismiss";
424+
button.addEventListener("click", () => {
425+
// Mark dismissed for current page lifetime and stop observers
426+
st.dismissed = true;
427+
if (st.bodyObserver) try { st.bodyObserver.disconnect(); } catch { }
428+
if (st.attrObserver) try { st.attrObserver.disconnect(); } catch { }
429+
host.remove();
430+
});
431+
432+
wrapperElement.appendChild(messageElement);
433+
wrapperElement.appendChild(button);
434+
shadow.appendChild(wrapperElement);
435+
document.body.appendChild(host);
436+
437+
// Re-add if removed from body
438+
if (!st.bodyObserver) {
439+
st.bodyObserver = new MutationObserver(() => {
440+
if (st.dismissed) return;
441+
const exists = document.getElementById(HOST_ID);
442+
if (!exists) {
443+
try { document.body.appendChild(host); } catch { }
444+
}
445+
});
446+
st.bodyObserver.observe(document.body, { childList: true });
447+
}
448+
449+
// Undo display:none / hidden
450+
if (!st.attrObserver) {
451+
st.attrObserver = new MutationObserver(() => {
452+
if (st.dismissed) return;
453+
host.style.display = "block";
454+
host.style.visibility = "visible";
455+
host.style.opacity = "1";
456+
});
457+
st.attrObserver.observe(host, { attributes: true, attributeFilter: ["style", "class", "hidden"] });
458+
}
336459
}
337460

338461
export function createEvent(name) {

0 commit comments

Comments
 (0)