function Toastra() {
let options = {};
let globals = {
type: "default",
mode: "default-mode",
position: "top-right",
duration: 3000,
selector: "body",
icon: null,
progressbar: false,
close: false,
title: "",
badge: null,
text: "Hi Guys, i'am Toastra!",
onComplete: null,
onCompleteParams: {},
offset: {
top: "",
left: "",
right: "",
bottom: "",
},
style: {
color: "",
background: "",
},
animation: "slide-right",
classname: "",
};
const icons = {
default:
'',
success:
'',
info: '',
warning:
'',
error: '',
update: '',
};
function config(default_option = {}) {
Object.assign(globals, default_option);
}
function notify(option) {
options = { ...globals, ...option };
let animationTime = 500;
let notification = document.createElement("div");
notification.className = `notification ${options.position} ${options.mode} ${options.classname}`;
notification.id = "notification";
Object.keys(options.offset).forEach((key) => {
notification.style[key] = options.offset[key];
});
let notificationContainer = document.createElement("div");
notificationContainer.className = `notification-container notification-toast-${options.type} ${options.animation} ${options.classname}`;
Object.keys(options.style).forEach((key) => {
notificationContainer.style[key] = options.style[key];
});
notificationContainer.classList.add("slide-in");
let notificationBlock = document.createElement("div");
notificationBlock.className = "notification-block";
notificationContainer.appendChild(notificationBlock);
if (options.icon !== null) {
let notificationIcon = document.createElement("div");
notificationIcon.className = "notification-icon";
notificationIcon.innerHTML = icons[options.type] ?? icons.default;
notificationBlock.appendChild(notificationIcon);
}
let notificationMessage = document.createElement("div");
notificationMessage.className = "notification-message";
notificationBlock.appendChild(notificationMessage);
if (options.title.length !== 0) {
let notificationTitle = document.createElement("div");
notificationTitle.className = "notification-title";
// notificationTitle.innerHTML = "" + options.title + "";
// notificationMessage.appendChild(notificationTitle);
// NEW: badge element (instead of data-attr + ::before)
if (options.badge) {
const badgeEl = document.createElement("span");
badgeEl.className = "notification-badge";
badgeEl.textContent = String(options.badge).toUpperCase();
notificationTitle.appendChild(badgeEl);
}
// Title text (keep your current behavior)
if (options.title && options.title.length) {
const titleText = document.createElement("span");
titleText.className = "notification-title";
titleText.innerHTML = "" + options.title + "";
notificationTitle.appendChild(titleText);
}
notificationMessage.appendChild(notificationTitle);
// NEW: optional subtitle (e.g. domain shown below)
if (options.subtitle && options.subtitle.length) {
const subtitleEl = document.createElement("div");
subtitleEl.className = "notification-subtitle";
subtitleEl.textContent = options.subtitle;
notificationMessage.appendChild(subtitleEl);
}
}
let notificationText = document.createElement("div");
notificationText.className = "notification-text";
notificationText.innerHTML = "" + options.text + "";
notificationMessage.appendChild(notificationText);
if (options.close) {
let notificationDismissButton = document.createElement("button");
notificationDismissButton.className = "notification-dismiss-btn";
notificationDismissButton.innerHTML =
'';
notificationBlock.appendChild(notificationDismissButton);
notificationDismissButton.addEventListener("click", () => {
notificationContainer.classList.remove("slide-in");
notificationContainer.classList.add("slide-out");
notificationContainer.addEventListener("animationend", () => {
notificationContainer.remove();
});
});
}
if (options.progressbar && options.duration !== -1) {
notificationContainer.addEventListener("animationend", () => {
let currentProgress = 0;
let notificationProgressbar = document.createElement("div");
notificationProgressbar.className = "notification-progressbar";
notificationBlock.appendChild(notificationProgressbar);
let count = setInterval(() => {
if (currentProgress < 100) {
currentProgress += 1;
notificationProgressbar.dataset.duration = (options.duration ?? globals.duration);
notificationProgressbar.style.width = "100%";
// currentProgress + "%";
} else {
clearInterval(count);
}
}, (options.duration ?? globals.duration) / 100);
});
}
if (document.getElementById(notification.id) === null) {
document.querySelector(options.selector).appendChild(notification);
}
document
.getElementById(notification.id)
.insertBefore(
notificationContainer,
document.getElementById(notification.id).children[0],
);
function removeToast() {
notificationContainer.classList.remove("slide-in");
notificationContainer.classList.add("slide-out");
notificationContainer.addEventListener("animationend", () => {
notificationContainer.remove();
});
}
const totalDelay = (options.duration ?? globals.duration) + animationTime;
setTimeout(() => {
const funcName = options.onComplete;
if (typeof funcName === "string") {
if (typeof window[funcName] === "function") {
window[funcName](options.onCompleteParams);
}
else if (typeof window.Callbacks?.[funcName] === "function") {
window.Callbacks[funcName](options.onCompleteParams);
}
else {
console.warn(`[Toastra] Callback '${funcName}' nicht gefunden.`);
}
} else if (typeof options.onComplete === "function") {
options.onComplete(options.onCompleteParams);
}
if (options.duration !== -1) {
removeToast();
}
}, totalDelay + 500);
// if (
// typeof options.onComplete === "string" &&
// typeof window.Callbacks[options.onComplete] === "function"
// ) {
// window.Callbacks[options.onComplete](options.onCompleteParams);
// } else {
// for (const [key, value] of Object.entries(options)) {
// setTimeout(() => {
// if (key === "duration" && value !== -1)
// {
// removeToast();
// }
// }, (options.duration ?? globals.duration) + animationTime);
// }
// }
}
function createQueue() {
const queue = [];
let isRunning = false;
function runQueue() {
if (queue.length === 0) {
isRunning = false;
return;
}
isRunning = true;
const next = queue.shift();
// Wrappe onComplete, damit nach dem Toast automatisch der nächste kommt
const userOnComplete = next.onComplete;
next.onComplete = (params) => {
// Benutzerdefinierte Funktion aufrufen (optional)
if (typeof userOnComplete === 'function') {
userOnComplete(params);
} else if (typeof userOnComplete === 'string') {
if (typeof window[userOnComplete] === 'function') {
window[userOnComplete](params);
} else if (typeof window.Callbacks?.[userOnComplete] === 'function') {
window.Callbacks[userOnComplete](params);
}
}
runQueue(); // Weiter mit dem nächsten Toast
};
// Toast anzeigen
toastra.notify(next);
}
return {
add(toast) {
queue.push(toast);
if (!isRunning) runQueue();
}
};
}
let globalQueue = null;
function getGlobalQueue() {
if (!globalQueue) {
globalQueue = createQueue();
}
return globalQueue;
}
return {
notify,
queue: getGlobalQueue,
config,
};
}
window.toastra = Toastra();