FBToast tests: constructor and onEnter hooks
parent
74ee415069
commit
a7363ae0f7
|
@ -0,0 +1,40 @@
|
|||
import { FBToast } from "../fb_toast";
|
||||
|
||||
describe("FBToast", () => {
|
||||
const parent = document.createElement("div");
|
||||
const newToast = () => new FBToast(parent, "title", "message", "red");
|
||||
|
||||
it("instantiates", () => {
|
||||
const instance = newToast();
|
||||
|
||||
expect(instance.leftLoaderEl.tagName).toEqual("DIV");
|
||||
expect(instance.loaderEl.tagName).toEqual("DIV");
|
||||
expect(instance.messageEl.tagName).toEqual("DIV");
|
||||
expect(instance.rightLoaderEl.tagName).toEqual("DIV");
|
||||
expect(instance.titleEl.tagName).toEqual("H4");
|
||||
expect(instance.toastEl.tagName).toEqual("DIV");
|
||||
expect(instance.spinnerLoaderEl.tagName).toEqual("DIV");
|
||||
expect(instance.isHovered).toEqual(false);
|
||||
expect(instance.intervalId).toEqual(0);
|
||||
expect(instance.message).toEqual("message");
|
||||
expect(instance.parent).toEqual(parent);
|
||||
expect(instance.timeout).toEqual(7);
|
||||
});
|
||||
|
||||
it("handles mouse enter events", () => {
|
||||
const i = newToast();
|
||||
i.isHovered = false;
|
||||
const children = [
|
||||
{ style: { animationPlayState: "X" } },
|
||||
{ style: { animationPlayState: "Y" } },
|
||||
{ style: { animationPlayState: "Z" } },
|
||||
];
|
||||
const fakeEvent: MouseEvent = {
|
||||
currentTarget: { children: [{}, {}, { children }] }
|
||||
// tslint:disable-next-line:no-any
|
||||
} as any;
|
||||
i.onEnter(fakeEvent);
|
||||
const playState = children.map(x => x.style.animationPlayState);
|
||||
expect(playState).toEqual(["paused", "paused", "paused"]);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,113 @@
|
|||
export class FBToast {
|
||||
/**
|
||||
* Warnings and errors fire once, to avoid bombarding the user with repetition.
|
||||
* Eg: "Can"t connect to server!" might get repetitive.
|
||||
*/
|
||||
static everyMessage: Record<string, boolean> = {};
|
||||
|
||||
public toastEl = document.createElement("div");
|
||||
public titleEl = document.createElement("h4");
|
||||
public messageEl = document.createElement("div");
|
||||
public loaderEl = document.createElement("div");
|
||||
public leftLoaderEl = document.createElement("div");
|
||||
public rightLoaderEl = document.createElement("div");
|
||||
public spinnerLoaderEl = document.createElement("div");
|
||||
|
||||
/** Used to stop a running interval timer */
|
||||
public intervalId = 0;
|
||||
|
||||
/** Amount of time before each element is removed. */
|
||||
public timeout = 7;
|
||||
|
||||
/** Declare if the user's mouse is hovering over the message. */
|
||||
public isHovered = false;
|
||||
|
||||
constructor(public parent: Element,
|
||||
title: string,
|
||||
public message: string,
|
||||
color: string) {
|
||||
|
||||
/** Fill contents. */
|
||||
this.titleEl.innerText = title;
|
||||
this.messageEl.innerText = message;
|
||||
|
||||
/** Add classes. */
|
||||
this.toastEl.classList.add("toast");
|
||||
this.toastEl.classList.add(color);
|
||||
this.titleEl.classList.add("toast-title");
|
||||
this.messageEl.classList.add("toast-message");
|
||||
this.loaderEl.classList.add("toast-loader");
|
||||
this.leftLoaderEl.classList.add("toast-loader-left");
|
||||
this.leftLoaderEl.classList.add(color);
|
||||
this.rightLoaderEl.classList.add("toast-loader-right");
|
||||
this.spinnerLoaderEl.classList.add("toast-loader-spinner");
|
||||
|
||||
this.loaderEl.appendChild(this.leftLoaderEl);
|
||||
this.loaderEl.appendChild(this.rightLoaderEl);
|
||||
this.loaderEl.appendChild(this.spinnerLoaderEl);
|
||||
this.toastEl.appendChild(this.titleEl);
|
||||
this.toastEl.appendChild(this.messageEl);
|
||||
this.toastEl.appendChild(this.loaderEl);
|
||||
|
||||
/** MouseLeave (resumes the timer). */
|
||||
this.toastEl.addEventListener("mouseleave", this.onLeave);
|
||||
|
||||
/** MouseEnter (pauses the timer). */
|
||||
this.toastEl.addEventListener("mouseenter", this.onEnter);
|
||||
|
||||
/** Click (makes the message go away entirely). */
|
||||
this.toastEl.addEventListener("click", this.onClick);
|
||||
|
||||
}
|
||||
|
||||
onEnter = (e: MouseEvent) => {
|
||||
const children = (e.currentTarget as HTMLElement).children[2].children;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
(children[i] as HTMLElement).style.animationPlayState = "paused";
|
||||
}
|
||||
this.isHovered = true;
|
||||
};
|
||||
|
||||
onLeave = (e: MouseEvent) => {
|
||||
const children = (e.currentTarget as HTMLElement).children[2].children;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
(children[i] as HTMLElement).style.animationPlayState = "running";
|
||||
}
|
||||
this.isHovered = false;
|
||||
};
|
||||
|
||||
detach = () => {
|
||||
this.parent.removeChild(this.toastEl);
|
||||
delete FBToast.everyMessage[this.message];
|
||||
};
|
||||
|
||||
onClick = (e: MouseEvent) => {
|
||||
(e.currentTarget as Element).classList.add("poof");
|
||||
setTimeout(this.detach, 200);
|
||||
}
|
||||
|
||||
/** Start timer. */
|
||||
doPolling = () => {
|
||||
(this.timeout <= 7) && this.toastEl.classList.add("active");
|
||||
(!this.isHovered && this.timeout <= 0.800) && this.toastEl.classList.add("poof");
|
||||
if (!this.isHovered) {
|
||||
this.timeout -= 0.100;
|
||||
if (this.timeout <= 0) {
|
||||
clearInterval(this.intervalId);
|
||||
if (this.toastEl && this.toastEl.parentNode === this.parent) {
|
||||
this.parent.removeChild(this.toastEl);
|
||||
delete FBToast.everyMessage[this.message];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
run = () => {
|
||||
|
||||
/** Append children. */
|
||||
this.parent.appendChild(this.toastEl);
|
||||
// TSC Thinks this is a node project :-\
|
||||
// tslint:disable-next-line:no-any
|
||||
this.intervalId = setInterval(this.doPolling, 100) as any;
|
||||
}
|
||||
}
|
|
@ -1,133 +1,4 @@
|
|||
class FBToast {
|
||||
/**
|
||||
* Warnings and errors fire once, to avoid bombarding the user with repetition.
|
||||
* Eg: "Can"t connect to server!" might get repetitive.
|
||||
*/
|
||||
static everyMessage: Record<string, boolean> = {};
|
||||
|
||||
public toastEl = document.createElement("div");
|
||||
public titleEl = document.createElement("h4");
|
||||
public messageEl = document.createElement("div");
|
||||
public loaderEl = document.createElement("div");
|
||||
public leftLoaderEl = document.createElement("div");
|
||||
public rightLoaderEl = document.createElement("div");
|
||||
public spinnerLoaderEl = document.createElement("div");
|
||||
|
||||
/** Used to stop a running interval timer */
|
||||
public intervalId = 0;
|
||||
|
||||
/**
|
||||
* Amount of time before each element is removed.
|
||||
*/
|
||||
public timeout = 7;
|
||||
|
||||
/**
|
||||
* Declare if the user's mouse is hovering over the message.
|
||||
*/
|
||||
public isHovered = false;
|
||||
|
||||
constructor(public parent: Element,
|
||||
title: string,
|
||||
public message: string,
|
||||
color: string) {
|
||||
/**
|
||||
* Fill contents.
|
||||
*/
|
||||
this.titleEl.innerText = title;
|
||||
this.messageEl.innerText = message;
|
||||
|
||||
/**
|
||||
* Add classes.
|
||||
*/
|
||||
this.toastEl.classList.add("toast");
|
||||
this.toastEl.classList.add(color);
|
||||
this.titleEl.classList.add("toast-title");
|
||||
this.messageEl.classList.add("toast-message");
|
||||
this.loaderEl.classList.add("toast-loader");
|
||||
this.leftLoaderEl.classList.add("toast-loader-left");
|
||||
this.leftLoaderEl.classList.add(color);
|
||||
this.rightLoaderEl.classList.add("toast-loader-right");
|
||||
this.spinnerLoaderEl.classList.add("toast-loader-spinner");
|
||||
|
||||
this.loaderEl.appendChild(this.leftLoaderEl);
|
||||
this.loaderEl.appendChild(this.rightLoaderEl);
|
||||
this.loaderEl.appendChild(this.spinnerLoaderEl);
|
||||
this.toastEl.appendChild(this.titleEl);
|
||||
this.toastEl.appendChild(this.messageEl);
|
||||
this.toastEl.appendChild(this.loaderEl);
|
||||
|
||||
/**
|
||||
* MouseLeave (resumes the timer).
|
||||
*/
|
||||
this.toastEl.addEventListener("mouseleave", this.mouseLeave);
|
||||
|
||||
/**
|
||||
* MouseEnter (pauses the timer).
|
||||
*/
|
||||
this.toastEl.addEventListener("mouseenter", this.mouseEnter);
|
||||
|
||||
/**
|
||||
* Click (makes the message go away entirely).
|
||||
*/
|
||||
this.toastEl.addEventListener("click", this.onClick);
|
||||
|
||||
}
|
||||
|
||||
mouseEnter = (e: MouseEvent) => {
|
||||
const children = (e.currentTarget as HTMLElement).children[2].children;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
(children[i] as HTMLElement).style.animationPlayState = "paused";
|
||||
}
|
||||
this.isHovered = true;
|
||||
};
|
||||
|
||||
mouseLeave = (e: MouseEvent) => {
|
||||
const children = (e.currentTarget as HTMLElement).children[2].children;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
(children[i] as HTMLElement).style.animationPlayState = "running";
|
||||
}
|
||||
this.isHovered = false;
|
||||
};
|
||||
|
||||
detach = () => {
|
||||
this.parent.removeChild(this.toastEl);
|
||||
delete FBToast.everyMessage[this.message];
|
||||
};
|
||||
|
||||
onClick = (e: MouseEvent) => {
|
||||
(e.currentTarget as Element).classList.add("poof");
|
||||
setTimeout(this.detach, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start timer.
|
||||
*/
|
||||
doPolling = () => {
|
||||
(this.timeout <= 7) && this.toastEl.classList.add("active");
|
||||
(!this.isHovered && this.timeout <= 0.800) && this.toastEl.classList.add("poof");
|
||||
if (!this.isHovered) {
|
||||
this.timeout -= 0.100;
|
||||
if (this.timeout <= 0) {
|
||||
clearInterval(this.intervalId);
|
||||
if (this.toastEl && this.toastEl.parentNode === this.parent) {
|
||||
this.parent.removeChild(this.toastEl);
|
||||
delete FBToast.everyMessage[this.message];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
run = () => {
|
||||
|
||||
/**
|
||||
* Append children.
|
||||
*/
|
||||
this.parent.appendChild(this.toastEl);
|
||||
// TSC Thinks this is a node project :-\
|
||||
// tslint:disable-next-line:no-any
|
||||
this.intervalId = setInterval(this.doPolling, 100) as any;
|
||||
}
|
||||
}
|
||||
import { FBToast } from "./fb_toast";
|
||||
|
||||
/**
|
||||
* The function responsible for attaching the messages to the container.
|
||||
|
|
Loading…
Reference in New Issue