diff --git a/README.md b/README.md index e783081..00511c2 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,22 @@ notify.show('Toasty!'); ``` +## Queued Notifications + +A notification queue can be created using the createShowQueue function, for example, in the constructor of a component: + +````js +constructor() { + super(); + this.show = notify.createShowQueue(); +} +```` +This queue can then be used with the same API as the notify.show function: + +````js +this.show('Toasty!'); +```` + ## Options The toast notification function `notify.show()` supports `message`, `type` and `timeout` attributes in the following way. @@ -81,3 +97,9 @@ You can also pass `-1` to cause the notification to display persistently. let myColor = { background: '#0E1717', text: "#FFFFFF" }; notify.show("this is sample text", "custom", 5000, myColor); ``` + +The createShowQueue function has two optional arguments: + +* `initialRecallDelay` is how long (in ms) to wait if the first attempt at showing a notification fails (because a non-queued notification was already being shown). Default: 500ms + +* `recallDelayIncrement` is a time (in ms) added to the recallDelay after each failed attempt. This is to mitigate numerous rapidly-repeated calls in the case of a non-queued notification being shown without a timeout. Default 500ms diff --git a/src/notify.js b/src/notify.js index 15e0d09..1b3040f 100644 --- a/src/notify.js +++ b/src/notify.js @@ -187,6 +187,7 @@ function hideToast() { /* Public functions */ /* Show Animated Toast Message */ +/* Returns true if the toast was shown, or false if show failed due to an existing notification */ function show(text, type, timeout, color) { if (!document.getElementById(notificationWrapperId).hasChildNodes()) { let renderTimeout = timeout; @@ -207,9 +208,60 @@ function show(text, type, timeout, color) { setTimeout(function() { hideToast(); }, renderTimeout + animationDuration); + + return true; } + return false; } +/* Add to Animated Toast Message Queue */ +/* Display immediately if no queue */ +/* initialRecallDelay: If the call to show fails because of an existing notification, how long to wait until we retry (ms) */ +/* recallDelayIncrement: Each time a successive call fails, the recall delay will be incremented by this (ms) */ +function createShowQueue(initialRecallDelay = 500, recallDelayIncrement = 500) { + + // Array to hold queued messages + this.msgs = []; + + // Is the showNotify function in progress - used so we can call showNotify when a + // message is added to an empty queue. + this.isNotifying = false; + + this.currentRecallDelay = initialRecallDelay; + + // Retrieve the next message from the queue and try to show it + this.showNotify = () => { + // If there are no messages in the queue + if (this.msgs.length ===0) { + this.isNotifying = false; + return; + } + + this.isNotifying = true; + + const current = this.msgs.pop(); + + // show will now return true if it is able to send the message, or false if there is an existing message + if (show(current.text, current.type, current.timeout, current.color)) { + this.currentRecallDelay = initialRecallDelay; + if (current.timeout > 0) { + setTimeout(() => this.showNotify(), current.timeout + animationDuration); + } + } else { + // If message show failed, re-add the current message to the front of the queue + this.msgs.unshift(current); + setTimeout(() => this.showNotify(), this.currentRecallDelay); + this.currentRecallDelay += recallDelayIncrement; + } + } + + return (text, type = '', timeout = defaultTimeout, color = colorWhite) => { + this.msgs.push({ text, type, timeout, color }); + if (!this.isNotifying) { + this.showNotify(); + } + } +} /* Export notification container */ export default class extends React.Component { @@ -222,5 +274,6 @@ export default class extends React.Component { /* Export notification functions */ export let notify = { - show + show, + createShowQueue };