11import { htmlEscape } from 'escape-goat' ;
22import { svg } from '../svg.js' ;
3+ import { animateOnce , showElem } from '../utils/dom.js' ;
34import Toastify from 'toastify-js' ; // don't use "async import", because when network error occurs, the "async import" also fails and nothing is shown
45
56const levels = {
@@ -21,13 +22,28 @@ const levels = {
2122} ;
2223
2324// See https://github.com/apvarun/toastify-js#api for options
24- function showToast ( message , level , { gravity, position, duration, useHtmlBody, ...other } = { } ) {
25+ function showToast ( message , level , { gravity, position, duration, useHtmlBody, preventDuplicates = true , ...other } = { } ) {
26+ const body = useHtmlBody ? String ( message ) : htmlEscape ( message ) ;
27+ const key = `${ level } -${ body } ` ;
28+
29+ // prevent showing duplicate toasts with same level and message, and give a visual feedback for end users
30+ if ( preventDuplicates ) {
31+ const toastEl = document . querySelector ( `.toastify[data-toast-unique-key="${ CSS . escape ( key ) } "]` ) ;
32+ if ( toastEl ) {
33+ const toastDupNumEl = toastEl . querySelector ( '.toast-duplicate-number' ) ;
34+ showElem ( toastDupNumEl ) ;
35+ toastDupNumEl . textContent = String ( Number ( toastDupNumEl . textContent ) + 1 ) ;
36+ animateOnce ( toastDupNumEl , 'pulse-1p5-200' ) ;
37+ return ;
38+ }
39+ }
40+
2541 const { icon, background, duration : levelDuration } = levels [ level ?? 'info' ] ;
2642 const toast = Toastify ( {
2743 text : `
2844 <div class='toast-icon'>${ svg ( icon ) } </div>
29- <div class='toast-body'>${ useHtmlBody ? message : htmlEscape ( message ) } </div>
30- <button class='toast-close'>${ svg ( 'octicon-x' ) } </button>
45+ <div class='toast-body'><span class="toast-duplicate-number tw-hidden">1</span> ${ body } </div>
46+ <button class='btn toast-close'>${ svg ( 'octicon-x' ) } </button>
3147 ` ,
3248 escapeMarkup : false ,
3349 gravity : gravity ?? 'top' ,
@@ -39,6 +55,7 @@ function showToast(message, level, {gravity, position, duration, useHtmlBody, ..
3955
4056 toast . showToast ( ) ;
4157 toast . toastElement . querySelector ( '.toast-close' ) . addEventListener ( 'click' , ( ) => toast . hideToast ( ) ) ;
58+ toast . toastElement . setAttribute ( 'data-toast-unique-key' , key ) ;
4259 return toast ;
4360}
4461
0 commit comments