toastify.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /*!
  2. * Toastify js 1.11.2
  3. * https://github.com/apvarun/toastify-js
  4. * @license MIT licensed
  5. *
  6. * Copyright (C) 2018 Varun A P
  7. */
  8. (function(root, factory) {
  9. if (typeof module === "object" && module.exports) {
  10. module.exports = factory();
  11. } else {
  12. root.Toastify = factory();
  13. }
  14. })(this, function(global) {
  15. // Object initialization
  16. var Toastify = function(options) {
  17. // Returning a new init object
  18. return new Toastify.lib.init(options);
  19. },
  20. // Library version
  21. version = "1.11.2";
  22. // Set the default global options
  23. Toastify.defaults = {
  24. oldestFirst: true,
  25. text: "Toastify is awesome!",
  26. node: undefined,
  27. duration: 3000,
  28. selector: undefined,
  29. callback: function () {
  30. },
  31. destination: undefined,
  32. newWindow: false,
  33. close: false,
  34. gravity: "toastify-top",
  35. positionLeft: false,
  36. position: '',
  37. backgroundColor: '',
  38. avatar: "",
  39. className: "",
  40. stopOnFocus: true,
  41. onClick: function () {
  42. },
  43. offset: {x: 0, y: 0},
  44. escapeMarkup: true,
  45. style: {background: ''}
  46. };
  47. // Defining the prototype of the object
  48. Toastify.lib = Toastify.prototype = {
  49. toastify: version,
  50. constructor: Toastify,
  51. // Initializing the object with required parameters
  52. init: function(options) {
  53. // Verifying and validating the input object
  54. if (!options) {
  55. options = {};
  56. }
  57. // Creating the options object
  58. this.options = {};
  59. this.toastElement = null;
  60. // Validating the options
  61. this.options.text = options.text || Toastify.defaults.text; // Display message
  62. this.options.node = options.node || Toastify.defaults.node; // Display content as node
  63. this.options.duration = options.duration === 0 ? 0 : options.duration || Toastify.defaults.duration; // Display duration
  64. this.options.selector = options.selector || Toastify.defaults.selector; // Parent selector
  65. this.options.callback = options.callback || Toastify.defaults.callback; // Callback after display
  66. this.options.destination = options.destination || Toastify.defaults.destination; // On-click destination
  67. this.options.newWindow = options.newWindow || Toastify.defaults.newWindow; // Open destination in new window
  68. this.options.close = options.close || Toastify.defaults.close; // Show toast close icon
  69. this.options.gravity = options.gravity === "bottom" ? "toastify-bottom" : Toastify.defaults.gravity; // toast position - top or bottom
  70. this.options.positionLeft = options.positionLeft || Toastify.defaults.positionLeft; // toast position - left or right
  71. this.options.position = options.position || Toastify.defaults.position; // toast position - left or right
  72. this.options.backgroundColor = options.backgroundColor || Toastify.defaults.backgroundColor; // toast background color
  73. this.options.avatar = options.avatar || Toastify.defaults.avatar; // img element src - url or a path
  74. this.options.className = options.className || Toastify.defaults.className; // additional class names for the toast
  75. this.options.stopOnFocus = options.stopOnFocus === undefined ? Toastify.defaults.stopOnFocus : options.stopOnFocus; // stop timeout on focus
  76. this.options.onClick = options.onClick || Toastify.defaults.onClick; // Callback after click
  77. this.options.offset = options.offset || Toastify.defaults.offset; // toast offset
  78. this.options.escapeMarkup = options.escapeMarkup !== undefined ? options.escapeMarkup : Toastify.defaults.escapeMarkup;
  79. this.options.style = options.style || Toastify.defaults.style;
  80. if(options.backgroundColor) {
  81. this.options.style.background = options.backgroundColor;
  82. }
  83. // Returning the current object for chaining functions
  84. return this;
  85. },
  86. // Building the DOM element
  87. buildToast: function() {
  88. // Validating if the options are defined
  89. if (!this.options) {
  90. throw "Toastify is not initialized";
  91. }
  92. // Creating the DOM object
  93. var divElement = document.createElement("div");
  94. divElement.className = "toastify on " + this.options.className;
  95. // Positioning toast to left or right or center
  96. if (!!this.options.position) {
  97. divElement.className += " toastify-" + this.options.position;
  98. } else {
  99. // To be depreciated in further versions
  100. if (this.options.positionLeft === true) {
  101. divElement.className += " toastify-left";
  102. console.warn('Property `positionLeft` will be depreciated in further versions. Please use `position` instead.')
  103. } else {
  104. // Default position
  105. divElement.className += " toastify-right";
  106. }
  107. }
  108. // Assigning gravity of element
  109. divElement.className += " " + this.options.gravity;
  110. if (this.options.backgroundColor) {
  111. // This is being deprecated in favor of using the style HTML DOM property
  112. console.warn('DEPRECATION NOTICE: "backgroundColor" is being deprecated. Please use the "style.background" property.');
  113. }
  114. // Loop through our style object and apply styles to divElement
  115. for (var property in this.options.style) {
  116. divElement.style[property] = this.options.style[property];
  117. }
  118. // Adding the toast message/node
  119. if (this.options.node && this.options.node.nodeType === Node.ELEMENT_NODE) {
  120. // If we have a valid node, we insert it
  121. divElement.appendChild(this.options.node)
  122. } else {
  123. if (this.options.escapeMarkup) {
  124. divElement.innerText = this.options.text;
  125. } else {
  126. divElement.innerHTML = this.options.text;
  127. }
  128. if (this.options.avatar !== "") {
  129. var avatarElement = document.createElement("img");
  130. avatarElement.src = this.options.avatar;
  131. avatarElement.className = "toastify-avatar";
  132. if (this.options.position == "left" || this.options.positionLeft === true) {
  133. // Adding close icon on the left of content
  134. divElement.appendChild(avatarElement);
  135. } else {
  136. // Adding close icon on the right of content
  137. divElement.insertAdjacentElement("afterbegin", avatarElement);
  138. }
  139. }
  140. }
  141. // Adding a close icon to the toast
  142. if (this.options.close === true) {
  143. // Create a span for close element
  144. var closeElement = document.createElement("span");
  145. closeElement.innerHTML = "✖";
  146. closeElement.className = "toast-close";
  147. // Triggering the removal of toast from DOM on close click
  148. closeElement.addEventListener(
  149. "click",
  150. function(event) {
  151. event.stopPropagation();
  152. this.removeElement(this.toastElement);
  153. window.clearTimeout(this.toastElement.timeOutValue);
  154. }.bind(this)
  155. );
  156. //Calculating screen width
  157. var width = window.innerWidth > 0 ? window.innerWidth : screen.width;
  158. // Adding the close icon to the toast element
  159. // Display on the right if screen width is less than or equal to 360px
  160. if ((this.options.position == "left" || this.options.positionLeft === true) && width > 360) {
  161. // Adding close icon on the left of content
  162. divElement.insertAdjacentElement("afterbegin", closeElement);
  163. } else {
  164. // Adding close icon on the right of content
  165. divElement.appendChild(closeElement);
  166. }
  167. }
  168. // Clear timeout while toast is focused
  169. if (this.options.stopOnFocus && this.options.duration > 0) {
  170. var self = this;
  171. // stop countdown
  172. divElement.addEventListener(
  173. "mouseover",
  174. function(event) {
  175. window.clearTimeout(divElement.timeOutValue);
  176. }
  177. )
  178. // add back the timeout
  179. divElement.addEventListener(
  180. "mouseleave",
  181. function() {
  182. divElement.timeOutValue = window.setTimeout(
  183. function() {
  184. // Remove the toast from DOM
  185. self.removeElement(divElement);
  186. },
  187. self.options.duration
  188. )
  189. }
  190. )
  191. }
  192. // Adding an on-click destination path
  193. if (typeof this.options.destination !== "undefined") {
  194. divElement.addEventListener(
  195. "click",
  196. function(event) {
  197. event.stopPropagation();
  198. if (this.options.newWindow === true) {
  199. window.open(this.options.destination, "_blank");
  200. } else {
  201. window.location = this.options.destination;
  202. }
  203. }.bind(this)
  204. );
  205. }
  206. if (typeof this.options.onClick === "function" && typeof this.options.destination === "undefined") {
  207. divElement.addEventListener(
  208. "click",
  209. function(event) {
  210. event.stopPropagation();
  211. this.options.onClick();
  212. }.bind(this)
  213. );
  214. }
  215. // Adding offset
  216. if(typeof this.options.offset === "object") {
  217. var x = getAxisOffsetAValue("x", this.options);
  218. var y = getAxisOffsetAValue("y", this.options);
  219. var xOffset = this.options.position == "left" ? x : "-" + x;
  220. var yOffset = this.options.gravity == "toastify-top" ? y : "-" + y;
  221. divElement.style.transform = "translate(" + xOffset + "," + yOffset + ")";
  222. }
  223. // Returning the generated element
  224. return divElement;
  225. },
  226. // Displaying the toast
  227. showToast: function() {
  228. // Creating the DOM object for the toast
  229. this.toastElement = this.buildToast();
  230. // Getting the root element to with the toast needs to be added
  231. var rootElement;
  232. if (typeof this.options.selector === "string") {
  233. rootElement = document.getElementById(this.options.selector);
  234. } else if (this.options.selector instanceof HTMLElement || (typeof ShadowRoot !== 'undefined' && this.options.selector instanceof ShadowRoot)) {
  235. rootElement = this.options.selector;
  236. } else {
  237. rootElement = document.body;
  238. }
  239. // Validating if root element is present in DOM
  240. if (!rootElement) {
  241. throw "Root element is not defined";
  242. }
  243. // Adding the DOM element
  244. var elementToInsert = Toastify.defaults.oldestFirst ? rootElement.firstChild : rootElement.lastChild;
  245. rootElement.insertBefore(this.toastElement, elementToInsert);
  246. // Repositioning the toasts in case multiple toasts are present
  247. Toastify.reposition();
  248. if (this.options.duration > 0) {
  249. this.toastElement.timeOutValue = window.setTimeout(
  250. function() {
  251. // Remove the toast from DOM
  252. this.removeElement(this.toastElement);
  253. }.bind(this),
  254. this.options.duration
  255. ); // Binding `this` for function invocation
  256. }
  257. // Supporting function chaining
  258. return this;
  259. },
  260. hideToast: function() {
  261. if (this.toastElement.timeOutValue) {
  262. clearTimeout(this.toastElement.timeOutValue);
  263. }
  264. this.removeElement(this.toastElement);
  265. },
  266. // Removing the element from the DOM
  267. removeElement: function(toastElement) {
  268. // Hiding the element
  269. // toastElement.classList.remove("on");
  270. toastElement.className = toastElement.className.replace(" on", "");
  271. // Removing the element from DOM after transition end
  272. window.setTimeout(
  273. function() {
  274. // remove options node if any
  275. if (this.options.node && this.options.node.parentNode) {
  276. this.options.node.parentNode.removeChild(this.options.node);
  277. }
  278. // Remove the element from the DOM, only when the parent node was not removed before.
  279. if (toastElement.parentNode) {
  280. toastElement.parentNode.removeChild(toastElement);
  281. }
  282. // Calling the callback function
  283. this.options.callback.call(toastElement);
  284. // Repositioning the toasts again
  285. Toastify.reposition();
  286. }.bind(this),
  287. 400
  288. ); // Binding `this` for function invocation
  289. },
  290. };
  291. // Positioning the toasts on the DOM
  292. Toastify.reposition = function() {
  293. // Top margins with gravity
  294. var topLeftOffsetSize = {
  295. top: 15,
  296. bottom: 15,
  297. };
  298. var topRightOffsetSize = {
  299. top: 15,
  300. bottom: 15,
  301. };
  302. var offsetSize = {
  303. top: 15,
  304. bottom: 15,
  305. };
  306. // Get all toast messages on the DOM
  307. var allToasts = document.getElementsByClassName("toastify");
  308. var classUsed;
  309. // Modifying the position of each toast element
  310. for (var i = 0; i < allToasts.length; i++) {
  311. // Getting the applied gravity
  312. if (containsClass(allToasts[i], "toastify-top") === true) {
  313. classUsed = "toastify-top";
  314. } else {
  315. classUsed = "toastify-bottom";
  316. }
  317. var height = allToasts[i].offsetHeight;
  318. classUsed = classUsed.substr(9, classUsed.length-1)
  319. // Spacing between toasts
  320. var offset = 15;
  321. var width = window.innerWidth > 0 ? window.innerWidth : screen.width;
  322. // Show toast in center if screen with less than or equal to 360px
  323. if (width <= 360) {
  324. // Setting the position
  325. allToasts[i].style[classUsed] = offsetSize[classUsed] + "px";
  326. offsetSize[classUsed] += height + offset;
  327. } else {
  328. if (containsClass(allToasts[i], "toastify-left") === true) {
  329. // Setting the position
  330. allToasts[i].style[classUsed] = topLeftOffsetSize[classUsed] + "px";
  331. topLeftOffsetSize[classUsed] += height + offset;
  332. } else {
  333. // Setting the position
  334. allToasts[i].style[classUsed] = topRightOffsetSize[classUsed] + "px";
  335. topRightOffsetSize[classUsed] += height + offset;
  336. }
  337. }
  338. }
  339. // Supporting function chaining
  340. return this;
  341. };
  342. // Helper function to get offset.
  343. function getAxisOffsetAValue(axis, options) {
  344. if(options.offset[axis]) {
  345. if(isNaN(options.offset[axis])) {
  346. return options.offset[axis];
  347. }
  348. else {
  349. return options.offset[axis] + 'px';
  350. }
  351. }
  352. return '0px';
  353. }
  354. function containsClass(elem, yourClass) {
  355. if (!elem || typeof yourClass !== "string") {
  356. return false;
  357. } else if (
  358. elem.className &&
  359. elem.className
  360. .trim()
  361. .split(/\s+/gi)
  362. .indexOf(yourClass) > -1
  363. ) {
  364. return true;
  365. } else {
  366. return false;
  367. }
  368. }
  369. // Setting up the prototype for the init object
  370. Toastify.lib.init.prototype = Toastify.lib;
  371. // Returning the Toastify function to be assigned to the window object/module
  372. return Toastify;
  373. });