1/*! 2 * Toastify js 1.12.0 (Class Implementation with slideFrom option) 3 * https://github.com/apvarun/toastify-js 4 * @license MIT licensed 5 * 6 * Copyright (C) 2018 Varun A P 7 * Converted to class-based implementation 8 */ 9(function (root, factory) { 10 if (typeof module === "object" && module.exports) { 11 module.exports = factory(); 12 } else { 13 root.Toastify = factory(); 14 } 15})(this, function (global) { 16 // Default global options 17 const DEFAULT_OPTIONS = { 18 oldestFirst: true, 19 text: "Toastify is awesome!", 20 node: undefined, 21 duration: 3000, 22 selector: undefined, 23 callback: function () { 24 }, 25 destination: undefined, 26 newWindow: false, 27 close: false, 28 gravity: "toastify-top", 29 positionLeft: false, 30 position: '', 31 backgroundColor: '', 32 avatar: "", 33 className: "", 34 stopOnFocus: true, 35 onClick: function () { 36 }, 37 offset: {x: 0, y: 0}, 38 escapeMarkup: true, 39 ariaLive: 'polite', 40 style: {background: ''}, 41 slideFrom: '', 42 type: '' 43 }; 44 45 class Toastify { 46 constructor(options = {}) { 47 // Creating the options object 48 this.options = {}; 49 this.toastElement = null; 50 this.version = "1.12.0"; 51 52 // Validating the options 53 this.options.text = options.text || DEFAULT_OPTIONS.text; 54 this.options.node = options.node || DEFAULT_OPTIONS.node; 55 this.options.duration = options.duration === 0 ? 0 : options.duration || DEFAULT_OPTIONS.duration; 56 this.options.selector = options.selector || DEFAULT_OPTIONS.selector; 57 this.options.callback = options.callback || DEFAULT_OPTIONS.callback; 58 this.options.destination = options.destination || DEFAULT_OPTIONS.destination; 59 this.options.newWindow = options.newWindow || DEFAULT_OPTIONS.newWindow; 60 this.options.close = options.close || DEFAULT_OPTIONS.close; 61 this.options.gravity = options.gravity === "bottom" ? "toastify-bottom" : DEFAULT_OPTIONS.gravity; 62 this.options.positionLeft = options.positionLeft || DEFAULT_OPTIONS.positionLeft; 63 this.options.position = options.position || DEFAULT_OPTIONS.position; 64 this.options.backgroundColor = options.backgroundColor || DEFAULT_OPTIONS.backgroundColor; 65 this.options.avatar = options.avatar || DEFAULT_OPTIONS.avatar; 66 this.options.className = options.className || DEFAULT_OPTIONS.className; 67 this.options.stopOnFocus = options.stopOnFocus === undefined ? DEFAULT_OPTIONS.stopOnFocus : options.stopOnFocus; 68 this.options.onClick = options.onClick || DEFAULT_OPTIONS.onClick; 69 this.options.offset = options.offset || DEFAULT_OPTIONS.offset; 70 this.options.escapeMarkup = options.escapeMarkup !== undefined ? options.escapeMarkup : DEFAULT_OPTIONS.escapeMarkup; 71 this.options.ariaLive = options.ariaLive || DEFAULT_OPTIONS.ariaLive; 72 this.options.style = options.style || Object.assign({}, DEFAULT_OPTIONS.style); 73 this.options.slideFrom = options.slideFrom || DEFAULT_OPTIONS.slideFrom; 74 this.options.type = options.type || null; 75 76 if (options.backgroundColor) { 77 this.options.style.background = options.backgroundColor; 78 } 79 } 80 81 buildToast() { 82 // Validating if the options are defined 83 if (!this.options) { 84 throw "Toastify is not initialized"; 85 } 86 87 // Creating the DOM object 88 const divElement = document.createElement("div"); 89 divElement.className = "toastify " + this.options.className; 90 91 // Positioning toast to left or right or center 92 if (!!this.options.position) { 93 divElement.className += " toastify-" + this.options.position; 94 } else { 95 // To be depreciated in further versions 96 if (this.options.positionLeft === true) { 97 divElement.className += " toastify-left"; 98 console.warn('Property `positionLeft` will be depreciated in further versions. Please use `position` instead.'); 99 } else { 100 // Default position 101 divElement.className += " toastify-right"; 102 } 103 } 104 105 // Assigning gravity of element 106 divElement.className += " " + this.options.gravity; 107 108 if (this.options.backgroundColor) {
109 // This is being deprecated in favor of using the style HTML DOM property 110 console.warn('DEPRECATION NOTICE: "backgroundColor" is being deprecated. Please use the "style.background" property.'); 111 } 112 113 // Loop through our style object and apply styles to divElement 114 for (const property in this.options.style) { 115 divElement.style[property] = this.options.style[property]; 116 } 117 118 // Announce the toast to screen readers 119 if (this.options.ariaLive) { 120 divElement.setAttribute('aria-live', this.options.ariaLive); 121 } 122 123 // Adding the toast message/node 124 if (this.options.node && this.options.node.nodeType === Node.ELEMENT_NODE) { 125 // If we have a valid node, we insert it 126 divElement.appendChild(this.options.node); 127 } else { 128 if (this.options.escapeMarkup) { 129 divElement.innerText = this.options.text; 130 } else { 131 divElement.innerHTML = this.options.text; 132 } 133 134 const successIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path fill="green" d="M512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896m-55.808 536.384-99.52-99.584a38.4 38.4 0 1 0-54.336 54.336l126.72 126.72a38.272 38.272 0 0 0 54.336 0l262.4-262.464a38.4 38.4 0 1 0-54.272-54.336z"></path></svg>'; 135 const errorIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path fill="currentColor" d="M512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896m0 393.664L407.936 353.6a38.4 38.4 0 1 0-54.336 54.336L457.664 512 353.6 616.064a38.4 38.4 0 1 0 54.336 54.336L512 566.336 616.064 670.4a38.4 38.4 0 1 0 54.336-54.336L566.336 512 670.4 407.936a38.4 38.4 0 1 0-54.336-54.336z"></path></svg>'; 136 const infoIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path fill="currentColor" d="M512 64a448 448 0 1 1 0 896.064A448 448 0 0 1 512 64m67.2 275.072c33.28 0 60.288-23.104 60.288-57.344s-27.072-57.344-60.288-57.344c-33.28 0-60.16 23.104-60.16 57.344s26.88 57.344 60.16 57.344M590.912 699.2c0-6.848 2.368-24.64 1.024-34.752l-52.608 60.544c-10.88 11.456-24.512 19.392-30.912 17.28a12.992 12.992 0 0 1-8.256-14.72l87.68-276.992c7.168-35.136-12.544-67.2-54.336-71.296-44.096 0-108.992 44.736-148.48 101.504 0 6.784-1.28 23.68.064 33.792l52.544-60.608c10.88-11.328 23.552-19.328 29.952-17.152a12.8 12.8 0 0 1 7.808 16.128L388.48 728.576c-10.048 32.256 8.96 63.872 55.04 71.04 67.84 0 107.904-43.648 147.456-100.416z"></path></svg>'; 137 const warningIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path fill="currentColor" d="M512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896m0 192a58.432 58.432 0 0 0-58.24 63.744l23.36 256.384a35.072 35.072 0 0 0 69.76 0l23.296-256.384A58.432 58.432 0 0 0 512 256m0 512a51.2 51.2 0 1 0 0-102.4 51.2 51.2 0 0 0 0 102.4"></path></svg>'; 138 139 if (this.options.type) { 140 141 142 const icon = document.createElement('div'); 143 icon.classList.add('toastify-icon'); 144 if (this.options.type === 'success') { 145 icon.innerHTML = successIcon.trim(); 146 icon.classList.add('success'); 147 } else if (this.options.type === 'error') { 148 icon.innerHTML = errorIcon.trim(); 149 icon.classList.add('error'); 150 } else if (this.options.type === 'info') { 151 icon.innerHTML = infoIcon.trim(); 152 icon.classList.add('info'); 153 } else if (this.options.type === 'warning') { 154 icon.innerHTML = warningIcon.trim(); 155 icon.classList.add('warning'); 156 } 157 158 divElement.classList.add('has-toastify-icon'); 159 160 if (this.options.position === "left" || this.options.positionLeft === true) { 161 // Adding close icon on the left of content 162 divElement.appendChild(icon); 163 164 } else { 165 // Adding close icon on the right of content 166 divElement.insertAdjacentElement("afterbegin", icon); 167 } 168 } 169 170 if (this.options.avatar !== "" && !this.options.type) { 171 const avatarElement = document.createElement("img"); 172 avatarElement.src = this.options.avatar; 173 avatarElement.className = "toastify-avatar"; 174 175 if (this.options.position == "left" || this.options.positionLeft === true) { 176 // Adding close icon on the left of content 177 divElement.appendChild(avatarElement); 178 } else { 179 // Adding close icon on the right of content 180 divElement.insertAdjacentElement("afterbegin", avatarElement); 181 } 182 } 183 } 184 185 // Adding a close icon to the toast 186 if (this.options.close === true) { 187 // Create a span for close element 188 const closeElement = document.createElement("button"); 189 closeElement.type = "button"; 190 closeElement.setAttribute("aria-label", "Close"); 191 closeElement.className = "toast-close"; 192 closeElement.innerHTML = "✖"; 193 194 // Triggering the removal of toast from DOM on close click 195 closeElement.addEventListener( 196 "click", 197 (event) => { 198 event.stopPropagation(); 199 this.removeElement(this.toastElement); 200 window.clearTimeout(this.toastElement.timeOutValue); 201 } 202 ); 203 204 //Calculating screen width 205 const width = window.innerWidth > 0 ? window.innerWidth : screen.width; 206 207 // Adding the close icon to the toast element 208 // Display on the right if screen width is less than or equal to 360px 209 if ((this.options.position == "left" || this.options.positionLeft === true) && width > 360) { 210 // Adding close icon on the left of content 211 divElement.insertAdjacentElement("afterbegin", closeElement); 212 } else { 213 // Adding close icon on the right of content 214 divElement.appendChild(closeElement); 215 } 216 } 217 218 // Clear timeout while toast is focused 219 if (this.options.stopOnFocus && this.options.duration > 0) { 220 // stop countdown 221 divElement.addEventListener( 222 "mouseover", 223 () => { 224 window.clearTimeout(divElement.timeOutValue); 225 } 226 ); 227 228 // add back the timeout 229 divElement.addEventListener( 230 "mouseleave", 231 () => { 232 divElement.timeOutValue = window.setTimeout( 233 () => { 234 // Remove the toast from DOM 235 this.removeElement(divElement); 236 }, 237 this.options.duration 238 ); 239 } 240 ); 241 } 242 243 // Adding an on-click destination path 244 if (typeof this.options.destination !== "undefined") { 245 divElement.addEventListener( 246 "click", 247 (event) => { 248 event.stopPropagation(); 249 if (this.options.newWindow === true) { 250 window.open(this.options.destination, "_blank"); 251 } else { 252 window.location = this.options.destination; 253 } 254 } 255 ); 256 } 257 258 if (typeof this.options.onClick === "function" && typeof this.options.destination === "undefined") { 259 divElement.addEventListener( 260 "click", 261 (event) => { 262 event.stopPropagation(); 263 this.options.onClick(); 264 } 265 ); 266 } 267 268 // Adding offset 269 if (typeof this.options.offset === "object") { 270 const x = Toastify.getAxisOffsetAValue("x", this.options); 271 const y = Toastify.getAxisOffsetAValue("y", this.options); 272 273 const xOffset = this.options.position == "left" ? x : "-" + x; 274 const yOffset = this.options.gravity == "toastify-top" ? y : "-" + y; 275 276 divElement.style.transform = "translate(" + xOffset + "," + yOffset + ")"; 277 } 278 279 return divElement; 280 } 281 282 // Get initial position for slide animation 283 getSlidePosition() { 284 if (!this.options.slideFrom) return null; 285 286 const width = window.innerWidth; 287 const height = window.innerHeight; 288 289 switch (this.options.slideFrom.toLowerCase()) { 290 case 'left': 291 return {transform: `translateX(-${width}px)`}; 292 case 'right': 293 return {transform: `translateX(${width}px)`}; 294 case 'top': 295 return {transform: `translateY(-${height}px)`}; 296 case 'bottom': 297 return {transform: `translateY(${height}px)`}; 298 default: 299 return null; 300 } 301 } 302 303 // Get final position considering offsets 304 getFinalPosition() { 305 let transform = ""; 306 307 if (typeof this.options.offset === "object") { 308 const x = Toastify.getAxisOffsetAValue("x", this.options); 309 const y = Toastify.getAxisOffsetAValue("y", this.options); 310 311 const xOffset = this.options.position == "left" ? x : "-" + x; 312 const yOffset = this.options.gravity == "toastify-top" ? y : "-" + y; 313 314 transform = `translate(${xOffset}, ${yOffset})`; 315 } 316 317 return {transform}; 318 } 319 320 showToast() { 321 // Creating the DOM object for the toast 322 this.toastElement = this.buildToast(); 323 324 // Apply slide animation if needed
325 const initialPosition = this.getSlidePosition(); 326 if (initialPosition) { 327 // Apply initial position (off-screen) 328 Object.assign(this.toastElement.style, initialPosition); 329 } 330 331 // Getting the root element to with the toast needs to be added 332 let rootElement; 333 if (typeof this.options.selector === "string") { 334 rootElement = document.getElementById(this.options.selector); 335 } else if (this.options.selector instanceof HTMLElement || (typeof ShadowRoot !== 'undefined' && this.options.selector instanceof ShadowRoot)) { 336 rootElement = this.options.selector; 337 } else { 338 rootElement = document.body; 339 } 340 341 // Validating if root element is present in DOM 342 if (!rootElement) { 343 throw "Root element is not defined"; 344 } 345 346 // Adding the DOM element 347 const elementToInsert = DEFAULT_OPTIONS.oldestFirst ? rootElement.firstChild : rootElement.lastChild; 348 rootElement.insertBefore(this.toastElement, elementToInsert); 349 // Force reflow 350 void this.toastElement.offsetWidth; 351 352 // Add the "on" class for default fade-in 353 if (!this.options.slideFrom) { 354 this.toastElement.className += " on"; 355 } 356 357 // If using slideFrom, animate to final position 358 if (initialPosition) { 359 // Make sure transition is applied 360 this.toastElement.style.transition = "transform 0.4s cubic-bezier(0.215, 0.61, 0.355, 1), opacity 0.4s cubic-bezier(0.215, 0.61, 0.355, 1)"; 361 362 // Force browser to recognize the element before animation 363 setTimeout(() => { 364 const finalPosition = this.getFinalPosition(); 365 Object.assign(this.toastElement.style, finalPosition); 366 this.toastElement.className += " on"; 367 }, 20); 368 } 369 370 // Repositioning the toasts in case multiple toasts are present 371 Toastify.reposition(); 372 373 if (this.options.duration > 0) { 374 this.toastElement.timeOutValue = window.setTimeout( 375 () => { 376 // Remove the toast from DOM 377 this.removeElement(this.toastElement); 378 }, 379 this.options.duration 380 ); 381 } 382 383 // Supporting function chaining 384 return this; 385 } 386 387 hideToast() { 388 if (this.toastElement.timeOutValue) { 389 clearTimeout(this.toastElement.timeOutValue); 390 } 391 this.removeElement(this.toastElement); 392 } 393 394 removeElement(toastElement) { 395 // If using slideFrom, animate out in that direction 396 if (this.options.slideFrom) { 397 const width = window.innerWidth; 398 const height = window.innerHeight; 399 400 // Ensure transition is still applied 401 toastElement.style.transition = "transform 0.4s cubic-bezier(0.215, 0.61, 0.355, 1), opacity 0.4s cubic-bezier(0.215, 0.61, 0.355, 1)"; 402 403 // Set exit transform based on slide direction 404 switch (this.options.slideFrom.toLowerCase()) { 405 case 'left': 406 toastElement.style.transform = `translateX(-${width}px)`; 407 break; 408 case 'right': 409 toastElement.style.transform = `translateX(${width}px)`; 410 break; 411 case 'top': 412 toastElement.style.transform = `translateY(-${height}px)`; 413 break; 414 case 'bottom': 415 toastElement.style.transform = `translateY(${height}px)`; 416 break; 417 } 418 419 // Also reduce opacity 420 toastElement.style.opacity = '0'; 421 } else { 422 // Standard removal - just remove "on" class 423 toastElement.className = toastElement.className.replace(" on", ""); 424 } 425 426 // Removing the element from DOM after transition end 427 window.setTimeout( 428 () => { 429 // remove options node if any 430 if (this.options.node && this.options.node.parentNode) { 431 this.options.node.parentNode.removeChild(this.options.node); 432 } 433 434 // Remove the element from the DOM, only when the parent node was not removed before. 435 if (toastElement.parentNode) { 436 toastElement.parentNode.removeChild(toastElement); 437 } 438 439 // Calling the callback function 440 this.options.callback.call(toastElement); 441 442 // Repositioning the toasts again 443 Toastify.reposition(); 444 }, 445 400 446 ); 447 } 448 449 // Static helper method to get offset 450 static getAxisOffsetAValue(axis, options) { 451 if (options.offset[axis]) { 452 if (isNaN(options.offset[axis])) { 453 return options.offset[axis]; 454 } else { 455 return options.offset[axis] + 'px'; 456 } 457 } 458 return '0px'; 459 } 460 461 // Static method to check if an element contains a class 462 static containsClass(elem, yourClass) { 463 if (!elem || typeof yourClass !== "string") { 464 return false;
465 } else if ( 466 elem.className && 467 elem.className 468 .trim() 469 .split(/\s+/gi) 470 .indexOf(yourClass) > -1 471 ) { 472 return true; 473 } else { 474 return false; 475 } 476 } 477 478 // Static method to reposition all toasts 479 static reposition() { 480 // Top and bottom margins 481 const topLeftOffsetSize = { 482 top: 15, 483 bottom: 15, 484 }; 485 const topRightOffsetSize = { 486 top: 15, 487 bottom: 15, 488 }; 489 const offsetSize = { 490 top: 15, 491 bottom: 15, 492 }; 493 494 // Get all toast messages on the DOM 495 const allToasts = Array.from(document.getElementsByClassName("toastify")); 496 497 // Reverse the order for bottom stacking when oldestFirst is false 498 499 500 if (Toastify.defaults.oldestFirst) { 501 allToasts.reverse(); 502 } 503 504 let classUsed; 505 506 // Modifying the position of each toast element 507 for (let i = 0; i < allToasts.length; i++) { 508 // Getting the applied gravity 509 if (Toastify.containsClass(allToasts[i], "toastify-top") === true) { 510 classUsed = "toastify-top"; 511 } else { 512 classUsed = "toastify-bottom"; 513 } 514 515 const height = allToasts[i].offsetHeight; 516 classUsed = classUsed.substr(9, classUsed.length - 1); // Get 'top' or 'bottom' 517 // Spacing between toasts 518 const offset = 15; 519 520 const width = window.innerWidth > 0 ? window.innerWidth : screen.width; 521 522 // Show toast in center if screen width is less than or equal to 360px 523 if (width <= 360) { 524 // Setting the position 525 allToasts[i].style[classUsed] = offsetSize[classUsed] + "px"; 526 offsetSize[classUsed] += height + offset; 527 } else { 528 if (Toastify.containsClass(allToasts[i], "toastify-left") === true) { 529 // Setting the position 530 allToasts[i].style[classUsed] = topLeftOffsetSize[classUsed] + "px"; 531 topLeftOffsetSize[classUsed] += height + offset; 532 } else { 533 // Setting the position 534 allToasts[i].style[classUsed] = topRightOffsetSize[classUsed] + "px"; 535 topRightOffsetSize[classUsed] += height + offset; 536 } 537 } 538 } 539 540 // Supporting function chaining 541 return this; 542 } 543 } 544 545 // Set default options as static property 546 Toastify.defaults = DEFAULT_OPTIONS; 547 548 // Return the Toastify class 549 return Toastify; 550});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.