You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

435 lines
16 KiB

  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. return toastr;
  40. ////////////////
  41. function error(message, title, optionsOverride) {
  42. return notify({
  43. type: toastType.error,
  44. iconClass: getOptions().iconClasses.error,
  45. message: message,
  46. optionsOverride: optionsOverride,
  47. title: title
  48. });
  49. }
  50. function getContainer(options, create) {
  51. if (!options) { options = getOptions(); }
  52. $container = $('#' + options.containerId);
  53. if ($container.length) {
  54. return $container;
  55. }
  56. if (create) {
  57. $container = createContainer(options);
  58. }
  59. return $container;
  60. }
  61. function info(message, title, optionsOverride) {
  62. return notify({
  63. type: toastType.info,
  64. iconClass: getOptions().iconClasses.info,
  65. message: message,
  66. optionsOverride: optionsOverride,
  67. title: title
  68. });
  69. }
  70. function subscribe(callback) {
  71. listener = callback;
  72. }
  73. function success(message, title, optionsOverride) {
  74. return notify({
  75. type: toastType.success,
  76. iconClass: getOptions().iconClasses.success,
  77. message: message,
  78. optionsOverride: optionsOverride,
  79. title: title
  80. });
  81. }
  82. function warning(message, title, optionsOverride) {
  83. return notify({
  84. type: toastType.warning,
  85. iconClass: getOptions().iconClasses.warning,
  86. message: message,
  87. optionsOverride: optionsOverride,
  88. title: title
  89. });
  90. }
  91. function clear($toastElement, clearOptions) {
  92. var options = getOptions();
  93. if (!$container) { getContainer(options); }
  94. if (!clearToast($toastElement, options, clearOptions)) {
  95. clearContainer(options);
  96. }
  97. }
  98. function remove($toastElement) {
  99. var options = getOptions();
  100. if (!$container) { getContainer(options); }
  101. if ($toastElement && $(':focus', $toastElement).length === 0) {
  102. removeToast($toastElement);
  103. return;
  104. }
  105. if ($container.children().length) {
  106. $container.remove();
  107. }
  108. }
  109. // internal functions
  110. function clearContainer (options) {
  111. var toastsToClear = $container.children();
  112. for (var i = toastsToClear.length - 1; i >= 0; i--) {
  113. clearToast($(toastsToClear[i]), options);
  114. }
  115. }
  116. function clearToast ($toastElement, options, clearOptions) {
  117. var force = clearOptions && clearOptions.force ? clearOptions.force : false;
  118. if ($toastElement && (force || $(':focus', $toastElement).length === 0)) {
  119. $toastElement[options.hideMethod]({
  120. duration: options.hideDuration,
  121. easing: options.hideEasing,
  122. complete: function () { removeToast($toastElement); }
  123. });
  124. return true;
  125. }
  126. return false;
  127. }
  128. function createContainer(options) {
  129. $container = $('<div/>')
  130. .attr('id', options.containerId)
  131. .addClass(options.positionClass)
  132. .attr('aria-live', 'polite')
  133. .attr('role', 'alert');
  134. $container.appendTo($(options.target));
  135. return $container;
  136. }
  137. function getDefaults() {
  138. return {
  139. tapToDismiss: true,
  140. toastClass: 'toast',
  141. containerId: 'toast-container',
  142. debug: false,
  143. showMethod: 'fadeIn', //fadeIn, slideDown, and show are built into jQuery
  144. showDuration: 300,
  145. showEasing: 'swing', //swing and linear are built into jQuery
  146. onShown: undefined,
  147. hideMethod: 'fadeOut',
  148. hideDuration: 1000,
  149. hideEasing: 'swing',
  150. onHidden: undefined,
  151. closeMethod: false,
  152. closeDuration: false,
  153. closeEasing: false,
  154. extendedTimeOut: 1000,
  155. iconClasses: {
  156. error: 'toast-error',
  157. info: 'toast-info',
  158. success: 'toast-success',
  159. warning: 'toast-warning'
  160. },
  161. iconClass: 'toast-info',
  162. positionClass: 'toast-top-right',
  163. timeOut: 5000, // Set timeOut and extendedTimeOut to 0 to make it sticky
  164. titleClass: 'toast-title',
  165. messageClass: 'toast-message',
  166. escapeHtml: false,
  167. target: 'body',
  168. closeHtml: '<button type="button">&times;</button>',
  169. newestOnTop: true,
  170. preventDuplicates: false,
  171. progressBar: false
  172. };
  173. }
  174. function publish(args) {
  175. if (!listener) { return; }
  176. listener(args);
  177. }
  178. function notify(map) {
  179. var options = getOptions();
  180. var iconClass = map.iconClass || options.iconClass;
  181. if (typeof (map.optionsOverride) !== 'undefined') {
  182. options = $.extend(options, map.optionsOverride);
  183. iconClass = map.optionsOverride.iconClass || iconClass;
  184. }
  185. if (shouldExit(options, map)) { return; }
  186. toastId++;
  187. $container = getContainer(options, true);
  188. var intervalId = null;
  189. var $toastElement = $('<div/>');
  190. var $titleElement = $('<div/>');
  191. var $messageElement = $('<div/>');
  192. var $progressElement = $('<div/>');
  193. var $closeElement = $(options.closeHtml);
  194. var progressBar = {
  195. intervalId: null,
  196. hideEta: null,
  197. maxHideTime: null
  198. };
  199. var response = {
  200. toastId: toastId,
  201. state: 'visible',
  202. startTime: new Date(),
  203. options: options,
  204. map: map
  205. };
  206. personalizeToast();
  207. displayToast();
  208. handleEvents();
  209. publish(response);
  210. if (options.debug && console) {
  211. console.log(response);
  212. }
  213. return $toastElement;
  214. function escapeHtml(source) {
  215. if (source == null)
  216. source = "";
  217. return new String(source)
  218. .replace(/&/g, '&amp;')
  219. .replace(/"/g, '&quot;')
  220. .replace(/'/g, '&#39;')
  221. .replace(/</g, '&lt;')
  222. .replace(/>/g, '&gt;');
  223. }
  224. function personalizeToast() {
  225. setIcon();
  226. setTitle();
  227. setMessage();
  228. setCloseButton();
  229. setProgressBar();
  230. setSequence();
  231. }
  232. function handleEvents() {
  233. $toastElement.hover(stickAround, delayedHideToast);
  234. if (!options.onclick && options.tapToDismiss) {
  235. $toastElement.click(hideToast);
  236. }
  237. if (options.closeButton && $closeElement) {
  238. $closeElement.click(function (event) {
  239. if (event.stopPropagation) {
  240. event.stopPropagation();
  241. } else if (event.cancelBubble !== undefined && event.cancelBubble !== true) {
  242. event.cancelBubble = true;
  243. }
  244. hideToast(true);
  245. });
  246. }
  247. if (options.onclick) {
  248. $toastElement.click(function (event) {
  249. options.onclick(event);
  250. hideToast();
  251. });
  252. }
  253. }
  254. function displayToast() {
  255. $toastElement.hide();
  256. $toastElement[options.showMethod](
  257. {duration: options.showDuration, easing: options.showEasing, complete: options.onShown}
  258. );
  259. if (options.timeOut > 0) {
  260. intervalId = setTimeout(hideToast, options.timeOut);
  261. progressBar.maxHideTime = parseFloat(options.timeOut);
  262. progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;
  263. if (options.progressBar) {
  264. progressBar.intervalId = setInterval(updateProgress, 10);
  265. }
  266. }
  267. }
  268. function setIcon() {
  269. if (map.iconClass) {
  270. $toastElement.addClass(options.toastClass).addClass(iconClass);
  271. }
  272. }
  273. function setSequence() {
  274. if (options.newestOnTop) {
  275. $container.prepend($toastElement);
  276. } else {
  277. $container.append($toastElement);
  278. }
  279. }
  280. function setTitle() {
  281. if (map.title) {
  282. $titleElement.append(!options.escapeHtml ? map.title : escapeHtml(map.title)).addClass(options.titleClass);
  283. $toastElement.append($titleElement);
  284. }
  285. }
  286. function setMessage() {
  287. if (map.message) {
  288. $messageElement.append(!options.escapeHtml ? map.message : escapeHtml(map.message)).addClass(options.messageClass);
  289. $toastElement.append($messageElement);
  290. }
  291. }
  292. function setCloseButton() {
  293. if (options.closeButton) {
  294. $closeElement.addClass('toast-close-button').attr('role', 'button');
  295. $toastElement.prepend($closeElement);
  296. }
  297. }
  298. function setProgressBar() {
  299. if (options.progressBar) {
  300. $progressElement.addClass('toast-progress');
  301. $toastElement.prepend($progressElement);
  302. }
  303. }
  304. function shouldExit(options, map) {
  305. if (options.preventDuplicates) {
  306. if (map.message === previousToast) {
  307. return true;
  308. } else {
  309. previousToast = map.message;
  310. }
  311. }
  312. return false;
  313. }
  314. function hideToast(override) {
  315. var method = override && options.closeMethod !== false ? options.closeMethod : options.hideMethod;
  316. var duration = override && options.closeDuration !== false ?
  317. options.closeDuration : options.hideDuration;
  318. var easing = override && options.closeEasing !== false ? options.closeEasing : options.hideEasing;
  319. if ($(':focus', $toastElement).length && !override) {
  320. return;
  321. }
  322. clearTimeout(progressBar.intervalId);
  323. return $toastElement[method]({
  324. duration: duration,
  325. easing: easing,
  326. complete: function () {
  327. removeToast($toastElement);
  328. if (options.onHidden && response.state !== 'hidden') {
  329. options.onHidden();
  330. }
  331. response.state = 'hidden';
  332. response.endTime = new Date();
  333. publish(response);
  334. }
  335. });
  336. }
  337. function delayedHideToast() {
  338. if (options.timeOut > 0 || options.extendedTimeOut > 0) {
  339. intervalId = setTimeout(hideToast, options.extendedTimeOut);
  340. progressBar.maxHideTime = parseFloat(options.extendedTimeOut);
  341. progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;
  342. }
  343. }
  344. function stickAround() {
  345. clearTimeout(intervalId);
  346. progressBar.hideEta = 0;
  347. $toastElement.stop(true, true)[options.showMethod](
  348. {duration: options.showDuration, easing: options.showEasing}
  349. );
  350. }
  351. function updateProgress() {
  352. var percentage = ((progressBar.hideEta - (new Date().getTime())) / progressBar.maxHideTime) * 100;
  353. $progressElement.width(percentage + '%');
  354. }
  355. }
  356. function getOptions() {
  357. return $.extend({}, getDefaults(), toastr.options);
  358. }
  359. function removeToast($toastElement) {
  360. if (!$container) { $container = getContainer(); }
  361. if ($toastElement.is(':visible')) {
  362. return;
  363. }
  364. $toastElement.remove();
  365. $toastElement = null;
  366. if ($container.children().length === 0) {
  367. $container.remove();
  368. previousToast = undefined;
  369. }
  370. }
  371. })();
  372. });
  373. }(typeof define === 'function' && define.amd ? define : function (deps, factory) {
  374. if (typeof module !== 'undefined' && module.exports) { //Node
  375. module.exports = factory(require('jquery'));
  376. } else {
  377. window.toastr = factory(window.jQuery);
  378. }
  379. }));