Initial commit
This commit is contained in:
commit
05c65aad4d
155 changed files with 93617 additions and 0 deletions
614
viewer/ui/loading-status.js
Normal file
614
viewer/ui/loading-status.js
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
import { core } from "../core.js";
|
||||
import { t } from "../i18n-utils.js";
|
||||
|
||||
export function attachLoadingStatus(viewer) {
|
||||
Object.assign(viewer, {
|
||||
toggleLoadingLogs() {
|
||||
this.showLoadingLogs = !this.showLoadingLogs;
|
||||
if (core.loadingLog.get()) {
|
||||
core.loadingLog.get().classList.toggle("editorToolbar-visible", this.showLoadingLogs);
|
||||
}
|
||||
this.updateEditorToolbarLabels();
|
||||
this.updateEditorToolbarState();
|
||||
},
|
||||
|
||||
getLoadingLogMessages() {
|
||||
return this.loadingLogMessageKeys.map((key) => t(key));
|
||||
},
|
||||
|
||||
getProcessingLoadingSteps() {
|
||||
return this.processingLoadingStepKeys.map((key) => t(key));
|
||||
},
|
||||
|
||||
createModelLoadingProgress(shell) {
|
||||
shell.className = "model-loader";
|
||||
shell.hidden = true;
|
||||
shell.setAttribute("role", "status");
|
||||
shell.setAttribute("aria-live", "polite");
|
||||
|
||||
const ring = document.createElement("div");
|
||||
ring.className = "model-loader__ring";
|
||||
ring.setAttribute("aria-hidden", "true");
|
||||
|
||||
const percent = document.createElement("div");
|
||||
percent.className = "model-loader__percent";
|
||||
percent.textContent = "0%";
|
||||
ring.appendChild(percent);
|
||||
|
||||
const content = document.createElement("div");
|
||||
content.className = "model-loader__content";
|
||||
|
||||
const phase = document.createElement("div");
|
||||
phase.className = "model-loader__phase";
|
||||
phase.textContent = this.getLoadingLogMessages()[0] ?? t("loadingLog.loadingAssets", "Loading assets");
|
||||
|
||||
const phaseViewport = document.createElement("div");
|
||||
phaseViewport.className = "model-loader__phase-viewport";
|
||||
|
||||
const phaseList = document.createElement("div");
|
||||
phaseList.className = "model-loader__phase-list";
|
||||
|
||||
phaseViewport.appendChild(phaseList);
|
||||
|
||||
const messages = this.getLoadingLogMessages();
|
||||
const stageKeyToIndex = new Map(
|
||||
this.loadingLogMessageKeys.map((key, index) => [key, index])
|
||||
);
|
||||
const loadingModelKeyIndex = Math.max(
|
||||
0,
|
||||
stageKeyToIndex.get("loadingLog.loadingModel") ?? 0
|
||||
);
|
||||
let hideTimer = null;
|
||||
|
||||
messages.forEach((msg) => {
|
||||
const item = document.createElement("div");
|
||||
item.className = "model-loader__phase-item";
|
||||
item.textContent = msg;
|
||||
phaseList.appendChild(item);
|
||||
});
|
||||
|
||||
const clearHideTimer = () => {
|
||||
if (hideTimer) {
|
||||
window.clearTimeout(hideTimer);
|
||||
hideTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
const updatePhase = (index) => {
|
||||
const itemHeight = phaseList.firstElementChild?.offsetHeight || 24;
|
||||
phaseList.style.transform = `translateY(-${index * itemHeight}px)`;
|
||||
phase.textContent = messages[index] || messages[loadingModelKeyIndex] || phase.textContent;
|
||||
Array.from(phaseList.children).forEach((item, itemIndex) => {
|
||||
item.toggleAttribute("data-active", itemIndex === index);
|
||||
item.toggleAttribute("data-near", itemIndex === index - 1 || itemIndex === index + 1);
|
||||
});
|
||||
};
|
||||
|
||||
const track = document.createElement("div");
|
||||
track.className = "model-loader__track";
|
||||
track.setAttribute("role", "progressbar");
|
||||
track.setAttribute("aria-valuemin", "0");
|
||||
track.setAttribute("aria-valuemax", "100");
|
||||
track.setAttribute("aria-valuenow", "0");
|
||||
content.append(phaseViewport, track);
|
||||
|
||||
const bar = document.createElement("div");
|
||||
bar.className = "model-loader__bar";
|
||||
track.appendChild(bar);
|
||||
|
||||
shell.replaceChildren(ring, content);
|
||||
|
||||
const set = (value = 0, maxValue = 100) => {
|
||||
const safeMax = Number.isFinite(maxValue) && maxValue > 0 ? maxValue : 100;
|
||||
const normalized = Number.isFinite(value) ? Math.min(Math.max(value / safeMax, 0), 1) : 0;
|
||||
const progress = Math.round(normalized * 100);
|
||||
|
||||
shell.style.setProperty("--model-loader-progress", String(progress));
|
||||
percent.textContent = `${progress}%`;
|
||||
bar.style.width = `${progress}%`;
|
||||
track.setAttribute("aria-valuenow", String(progress));
|
||||
updatePhase(loadingModelKeyIndex);
|
||||
};
|
||||
|
||||
set(0, 100);
|
||||
|
||||
return {
|
||||
getElement: () => shell,
|
||||
show: () => {
|
||||
clearHideTimer();
|
||||
shell.hidden = false;
|
||||
delete shell.dataset.complete;
|
||||
updatePhase(loadingModelKeyIndex);
|
||||
},
|
||||
hide: () => {
|
||||
clearHideTimer();
|
||||
shell.hidden = true;
|
||||
delete shell.dataset.complete;
|
||||
},
|
||||
setStage: (stageKey, progressValue = null) => {
|
||||
const index = stageKeyToIndex.get(stageKey);
|
||||
if (typeof index === "number") {
|
||||
updatePhase(index);
|
||||
}
|
||||
if (Number.isFinite(progressValue)) {
|
||||
const normalizedProgress = Math.max(0, Math.min(Math.round(progressValue), 100));
|
||||
shell.style.setProperty("--model-loader-progress", String(normalizedProgress));
|
||||
percent.textContent = `${normalizedProgress}%`;
|
||||
bar.style.width = `${normalizedProgress}%`;
|
||||
track.setAttribute("aria-valuenow", String(normalizedProgress));
|
||||
}
|
||||
},
|
||||
complete: (delayMs = 2400) => {
|
||||
clearHideTimer();
|
||||
updatePhase(stageKeyToIndex.get("loadingLog.modelLoaded") ?? messages.length - 1);
|
||||
shell.style.setProperty("--model-loader-progress", "100");
|
||||
percent.textContent = "100%";
|
||||
bar.style.width = "100%";
|
||||
track.setAttribute("aria-valuenow", "100");
|
||||
shell.dataset.complete = "true";
|
||||
hideTimer = window.setTimeout(() => {
|
||||
hideTimer = null;
|
||||
delete shell.dataset.complete;
|
||||
shell.hidden = true;
|
||||
}, delayMs);
|
||||
},
|
||||
set,
|
||||
reset: (maxValue = 100) => {
|
||||
clearHideTimer();
|
||||
delete shell.dataset.complete;
|
||||
set(0, maxValue);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
createLoadingLog() {
|
||||
const shell = document.createElement("div");
|
||||
shell.id = "loading-log";
|
||||
shell.setAttribute("aria-live", "polite");
|
||||
shell.hidden = true;
|
||||
|
||||
const collapsedToggle = document.createElement("button");
|
||||
collapsedToggle.type = "button";
|
||||
collapsedToggle.className = "loading-log__collapsed-toggle";
|
||||
collapsedToggle.setAttribute("aria-label", t("loadingLog.title", "Loading process log"));
|
||||
collapsedToggle.setAttribute("aria-expanded", "false");
|
||||
shell.appendChild(collapsedToggle);
|
||||
|
||||
const header = document.createElement("button");
|
||||
header.type = "button";
|
||||
header.className = "loading-log__header";
|
||||
header.setAttribute("aria-expanded", "false");
|
||||
|
||||
const headerTitle = document.createElement("span");
|
||||
headerTitle.className = "loading-log__title";
|
||||
headerTitle.textContent = t("loadingLog.title", "Loading process log");
|
||||
|
||||
const headerSummary = document.createElement("span");
|
||||
headerSummary.className = "loading-log__summary";
|
||||
|
||||
header.append(headerTitle, headerSummary);
|
||||
shell.appendChild(header);
|
||||
|
||||
const body = document.createElement("div");
|
||||
body.className = "loading-log__body";
|
||||
|
||||
const list = document.createElement("div");
|
||||
list.className = "loading-log__messages";
|
||||
|
||||
const progress = document.createElement("div");
|
||||
progress.className = "loading-log__progress";
|
||||
progress.setAttribute("role", "progressbar");
|
||||
progress.setAttribute("aria-valuemin", "0");
|
||||
progress.setAttribute("aria-valuemax", "100");
|
||||
progress.setAttribute("aria-valuenow", "0");
|
||||
|
||||
const progressBar = document.createElement("div");
|
||||
progressBar.className = "loading-log__progress-bar";
|
||||
progress.appendChild(progressBar);
|
||||
|
||||
body.append(list, progress);
|
||||
shell.appendChild(body);
|
||||
core.container.appendChild(shell);
|
||||
|
||||
shell.classList.add("editorToolbar-hidden");
|
||||
|
||||
let timer = null;
|
||||
let messageIndex = 0;
|
||||
let visibleCount = 0;
|
||||
let currentProgress = 0;
|
||||
let startedAt = 0;
|
||||
let hideTimer = null;
|
||||
let progressUpdated = false;
|
||||
const minVisibleMs = 900;
|
||||
const loadingMessages = this.getLoadingLogMessages();
|
||||
const loadingStageKeyToIndex = new Map(
|
||||
this.loadingLogMessageKeys.map((key, index) => [key, index])
|
||||
);
|
||||
const loadingModelMessageIndex = Math.max(
|
||||
0,
|
||||
loadingStageKeyToIndex.get("loadingLog.loadingModel") ?? 0
|
||||
);
|
||||
let isExpanded = false;
|
||||
|
||||
const setExpanded = (expanded) => {
|
||||
isExpanded = expanded;
|
||||
shell.dataset.expanded = expanded ? "true" : "false";
|
||||
header.setAttribute("aria-expanded", expanded ? "true" : "false");
|
||||
collapsedToggle.setAttribute("aria-expanded", expanded ? "true" : "false");
|
||||
};
|
||||
|
||||
const updateSummary = () => {
|
||||
const activeMessage = loadingMessages[messageIndex] || loadingMessages[loadingModelMessageIndex] || "";
|
||||
headerSummary.textContent = `${currentProgress}% • ${activeMessage}`;
|
||||
};
|
||||
|
||||
header.addEventListener("click", () => {
|
||||
if (shell.hidden) return;
|
||||
setExpanded(!isExpanded);
|
||||
});
|
||||
|
||||
collapsedToggle.addEventListener("click", () => {
|
||||
if (shell.hidden) return;
|
||||
setExpanded(!isExpanded);
|
||||
});
|
||||
|
||||
const renderMessages = (allDone = false) => {
|
||||
const messages = loadingMessages
|
||||
.slice(Math.max(0, messageIndex - visibleCount + 1), messageIndex + 1);
|
||||
list.replaceChildren(...messages.map((message, index) => {
|
||||
const row = document.createElement("div");
|
||||
row.className = "loading-log__message";
|
||||
if (allDone) {
|
||||
row.classList.add("loading-log__message--done");
|
||||
} else if (index === messages.length - 1) {
|
||||
row.classList.add("loading-log__message--active");
|
||||
}
|
||||
row.textContent = message;
|
||||
return row;
|
||||
}));
|
||||
};
|
||||
|
||||
const setProgress = (value) => {
|
||||
const normalizedValue = Number.isFinite(value) ? Math.min(Math.max(value, 0), 100) : 0;
|
||||
currentProgress = Math.max(currentProgress, Math.round(normalizedValue));
|
||||
progressBar.style.width = `${currentProgress}%`;
|
||||
progress.setAttribute("aria-valuenow", String(currentProgress));
|
||||
updateSummary();
|
||||
};
|
||||
|
||||
const tick = () => {
|
||||
visibleCount = Math.min(4, visibleCount + 1);
|
||||
if (!progressUpdated) {
|
||||
messageIndex = loadingModelMessageIndex;
|
||||
setProgress(Math.min(currentProgress + 8, 12));
|
||||
}
|
||||
renderMessages();
|
||||
};
|
||||
|
||||
const stop = () => {
|
||||
if (timer) {
|
||||
window.clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
};
|
||||
|
||||
const clearHideTimer = () => {
|
||||
if (hideTimer) {
|
||||
window.clearTimeout(hideTimer);
|
||||
hideTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
const collapseLog = () => {
|
||||
shell.classList.remove("loading-log--done");
|
||||
shell.classList.remove("loading-log--error");
|
||||
setExpanded(false);
|
||||
hideTimer = null;
|
||||
};
|
||||
|
||||
return {
|
||||
start: () => {
|
||||
stop();
|
||||
clearHideTimer();
|
||||
progressUpdated = false;
|
||||
startedAt = performance.now();
|
||||
shell.hidden = false;
|
||||
setExpanded(false);
|
||||
shell.classList.remove("loading-log--done", "loading-log--error");
|
||||
messageIndex = loadingModelMessageIndex;
|
||||
visibleCount = 1;
|
||||
currentProgress = 0;
|
||||
renderMessages();
|
||||
setProgress(6);
|
||||
timer = window.setInterval(tick, 520);
|
||||
},
|
||||
update: (value) => {
|
||||
if (shell.hidden) return;
|
||||
progressUpdated = true;
|
||||
const normalized = Number.isFinite(value) ? value : 0;
|
||||
messageIndex = loadingModelMessageIndex;
|
||||
visibleCount = Math.min(4, Math.max(visibleCount, 2));
|
||||
renderMessages();
|
||||
setProgress(Math.min(normalized, 99));
|
||||
},
|
||||
setStage: (stageKey, progressValue = null) => {
|
||||
if (shell.hidden) return;
|
||||
const stageIndex = loadingStageKeyToIndex.get(stageKey);
|
||||
if (typeof stageIndex === "number") {
|
||||
messageIndex = stageIndex;
|
||||
visibleCount = Math.min(4, Math.max(visibleCount, 2));
|
||||
renderMessages();
|
||||
updateSummary();
|
||||
}
|
||||
if (Number.isFinite(progressValue)) {
|
||||
setProgress(progressValue);
|
||||
}
|
||||
},
|
||||
finish: () => {
|
||||
if (shell.hidden) return;
|
||||
stop();
|
||||
const messageCount = loadingMessages.length;
|
||||
messageIndex = messageCount - 1;
|
||||
visibleCount = messageCount;
|
||||
renderMessages(true);
|
||||
setProgress(100);
|
||||
updateSummary();
|
||||
shell.classList.add("loading-log--done");
|
||||
const visibleFor = performance.now() - startedAt;
|
||||
const hideDelay = Math.max(1200, minVisibleMs - visibleFor + 800);
|
||||
clearHideTimer();
|
||||
hideTimer = window.setTimeout(() => {
|
||||
collapseLog();
|
||||
}, hideDelay);
|
||||
},
|
||||
fail: () => {
|
||||
if (shell.hidden) return;
|
||||
stop();
|
||||
clearHideTimer();
|
||||
setExpanded(true);
|
||||
shell.classList.add("loading-log--error");
|
||||
hideTimer = window.setTimeout(() => {
|
||||
shell.classList.remove("loading-log--error");
|
||||
setExpanded(false);
|
||||
hideTimer = null;
|
||||
}, 2000);
|
||||
},
|
||||
get: () => shell,
|
||||
};
|
||||
},
|
||||
|
||||
showStatusNotice(message, duration = 2600, options = {}) {
|
||||
this.enqueueStatusNotice({ message, duration, tone: "info", ...options });
|
||||
},
|
||||
|
||||
localizeStatusNotice(notice) {
|
||||
if (!notice) return notice;
|
||||
const i18nKey = String(notice.i18nKey || "");
|
||||
const detailI18nKey = String(notice.detailI18nKey || "");
|
||||
return {
|
||||
...notice,
|
||||
message: i18nKey ? t(i18nKey, notice.i18nVars || {}, notice.message) : notice.message,
|
||||
detail: detailI18nKey ? t(detailI18nKey, notice.detailI18nVars || {}, notice.detail) : notice.detail,
|
||||
};
|
||||
},
|
||||
|
||||
renderStatusNoticeContent(notice) {
|
||||
if (!this.statusNotice || !notice) return;
|
||||
const message = String(notice.message ?? "");
|
||||
const detail = String(notice.detail ?? "");
|
||||
|
||||
this.statusNotice.textContent = "";
|
||||
|
||||
const messageNode = document.createElement("span");
|
||||
messageNode.className = "viewer-notice-message";
|
||||
messageNode.textContent = message;
|
||||
this.statusNotice.appendChild(messageNode);
|
||||
|
||||
if (detail) {
|
||||
const detailLines = detail.split(/\r?\n/);
|
||||
for (const line of detailLines) {
|
||||
const detailNode = document.createElement("span");
|
||||
detailNode.className = "viewer-notice-detail";
|
||||
detailNode.innerHTML = line;
|
||||
this.statusNotice.appendChild(detailNode);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getStatusNoticeText(notice) {
|
||||
return [notice?.message, notice?.detail].filter(Boolean).join(" ");
|
||||
},
|
||||
|
||||
refreshStatusNoticeLanguage() {
|
||||
if (Array.isArray(this.statusNoticeQueue)) {
|
||||
this.statusNoticeQueue = this.statusNoticeQueue.map((notice) => this.localizeStatusNotice(notice));
|
||||
}
|
||||
|
||||
if (!this.statusNoticeCurrent) return;
|
||||
this.statusNoticeCurrent = this.localizeStatusNotice(this.statusNoticeCurrent);
|
||||
this.renderStatusNoticeContent(this.statusNoticeCurrent);
|
||||
},
|
||||
|
||||
showStatusNoticeNow(notice) {
|
||||
if (!this.statusNotice || !notice) return;
|
||||
notice = this.localizeStatusNotice(notice);
|
||||
|
||||
if (this.statusNoticeHideTimer) {
|
||||
clearTimeout(this.statusNoticeHideTimer);
|
||||
this.statusNoticeHideTimer = null;
|
||||
}
|
||||
|
||||
this.statusNoticeActive = true;
|
||||
this.statusNoticeCurrent = notice;
|
||||
this.statusNotice.hidden = false;
|
||||
this.renderStatusNoticeContent(notice);
|
||||
this.statusNotice.dataset.tone = notice.tone || "info";
|
||||
if (notice.variant) {
|
||||
this.statusNotice.dataset.variant = notice.variant;
|
||||
} else {
|
||||
delete this.statusNotice.dataset.variant;
|
||||
}
|
||||
this.noticeContainer?.classList.toggle("viewer-notice-container--sandbox", notice.variant === "sandbox");
|
||||
this.statusNotice.classList.remove("is-hiding");
|
||||
this.statusNotice.classList.add("is-visible");
|
||||
|
||||
if (this.statusNoticeTimer) {
|
||||
clearTimeout(this.statusNoticeTimer);
|
||||
this.statusNoticeTimer = null;
|
||||
}
|
||||
|
||||
if (notice.persistent) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.statusNoticeTimer = setTimeout(() => {
|
||||
if (this.statusNotice) {
|
||||
this.statusNotice.classList.remove("is-visible");
|
||||
this.statusNotice.classList.add("is-hiding");
|
||||
}
|
||||
|
||||
this.statusNoticeHideTimer = setTimeout(() => {
|
||||
if (this.statusNotice) {
|
||||
this.statusNotice.hidden = true;
|
||||
this.statusNotice.classList.remove("is-hiding");
|
||||
delete this.statusNotice.dataset.variant;
|
||||
}
|
||||
this.noticeContainer?.classList.remove("viewer-notice-container--sandbox");
|
||||
this.statusNoticeActive = false;
|
||||
this.statusNoticeCurrent = null;
|
||||
this.statusNoticeTimer = null;
|
||||
this.statusNoticeHideTimer = null;
|
||||
this.processStatusNoticeQueue();
|
||||
}, 220);
|
||||
}, notice.duration);
|
||||
},
|
||||
|
||||
dismissStatusNotice(key = "") {
|
||||
const normalizedKey = String(key || "");
|
||||
this.statusNoticeQueue = this.statusNoticeQueue.filter(
|
||||
(entry) => normalizedKey && (entry?.key || "") !== normalizedKey
|
||||
);
|
||||
|
||||
if (
|
||||
normalizedKey &&
|
||||
(!this.statusNoticeCurrent || (this.statusNoticeCurrent.key || "") !== normalizedKey)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.statusNoticeTimer) {
|
||||
clearTimeout(this.statusNoticeTimer);
|
||||
this.statusNoticeTimer = null;
|
||||
}
|
||||
if (this.statusNoticeHideTimer) {
|
||||
clearTimeout(this.statusNoticeHideTimer);
|
||||
this.statusNoticeHideTimer = null;
|
||||
}
|
||||
|
||||
if (this.statusNotice) {
|
||||
this.statusNotice.hidden = true;
|
||||
this.statusNotice.classList.remove("is-visible", "is-hiding");
|
||||
delete this.statusNotice.dataset.variant;
|
||||
}
|
||||
this.noticeContainer?.classList.remove("viewer-notice-container--sandbox");
|
||||
|
||||
this.statusNoticeActive = false;
|
||||
this.statusNoticeCurrent = null;
|
||||
this.processStatusNoticeQueue();
|
||||
},
|
||||
|
||||
enqueueStatusNotice({
|
||||
message,
|
||||
duration = 2600,
|
||||
tone = "info",
|
||||
key = "",
|
||||
replace = false,
|
||||
persistent = false,
|
||||
variant = "",
|
||||
i18nKey = "",
|
||||
i18nVars = {},
|
||||
detail = "",
|
||||
detailI18nKey = "",
|
||||
detailI18nVars = {},
|
||||
} = {}) {
|
||||
const text = String(message ?? "");
|
||||
if (!text) return;
|
||||
|
||||
const nextNotice = {
|
||||
message: text,
|
||||
tone,
|
||||
duration: Number.isFinite(duration) ? duration : 2600,
|
||||
key: String(key || ""),
|
||||
persistent,
|
||||
variant: String(variant || ""),
|
||||
i18nKey: String(i18nKey || ""),
|
||||
i18nVars: i18nVars && typeof i18nVars === "object" ? { ...i18nVars } : {},
|
||||
detail: String(detail || ""),
|
||||
detailI18nKey: String(detailI18nKey || ""),
|
||||
detailI18nVars: detailI18nVars && typeof detailI18nVars === "object" ? { ...detailI18nVars } : {},
|
||||
};
|
||||
|
||||
if (
|
||||
this.statusNoticeActive &&
|
||||
this.getStatusNoticeText(this.statusNoticeCurrent) === this.getStatusNoticeText(nextNotice) &&
|
||||
(this.statusNoticeCurrent?.tone || "info") === nextNotice.tone &&
|
||||
(this.statusNoticeCurrent?.key || "") === nextNotice.key
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nextNotice.key) {
|
||||
this.statusNoticeQueue = this.statusNoticeQueue.filter(
|
||||
(entry) => (entry?.key || "") !== nextNotice.key
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
replace &&
|
||||
this.statusNoticeActive &&
|
||||
(!nextNotice.key || (this.statusNoticeCurrent?.key || "") === nextNotice.key)
|
||||
) {
|
||||
this.showStatusNoticeNow(nextNotice);
|
||||
return;
|
||||
}
|
||||
|
||||
const isDuplicateQueued = this.statusNoticeQueue.some(
|
||||
(entry) =>
|
||||
this.getStatusNoticeText(entry) === this.getStatusNoticeText(nextNotice) &&
|
||||
entry?.tone === nextNotice.tone &&
|
||||
(entry?.key || "") === nextNotice.key
|
||||
);
|
||||
if (isDuplicateQueued) return;
|
||||
|
||||
const priorityMap = {
|
||||
error: 0,
|
||||
warning: 1,
|
||||
info: 2,
|
||||
success: 3,
|
||||
};
|
||||
const nextPriority = priorityMap[nextNotice.tone] ?? 2;
|
||||
const insertAt = this.statusNoticeQueue.findIndex((entry) => {
|
||||
const entryPriority = priorityMap[entry?.tone] ?? 2;
|
||||
return nextPriority < entryPriority;
|
||||
});
|
||||
|
||||
if (insertAt === -1) {
|
||||
this.statusNoticeQueue.push(nextNotice);
|
||||
} else {
|
||||
this.statusNoticeQueue.splice(insertAt, 0, nextNotice);
|
||||
}
|
||||
|
||||
this.processStatusNoticeQueue();
|
||||
},
|
||||
|
||||
processStatusNoticeQueue() {
|
||||
if (this.statusNoticeActive) return;
|
||||
if (!this.statusNotice) return;
|
||||
if (!Array.isArray(this.statusNoticeQueue) || this.statusNoticeQueue.length === 0) return;
|
||||
|
||||
const nextNotice = this.statusNoticeQueue.shift();
|
||||
if (!nextNotice) return;
|
||||
this.showStatusNoticeNow(nextNotice);
|
||||
},
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue