Add alert class
This commit is contained in:
parent
e57977f94b
commit
a0ef7f3854
@ -526,6 +526,43 @@ button > * {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.alert {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
width: 300px;
|
||||
background: #666;
|
||||
color: white;
|
||||
font-family: "Open Sans", Verdana, sans-serif;
|
||||
font-size: 0.8em;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
margin: 1em 0 1em -150px;
|
||||
padding: 6px 20px;
|
||||
border-radius: 5px;
|
||||
border-top: 1px solid #555;
|
||||
box-shadow: 10px 10px 10px -8px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.alert.error {
|
||||
background: #d95b5b;
|
||||
border-top: 1px solid #d05858;
|
||||
}
|
||||
|
||||
.alert button {
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
right: 0;
|
||||
border: none;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
background: none;
|
||||
font-weight: normal;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
/* chart */
|
||||
.ct-point {
|
||||
transition: 0.3s;
|
||||
|
132
js/src/alert.js
Normal file
132
js/src/alert.js
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* μlogger
|
||||
*
|
||||
* Copyright(C) 2019 Bartek Fabiszewski (www.fabiszewski.net)
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import uUtils from './utils.js';
|
||||
|
||||
export default class uAlert {
|
||||
|
||||
/**
|
||||
* @typedef {Object} AlertOptions
|
||||
* @property {number} [autoClose=0] Optional autoclose delay time in ms, default 0 – no autoclose
|
||||
* @property {string} [id] Optional box id
|
||||
* @property {string} [class] Optional box class
|
||||
*/
|
||||
|
||||
/**
|
||||
* Builds alert box
|
||||
* @param {string} message
|
||||
* @param {AlertOptions} [options] Optional options
|
||||
*/
|
||||
constructor(message, options = {}) {
|
||||
this.autoClose = options.autoClose || 0;
|
||||
const html = `<div class="alert"><span>${message}</span></div>`;
|
||||
this.box = uUtils.nodeFromHtml(html);
|
||||
if (options.id) {
|
||||
this.box.id = options.id;
|
||||
}
|
||||
if (options.class) {
|
||||
this.box.classList.add(options.class);
|
||||
}
|
||||
if (this.autoClose === 0) {
|
||||
const button = document.createElement('button');
|
||||
button.setAttribute('type', 'button');
|
||||
button.textContent = '×';
|
||||
button.onclick = () => this.destroy();
|
||||
this.box.appendChild(button);
|
||||
}
|
||||
this.closeHandle = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate new box top offset
|
||||
* @return {number} Top offset
|
||||
*/
|
||||
static getPosition() {
|
||||
const boxes = document.querySelectorAll('.alert');
|
||||
const lastBox = boxes[boxes.length - 1];
|
||||
let position = 0;
|
||||
if (lastBox) {
|
||||
const maxPosition = document.body.clientHeight - 100;
|
||||
position = lastBox.getBoundingClientRect().bottom;
|
||||
if (position > maxPosition) {
|
||||
position = maxPosition;
|
||||
}
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
render() {
|
||||
const top = uAlert.getPosition();
|
||||
if (top) {
|
||||
this.box.style.top = `${top}px`;
|
||||
}
|
||||
document.body.appendChild(this.box);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this.closeHandle) {
|
||||
clearTimeout(this.closeHandle);
|
||||
this.closeHandle = null;
|
||||
}
|
||||
if (this.box) {
|
||||
if (document.body.contains(this.box)) {
|
||||
document.body.removeChild(this.box);
|
||||
}
|
||||
this.box = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show alert box
|
||||
* @param {string} message
|
||||
* @param {AlertOptions} [options] Optional options
|
||||
* @return uAlert
|
||||
*/
|
||||
static show(message, options) {
|
||||
const box = new uAlert(message, options);
|
||||
box.render();
|
||||
if (box.autoClose) {
|
||||
box.closeHandle = setTimeout(() => box.destroy(), box.autoClose);
|
||||
}
|
||||
return box;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show alert error box
|
||||
* @param {string} message
|
||||
* @param {Error=} e Optional error to be logged to console
|
||||
* @return uAlert
|
||||
*/
|
||||
static error(message, e) {
|
||||
if (e instanceof Error) {
|
||||
console.error(`${e.name}: ${e.message} (${e.stack})`);
|
||||
}
|
||||
return this.show(message, { class: 'error' });
|
||||
}
|
||||
|
||||
/**
|
||||
* Show alert toast box
|
||||
* @param {string} message
|
||||
* @return uAlert
|
||||
*/
|
||||
static toast(message) {
|
||||
return this.show(message, { class: 'toast', autoClose: 10000 });
|
||||
}
|
||||
|
||||
}
|
@ -280,22 +280,6 @@ export default class uUtils {
|
||||
window.location.assign(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {(Error|string)} e
|
||||
* @param {string=} message
|
||||
*/
|
||||
static error(e, message) {
|
||||
let details;
|
||||
if (e instanceof Error) {
|
||||
details = `${e.name}: ${e.message} (${e.stack})`;
|
||||
} else {
|
||||
details = e;
|
||||
message = e;
|
||||
}
|
||||
console.error(details);
|
||||
alert(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Degrees to radians
|
||||
* @param {number} degrees
|
||||
|
143
js/test/alert.test.js
Normal file
143
js/test/alert.test.js
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* μlogger
|
||||
*
|
||||
* Copyright(C) 2020 Bartek Fabiszewski (www.fabiszewski.net)
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import uAlert from '../src/alert.js';
|
||||
|
||||
describe('Alert tests', () => {
|
||||
|
||||
const message = 'test message';
|
||||
let alert;
|
||||
|
||||
afterEach(() => {
|
||||
if (alert) {
|
||||
alert.destroy();
|
||||
}
|
||||
document.body.innerText = '';
|
||||
});
|
||||
|
||||
it('should create alert box with message', () => {
|
||||
// when
|
||||
alert = new uAlert(message);
|
||||
const textEl = alert.box.firstChild;
|
||||
// then
|
||||
expect(textEl.innerText).toBe(message);
|
||||
});
|
||||
|
||||
it('should create alert box with autoClose option', () => {
|
||||
// given
|
||||
const autoClose = 1;
|
||||
const options = { autoClose }
|
||||
// when
|
||||
alert = new uAlert(message, options);
|
||||
const textEl = alert.box.firstChild;
|
||||
// then
|
||||
expect(textEl.innerText).toBe(message);
|
||||
expect(alert.autoClose).toBe(autoClose);
|
||||
});
|
||||
|
||||
it('should create alert box with id option', () => {
|
||||
// given
|
||||
const id = 'testId';
|
||||
const options = { id }
|
||||
// when
|
||||
alert = new uAlert(message, options);
|
||||
const boxEl = alert.box;
|
||||
const textEl = alert.box.firstChild;
|
||||
// then
|
||||
expect(textEl.innerText).toBe(message);
|
||||
expect(boxEl.id).toBe(id);
|
||||
});
|
||||
|
||||
it('should create alert box with class option', () => {
|
||||
// given
|
||||
const className = 'test_class';
|
||||
const options = { class: className }
|
||||
// when
|
||||
alert = new uAlert(message, options);
|
||||
const boxEl = alert.box;
|
||||
const textEl = alert.box.firstChild;
|
||||
// then
|
||||
expect(textEl.innerText).toBe(message);
|
||||
expect(boxEl.classList).toContain(className);
|
||||
});
|
||||
|
||||
it('should render and destroy alert box', () => {
|
||||
// given
|
||||
const id = 'testId';
|
||||
const options = { id }
|
||||
alert = new uAlert(message, options);
|
||||
|
||||
// when
|
||||
alert.render();
|
||||
// then
|
||||
expect(document.querySelector(`#${id}`)).not.toBeNull();
|
||||
|
||||
// when
|
||||
alert.destroy();
|
||||
// then
|
||||
expect(document.querySelector(`#${id}`)).toBeNull();
|
||||
});
|
||||
|
||||
it('should show and autoclose alert box', (done) => {
|
||||
// given
|
||||
const id = 'testId';
|
||||
const options = { id: id, autoClose: 50 }
|
||||
|
||||
// when
|
||||
alert = uAlert.show(message, options);
|
||||
// then
|
||||
expect(document.querySelector(`#${id}`)).not.toBeNull();
|
||||
|
||||
setTimeout(() => {
|
||||
expect(document.querySelector(`#${id}`)).toBeNull();
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should close alert box on close button click', (done) => {
|
||||
// given
|
||||
const id = 'testId';
|
||||
const options = { id }
|
||||
alert = uAlert.show(message, options);
|
||||
const closeButton = alert.box.querySelector('button');
|
||||
// when
|
||||
closeButton.click();
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(document.querySelector(`#${id}`)).toBeNull();
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should show error alert box', () => {
|
||||
// when
|
||||
alert = uAlert.error(message);
|
||||
// then
|
||||
expect(document.querySelector('.alert.error')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should show toast alert box', () => {
|
||||
// when
|
||||
alert = uAlert.toast(message);
|
||||
// then
|
||||
expect(document.querySelector('.alert.toast')).not.toBeNull();
|
||||
expect(alert.autoClose).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user