toastr.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. /*
  2. * Toastr
  3. * Copyright 2012-2015
  4. * Authors: John Papa, Hans Fjällemark, and Tim Ferrell.
  5. * All Rights Reserved.
  6. * Use, reproduction, distribution, and modification of this code is subject to the terms and
  7. * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
  8. *
  9. * ARIA Support: Greta Krafsig
  10. *
  11. * Project: https://github.com/CodeSeven/toastr
  12. */
  13. /* global define */
  14. (function (define) {
  15. define(['jquery'], function ($) {
  16. return (function () {
  17. var $container;
  18. var listener;
  19. var toastId = 0;
  20. var toastType = {
  21. error: 'error',
  22. info: 'info',
  23. success: 'success',
  24. warning: 'warning'
  25. };
  26. var toastr = {
  27. clear: clear,
  28. remove: remove,
  29. error: error,
  30. getContainer: getContainer,
  31. info: info,
  32. options: {},
  33. subscribe: subscribe,
  34. success: success,
  35. version: '2.1.2',
  36. warning: warning
  37. };
  38. var previousToast;
  39. toastr.loading = function () {
  40. var div = document.createElement("div");
  41. $(div).appendTo('body');
  42. $(div).css({
  43. position: 'fixed',
  44. top: '0px',
  45. left: '0px',
  46. right: '0px',
  47. bottom: '0px',
  48. zIndex: 999999
  49. }).html('<div class="loader loader--glisteningWindow"></div>');
  50. div.id = 'toast-loading';
  51. $(div).addClass('loading');
  52. $(div).find('.loader').css({
  53. position: 'fixed',
  54. top: '40%',
  55. left: '50%'
  56. });
  57. };
  58. toastr.loading.close = function () {
  59. $('#toast-loading').remove();
  60. };
  61. return toastr;
  62. ////////////////
  63. function error(message, title, optionsOverride) {
  64. return notify({
  65. type: toastType.error,
  66. iconClass: getOptions().iconClasses.error,
  67. message: message,
  68. optionsOverride: optionsOverride,
  69. title: title
  70. });
  71. }
  72. function getContainer(options, create) {
  73. if (!options) {
  74. options = getOptions();
  75. }
  76. $container = $('#' + options.containerId);
  77. if ($container.length) {
  78. return $container;
  79. }
  80. if (create) {
  81. $container = createContainer(options);
  82. }
  83. return $container;
  84. }
  85. function info(message, title, optionsOverride) {
  86. return notify({
  87. type: toastType.info,
  88. iconClass: getOptions().iconClasses.info,
  89. message: message,
  90. optionsOverride: optionsOverride,
  91. title: title
  92. });
  93. }
  94. function subscribe(callback) {
  95. listener = callback;
  96. }
  97. function success(message, title, optionsOverride) {
  98. return notify({
  99. type: toastType.success,
  100. iconClass: getOptions().iconClasses.success,
  101. message: message,
  102. optionsOverride: optionsOverride,
  103. title: title
  104. });
  105. }
  106. function warning(message, title, optionsOverride) {
  107. return notify({
  108. type: toastType.warning,
  109. iconClass: getOptions().iconClasses.warning,
  110. message: message,
  111. optionsOverride: optionsOverride,
  112. title: title
  113. });
  114. }
  115. function clear($toastElement, clearOptions) {
  116. var options = getOptions();
  117. if (!$container) {
  118. getContainer(options);
  119. }
  120. if (!clearToast($toastElement, options, clearOptions)) {
  121. clearContainer(options);
  122. }
  123. }
  124. function remove($toastElement) {
  125. var options = getOptions();
  126. if (!$container) {
  127. getContainer(options);
  128. }
  129. if ($toastElement && $(':focus', $toastElement).length === 0) {
  130. removeToast($toastElement);
  131. return;
  132. }
  133. if ($container.children().length) {
  134. $container.remove();
  135. }
  136. }
  137. // internal functions
  138. function clearContainer(options) {
  139. var toastsToClear = $container.children();
  140. for (var i = toastsToClear.length - 1; i >= 0; i--) {
  141. clearToast($(toastsToClear[i]), options);
  142. }
  143. }
  144. function clearToast($toastElement, options, clearOptions) {
  145. var force = clearOptions && clearOptions.force ? clearOptions.force : false;
  146. if ($toastElement && (force || $(':focus', $toastElement).length === 0)) {
  147. $toastElement[options.hideMethod]({
  148. duration: options.hideDuration,
  149. easing: options.hideEasing,
  150. complete: function () {
  151. removeToast($toastElement);
  152. }
  153. });
  154. return true;
  155. }
  156. return false;
  157. }
  158. function createContainer(options) {
  159. $container = $('<div/>')
  160. .attr('id', options.containerId)
  161. .addClass(options.positionClass)
  162. .attr('aria-live', 'polite')
  163. .attr('role', 'alert');
  164. $container.appendTo($(options.target));
  165. return $container;
  166. }
  167. function getDefaults() {
  168. return {
  169. tapToDismiss: true,
  170. toastClass: 'toast',
  171. containerId: 'toast-container',
  172. debug: false,
  173. showMethod: 'fadeIn', //fadeIn, slideDown, and show are built into jQuery
  174. showDuration: 300,
  175. showEasing: 'swing', //swing and linear are built into jQuery
  176. onShown: undefined,
  177. hideMethod: 'fadeOut',
  178. hideDuration: 1000,
  179. hideEasing: 'swing',
  180. onHidden: undefined,
  181. closeMethod: false,
  182. closeDuration: false,
  183. closeEasing: false,
  184. extendedTimeOut: 1000,
  185. iconClasses: {
  186. error: 'toast-error',
  187. info: 'toast-info',
  188. success: 'toast-success',
  189. warning: 'toast-warning'
  190. },
  191. iconClass: 'toast-info',
  192. positionClass: 'toast-top-right',
  193. timeOut: 5000, // Set timeOut and extendedTimeOut to 0 to make it sticky
  194. titleClass: 'toast-title',
  195. messageClass: 'toast-message',
  196. escapeHtml: false,
  197. target: 'body',
  198. closeHtml: '<button type="button">&times;</button>',
  199. newestOnTop: true,
  200. preventDuplicates: false,
  201. progressBar: false
  202. };
  203. }
  204. function publish(args) {
  205. if (!listener) {
  206. return;
  207. }
  208. listener(args);
  209. }
  210. function notify(map) {
  211. var options = getOptions();
  212. var iconClass = map.iconClass || options.iconClass;
  213. if (typeof (map.optionsOverride) !== 'undefined') {
  214. options = $.extend(options, map.optionsOverride);
  215. iconClass = map.optionsOverride.iconClass || iconClass;
  216. }
  217. if (shouldExit(options, map)) {
  218. return;
  219. }
  220. toastId++;
  221. $container = getContainer(options, true);
  222. var intervalId = null;
  223. var $toastElement = $('<div/>');
  224. var $titleElement = $('<div/>');
  225. var $messageElement = $('<div/>');
  226. var $progressElement = $('<div/>');
  227. var $closeElement = $(options.closeHtml);
  228. var progressBar = {
  229. intervalId: null,
  230. hideEta: null,
  231. maxHideTime: null
  232. };
  233. var response = {
  234. toastId: toastId,
  235. state: 'visible',
  236. startTime: new Date(),
  237. options: options,
  238. map: map
  239. };
  240. personalizeToast();
  241. displayToast();
  242. handleEvents();
  243. publish(response);
  244. if (options.debug && console) {
  245. console.log(response);
  246. }
  247. return $toastElement;
  248. function escapeHtml(source) {
  249. if (source == null)
  250. source = "";
  251. return new String(source)
  252. .replace(/&/g, '&amp;')
  253. .replace(/"/g, '&quot;')
  254. .replace(/'/g, '&#39;')
  255. .replace(/</g, '&lt;')
  256. .replace(/>/g, '&gt;');
  257. }
  258. function personalizeToast() {
  259. setIcon();
  260. setTitle();
  261. setMessage();
  262. setCloseButton();
  263. setProgressBar();
  264. setSequence();
  265. }
  266. function handleEvents() {
  267. $toastElement.hover(stickAround, delayedHideToast);
  268. if (!options.onclick && options.tapToDismiss) {
  269. $toastElement.click(hideToast);
  270. }
  271. if (options.closeButton && $closeElement) {
  272. $closeElement.click(function (event) {
  273. if (event.stopPropagation) {
  274. event.stopPropagation();
  275. } else if (event.cancelBubble !== undefined && event.cancelBubble !== true) {
  276. event.cancelBubble = true;
  277. }
  278. hideToast(true);
  279. });
  280. }
  281. if (options.onclick) {
  282. $toastElement.click(function (event) {
  283. options.onclick(event);
  284. hideToast();
  285. });
  286. }
  287. }
  288. function displayToast() {
  289. $toastElement.hide();
  290. $toastElement[options.showMethod](
  291. {duration: options.showDuration, easing: options.showEasing, complete: options.onShown}
  292. );
  293. if (options.timeOut > 0) {
  294. intervalId = setTimeout(hideToast, options.timeOut);
  295. progressBar.maxHideTime = parseFloat(options.timeOut);
  296. progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;
  297. if (options.progressBar) {
  298. progressBar.intervalId = setInterval(updateProgress, 10);
  299. }
  300. }
  301. }
  302. function setIcon() {
  303. if (map.iconClass) {
  304. $toastElement.addClass(options.toastClass).addClass(iconClass);
  305. }
  306. }
  307. function setSequence() {
  308. if (options.newestOnTop) {
  309. $container.prepend($toastElement);
  310. } else {
  311. $container.append($toastElement);
  312. }
  313. }
  314. function setTitle() {
  315. if (map.title) {
  316. $titleElement.append(!options.escapeHtml ? map.title : escapeHtml(map.title)).addClass(options.titleClass);
  317. $toastElement.append($titleElement);
  318. }
  319. }
  320. function setMessage() {
  321. if (map.message) {
  322. $messageElement.append(!options.escapeHtml ? map.message : escapeHtml(map.message)).addClass(options.messageClass);
  323. $toastElement.append($messageElement);
  324. }
  325. }
  326. function setCloseButton() {
  327. if (options.closeButton) {
  328. $closeElement.addClass('toast-close-button').attr('role', 'button');
  329. $toastElement.prepend($closeElement);
  330. }
  331. }
  332. function setProgressBar() {
  333. if (options.progressBar) {
  334. $progressElement.addClass('toast-progress');
  335. $toastElement.prepend($progressElement);
  336. }
  337. }
  338. function shouldExit(options, map) {
  339. if (options.preventDuplicates) {
  340. if (map.message === previousToast) {
  341. return true;
  342. } else {
  343. previousToast = map.message;
  344. }
  345. }
  346. return false;
  347. }
  348. function hideToast(override) {
  349. var method = override && options.closeMethod !== false ? options.closeMethod : options.hideMethod;
  350. var duration = override && options.closeDuration !== false ?
  351. options.closeDuration : options.hideDuration;
  352. var easing = override && options.closeEasing !== false ? options.closeEasing : options.hideEasing;
  353. if ($(':focus', $toastElement).length && !override) {
  354. return;
  355. }
  356. clearTimeout(progressBar.intervalId);
  357. return $toastElement[method]({
  358. duration: duration,
  359. easing: easing,
  360. complete: function () {
  361. removeToast($toastElement);
  362. if (options.onHidden && response.state !== 'hidden') {
  363. options.onHidden();
  364. }
  365. response.state = 'hidden';
  366. response.endTime = new Date();
  367. publish(response);
  368. }
  369. });
  370. }
  371. function delayedHideToast() {
  372. if (options.timeOut > 0 || options.extendedTimeOut > 0) {
  373. intervalId = setTimeout(hideToast, options.extendedTimeOut);
  374. progressBar.maxHideTime = parseFloat(options.extendedTimeOut);
  375. progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;
  376. }
  377. }
  378. function stickAround() {
  379. clearTimeout(intervalId);
  380. progressBar.hideEta = 0;
  381. $toastElement.stop(true, true)[options.showMethod](
  382. {duration: options.showDuration, easing: options.showEasing}
  383. );
  384. }
  385. function updateProgress() {
  386. var percentage = ((progressBar.hideEta - (new Date().getTime())) / progressBar.maxHideTime) * 100;
  387. $progressElement.width(percentage + '%');
  388. }
  389. }
  390. function getOptions() {
  391. return $.extend({}, getDefaults(), toastr.options);
  392. }
  393. function removeToast($toastElement) {
  394. if (!$container) {
  395. $container = getContainer();
  396. }
  397. if ($toastElement.is(':visible')) {
  398. return;
  399. }
  400. $toastElement.remove();
  401. $toastElement = null;
  402. if ($container.children().length === 0) {
  403. $container.remove();
  404. previousToast = undefined;
  405. }
  406. }
  407. })();
  408. });
  409. }(typeof define === 'function' && define.amd ? define : function (deps, factory) {
  410. if (typeof module !== 'undefined' && module.exports) { //Node
  411. module.exports = factory(require('jquery'));
  412. } else {
  413. window.toastr = factory(window.jQuery);
  414. }
  415. }));