push.js 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028
  1. /**
  2. * Push v1.0
  3. * =========
  4. * A compact, cross-browser solution for the JavaScript Notifications API
  5. *
  6. * Credits
  7. * -------
  8. * Tsvetan Tsvetkov (ttsvetko)
  9. * Alex Gibson (alexgibson)
  10. *
  11. * License
  12. * -------
  13. *
  14. * The MIT License (MIT)
  15. *
  16. * Copyright (c) 2015-2017 Tyler Nickerson
  17. *
  18. * Permission is hereby granted, free of charge, to any person obtaining a copy
  19. * of this software and associated documentation files (the "Software"), to deal
  20. * in the Software without restriction, including without limitation the rights
  21. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  22. * copies of the Software, and to permit persons to whom the Software is
  23. * furnished to do so, subject to the following conditions:
  24. *
  25. * The above copyright notice and this permission notice shall be included in
  26. * all copies or substantial portions of the Software.
  27. *
  28. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  29. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  30. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  31. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  32. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  33. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  34. * THE SOFTWARE.
  35. */
  36. (function (global, factory) {
  37. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  38. typeof define === 'function' && define.amd ? define(factory) :
  39. (global.Push = factory());
  40. }(this, (function () { 'use strict';
  41. function _typeof(obj) {
  42. if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
  43. _typeof = function (obj) {
  44. return typeof obj;
  45. };
  46. } else {
  47. _typeof = function (obj) {
  48. return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
  49. };
  50. }
  51. return _typeof(obj);
  52. }
  53. function _classCallCheck(instance, Constructor) {
  54. if (!(instance instanceof Constructor)) {
  55. throw new TypeError("Cannot call a class as a function");
  56. }
  57. }
  58. function _defineProperties(target, props) {
  59. for (var i = 0; i < props.length; i++) {
  60. var descriptor = props[i];
  61. descriptor.enumerable = descriptor.enumerable || false;
  62. descriptor.configurable = true;
  63. if ("value" in descriptor) descriptor.writable = true;
  64. Object.defineProperty(target, descriptor.key, descriptor);
  65. }
  66. }
  67. function _createClass(Constructor, protoProps, staticProps) {
  68. if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  69. if (staticProps) _defineProperties(Constructor, staticProps);
  70. return Constructor;
  71. }
  72. function _inherits(subClass, superClass) {
  73. if (typeof superClass !== "function" && superClass !== null) {
  74. throw new TypeError("Super expression must either be null or a function");
  75. }
  76. subClass.prototype = Object.create(superClass && superClass.prototype, {
  77. constructor: {
  78. value: subClass,
  79. enumerable: false,
  80. writable: true,
  81. configurable: true
  82. }
  83. });
  84. if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
  85. }
  86. function _possibleConstructorReturn(self, call) {
  87. if (call && (typeof call === "object" || typeof call === "function")) {
  88. return call;
  89. }
  90. if (self === void 0) {
  91. throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  92. }
  93. return self;
  94. }
  95. var errorPrefix = 'PushError:';
  96. var Messages = {
  97. errors: {
  98. incompatible: "".concat(errorPrefix, " Push.js is incompatible with browser."),
  99. invalid_plugin: "".concat(errorPrefix, " plugin class missing from plugin manifest (invalid plugin). Please check the documentation."),
  100. invalid_title: "".concat(errorPrefix, " title of notification must be a string"),
  101. permission_denied: "".concat(errorPrefix, " permission request declined"),
  102. sw_notification_error: "".concat(errorPrefix, " could not show a ServiceWorker notification due to the following reason: "),
  103. sw_registration_error: "".concat(errorPrefix, " could not register the ServiceWorker due to the following reason: "),
  104. unknown_interface: "".concat(errorPrefix, " unable to create notification: unknown interface")
  105. }
  106. };
  107. var Permission =
  108. /*#__PURE__*/
  109. function () {
  110. // Private members
  111. // Public members
  112. function Permission(win) {
  113. _classCallCheck(this, Permission);
  114. this._win = win;
  115. this.GRANTED = 'granted';
  116. this.DEFAULT = 'default';
  117. this.DENIED = 'denied';
  118. this._permissions = [this.GRANTED, this.DEFAULT, this.DENIED];
  119. }
  120. /**
  121. * Requests permission for desktop notifications
  122. * @param {Function} onGranted - Function to execute once permission is granted
  123. * @param {Function} onDenied - Function to execute once permission is denied
  124. * @return {void, Promise}
  125. */
  126. _createClass(Permission, [{
  127. key: "request",
  128. value: function request(onGranted, onDenied) {
  129. return arguments.length > 0 ? this._requestWithCallback.apply(this, arguments) : this._requestAsPromise();
  130. }
  131. /**
  132. * Old permissions implementation deprecated in favor of a promise based one
  133. * @deprecated Since V1.0.4
  134. * @param {Function} onGranted - Function to execute once permission is granted
  135. * @param {Function} onDenied - Function to execute once permission is denied
  136. * @return {void}
  137. */
  138. }, {
  139. key: "_requestWithCallback",
  140. value: function _requestWithCallback(onGranted, onDenied) {
  141. var _this = this;
  142. var existing = this.get();
  143. var resolve = function resolve() {
  144. var result = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _this._win.Notification.permission;
  145. if (typeof result === 'undefined' && _this._win.webkitNotifications) result = _this._win.webkitNotifications.checkPermission();
  146. if (result === _this.GRANTED || result === 0) {
  147. if (onGranted) onGranted();
  148. } else if (onDenied) onDenied();
  149. };
  150. /* Permissions already set */
  151. if (existing !== this.DEFAULT) {
  152. resolve(existing);
  153. } else if (this._win.webkitNotifications && this._win.webkitNotifications.checkPermission) {
  154. /* Safari 6+, Legacy webkit browsers */
  155. this._win.webkitNotifications.requestPermission(resolve);
  156. } else if (this._win.Notification && this._win.Notification.requestPermission) {
  157. /* Chrome 23+ */
  158. this._win.Notification.requestPermission().then(resolve).catch(function () {
  159. if (onDenied) onDenied();
  160. });
  161. } else if (onGranted) {
  162. /* Let the user continue by default */
  163. onGranted();
  164. }
  165. }
  166. /**
  167. * Requests permission for desktop notifications in a promise based way
  168. * @return {Promise}
  169. */
  170. }, {
  171. key: "_requestAsPromise",
  172. value: function _requestAsPromise() {
  173. var _this2 = this;
  174. var existing = this.get();
  175. var isGranted = function isGranted(result) {
  176. return result === _this2.GRANTED || result === 0;
  177. };
  178. /* Permissions already set */
  179. var hasPermissions = existing !== this.DEFAULT;
  180. /* Safari 6+, Chrome 23+ */
  181. var isModernAPI = this._win.Notification && this._win.Notification.requestPermission;
  182. /* Legacy webkit browsers */
  183. var isWebkitAPI = this._win.webkitNotifications && this._win.webkitNotifications.checkPermission;
  184. return new Promise(function (resolvePromise, rejectPromise) {
  185. var resolver = function resolver(result) {
  186. return isGranted(result) ? resolvePromise() : rejectPromise();
  187. };
  188. if (hasPermissions) {
  189. resolver(existing);
  190. } else if (isWebkitAPI) {
  191. _this2._win.webkitNotifications.requestPermission(function (result) {
  192. resolver(result);
  193. });
  194. } else if (isModernAPI) {
  195. _this2._win.Notification.requestPermission().then(function (result) {
  196. resolver(result);
  197. }).catch(rejectPromise);
  198. } else resolvePromise();
  199. });
  200. }
  201. /**
  202. * Returns whether Push has been granted permission to run
  203. * @return {Boolean}
  204. */
  205. }, {
  206. key: "has",
  207. value: function has() {
  208. return this.get() === this.GRANTED;
  209. }
  210. /**
  211. * Gets the permission level
  212. * @return {Permission} The permission level
  213. */
  214. }, {
  215. key: "get",
  216. value: function get() {
  217. var permission;
  218. /* Safari 6+, Chrome 23+ */
  219. if (this._win.Notification && this._win.Notification.permission) permission = this._win.Notification.permission;else if (this._win.webkitNotifications && this._win.webkitNotifications.checkPermission)
  220. /* Legacy webkit browsers */
  221. permission = this._permissions[this._win.webkitNotifications.checkPermission()];else if (navigator.mozNotification)
  222. /* Firefox Mobile */
  223. permission = this.GRANTED;else if (this._win.external && this._win.external.msIsSiteMode)
  224. /* IE9+ */
  225. permission = this._win.external.msIsSiteMode() ? this.GRANTED : this.DEFAULT;else permission = this.GRANTED;
  226. return permission;
  227. }
  228. }]);
  229. return Permission;
  230. }();
  231. var Util =
  232. /*#__PURE__*/
  233. function () {
  234. function Util() {
  235. _classCallCheck(this, Util);
  236. }
  237. _createClass(Util, null, [{
  238. key: "isUndefined",
  239. value: function isUndefined(obj) {
  240. return obj === undefined;
  241. }
  242. }, {
  243. key: "isNull",
  244. value: function isNull(obs) {
  245. return obj === null;
  246. }
  247. }, {
  248. key: "isString",
  249. value: function isString(obj) {
  250. return typeof obj === 'string';
  251. }
  252. }, {
  253. key: "isFunction",
  254. value: function isFunction(obj) {
  255. return obj && {}.toString.call(obj) === '[object Function]';
  256. }
  257. }, {
  258. key: "isObject",
  259. value: function isObject(obj) {
  260. return _typeof(obj) === 'object';
  261. }
  262. }, {
  263. key: "objectMerge",
  264. value: function objectMerge(target, source) {
  265. for (var key in source) {
  266. if (target.hasOwnProperty(key) && this.isObject(target[key]) && this.isObject(source[key])) {
  267. this.objectMerge(target[key], source[key]);
  268. } else {
  269. target[key] = source[key];
  270. }
  271. }
  272. }
  273. }]);
  274. return Util;
  275. }();
  276. var AbstractAgent = function AbstractAgent(win) {
  277. _classCallCheck(this, AbstractAgent);
  278. this._win = win;
  279. };
  280. /**
  281. * Notification agent for modern desktop browsers:
  282. * Safari 6+, Firefox 22+, Chrome 22+, Opera 25+
  283. */
  284. var DesktopAgent$$1 =
  285. /*#__PURE__*/
  286. function (_AbstractAgent) {
  287. _inherits(DesktopAgent$$1, _AbstractAgent);
  288. function DesktopAgent$$1() {
  289. _classCallCheck(this, DesktopAgent$$1);
  290. return _possibleConstructorReturn(this, (DesktopAgent$$1.__proto__ || Object.getPrototypeOf(DesktopAgent$$1)).apply(this, arguments));
  291. }
  292. _createClass(DesktopAgent$$1, [{
  293. key: "isSupported",
  294. /**
  295. * Returns a boolean denoting support
  296. * @returns {Boolean} boolean denoting whether webkit notifications are supported
  297. */
  298. value: function isSupported() {
  299. return this._win.Notification !== undefined;
  300. }
  301. /**
  302. * Creates a new notification
  303. * @param title - notification title
  304. * @param options - notification options array
  305. * @returns {Notification}
  306. */
  307. }, {
  308. key: "create",
  309. value: function create(title, options) {
  310. return new this._win.Notification(title, {
  311. icon: Util.isString(options.icon) || Util.isUndefined(options.icon) || Util.isNull(options.icon) ? options.icon : options.icon.x32,
  312. body: options.body,
  313. tag: options.tag,
  314. requireInteraction: options.requireInteraction
  315. });
  316. }
  317. /**
  318. * Close a given notification
  319. * @param notification - notification to close
  320. */
  321. }, {
  322. key: "close",
  323. value: function close(notification) {
  324. notification.close();
  325. }
  326. }]);
  327. return DesktopAgent$$1;
  328. }(AbstractAgent);
  329. /**
  330. * Notification agent for modern desktop browsers:
  331. * Safari 6+, Firefox 22+, Chrome 22+, Opera 25+
  332. */
  333. var MobileChromeAgent$$1 =
  334. /*#__PURE__*/
  335. function (_AbstractAgent) {
  336. _inherits(MobileChromeAgent$$1, _AbstractAgent);
  337. function MobileChromeAgent$$1() {
  338. _classCallCheck(this, MobileChromeAgent$$1);
  339. return _possibleConstructorReturn(this, (MobileChromeAgent$$1.__proto__ || Object.getPrototypeOf(MobileChromeAgent$$1)).apply(this, arguments));
  340. }
  341. _createClass(MobileChromeAgent$$1, [{
  342. key: "isSupported",
  343. /**
  344. * Returns a boolean denoting support
  345. * @returns {Boolean} boolean denoting whether webkit notifications are supported
  346. */
  347. value: function isSupported() {
  348. return this._win.navigator !== undefined && this._win.navigator.serviceWorker !== undefined;
  349. }
  350. /**
  351. * Returns the function body as a string
  352. * @param func
  353. */
  354. }, {
  355. key: "getFunctionBody",
  356. value: function getFunctionBody(func) {
  357. var str = func.toString().match(/function[^{]+{([\s\S]*)}$/);
  358. return typeof str !== 'undefined' && str !== null && str.length > 1 ? str[1] : null;
  359. }
  360. /**
  361. * Creates a new notification
  362. * @param id ID of notification
  363. * @param title Title of notification
  364. * @param options Options object
  365. * @param serviceWorker ServiceWorker path
  366. * @param callback Callback function
  367. */
  368. }, {
  369. key: "create",
  370. value: function create(id, title, options, serviceWorker, callback) {
  371. var _this = this;
  372. /* Register ServiceWorker */
  373. this._win.navigator.serviceWorker.register(serviceWorker);
  374. this._win.navigator.serviceWorker.ready.then(function (registration) {
  375. /* Local data the service worker will use */
  376. var localData = {
  377. id: id,
  378. link: options.link,
  379. origin: document.location.href,
  380. onClick: Util.isFunction(options.onClick) ? _this.getFunctionBody(options.onClick) : '',
  381. onClose: Util.isFunction(options.onClose) ? _this.getFunctionBody(options.onClose) : ''
  382. };
  383. /* Merge the local data with user-provided data */
  384. if (options.data !== undefined && options.data !== null) localData = Object.assign(localData, options.data);
  385. /* Show the notification */
  386. registration.showNotification(title, {
  387. icon: options.icon,
  388. body: options.body,
  389. vibrate: options.vibrate,
  390. tag: options.tag,
  391. data: localData,
  392. requireInteraction: options.requireInteraction,
  393. silent: options.silent
  394. }).then(function () {
  395. registration.getNotifications().then(function (notifications) {
  396. /* Send an empty message so the ServiceWorker knows who the client is */
  397. registration.active.postMessage('');
  398. /* Trigger callback */
  399. callback(notifications);
  400. });
  401. }).catch(function (error) {
  402. throw new Error(Messages.errors.sw_notification_error + error.message);
  403. });
  404. }).catch(function (error) {
  405. throw new Error(Messages.errors.sw_registration_error + error.message);
  406. });
  407. }
  408. /**
  409. * Close all notification
  410. */
  411. }, {
  412. key: "close",
  413. value: function close() {// Can't do this with service workers
  414. }
  415. }]);
  416. return MobileChromeAgent$$1;
  417. }(AbstractAgent);
  418. /**
  419. * Notification agent for modern desktop browsers:
  420. * Safari 6+, Firefox 22+, Chrome 22+, Opera 25+
  421. */
  422. var MobileFirefoxAgent$$1 =
  423. /*#__PURE__*/
  424. function (_AbstractAgent) {
  425. _inherits(MobileFirefoxAgent$$1, _AbstractAgent);
  426. function MobileFirefoxAgent$$1() {
  427. _classCallCheck(this, MobileFirefoxAgent$$1);
  428. return _possibleConstructorReturn(this, (MobileFirefoxAgent$$1.__proto__ || Object.getPrototypeOf(MobileFirefoxAgent$$1)).apply(this, arguments));
  429. }
  430. _createClass(MobileFirefoxAgent$$1, [{
  431. key: "isSupported",
  432. /**
  433. * Returns a boolean denoting support
  434. * @returns {Boolean} boolean denoting whether webkit notifications are supported
  435. */
  436. value: function isSupported() {
  437. return this._win.navigator.mozNotification !== undefined;
  438. }
  439. /**
  440. * Creates a new notification
  441. * @param title - notification title
  442. * @param options - notification options array
  443. * @returns {Notification}
  444. */
  445. }, {
  446. key: "create",
  447. value: function create(title, options) {
  448. var notification = this._win.navigator.mozNotification.createNotification(title, options.body, options.icon);
  449. notification.show();
  450. return notification;
  451. }
  452. }]);
  453. return MobileFirefoxAgent$$1;
  454. }(AbstractAgent);
  455. /**
  456. * Notification agent for IE9
  457. */
  458. var MSAgent$$1 =
  459. /*#__PURE__*/
  460. function (_AbstractAgent) {
  461. _inherits(MSAgent$$1, _AbstractAgent);
  462. function MSAgent$$1() {
  463. _classCallCheck(this, MSAgent$$1);
  464. return _possibleConstructorReturn(this, (MSAgent$$1.__proto__ || Object.getPrototypeOf(MSAgent$$1)).apply(this, arguments));
  465. }
  466. _createClass(MSAgent$$1, [{
  467. key: "isSupported",
  468. /**
  469. * Returns a boolean denoting support
  470. * @returns {Boolean} boolean denoting whether webkit notifications are supported
  471. */
  472. value: function isSupported() {
  473. return this._win.external !== undefined && this._win.external.msIsSiteMode !== undefined;
  474. }
  475. /**
  476. * Creates a new notification
  477. * @param title - notification title
  478. * @param options - notification options array
  479. * @returns {Notification}
  480. */
  481. }, {
  482. key: "create",
  483. value: function create(title, options) {
  484. /* Clear any previous notifications */
  485. this._win.external.msSiteModeClearIconOverlay();
  486. this._win.external.msSiteModeSetIconOverlay(Util.isString(options.icon) || Util.isUndefined(options.icon) ? options.icon : options.icon.x16, title);
  487. this._win.external.msSiteModeActivate();
  488. return null;
  489. }
  490. /**
  491. * Close a given notification
  492. * @param notification - notification to close
  493. */
  494. }, {
  495. key: "close",
  496. value: function close() {
  497. this._win.external.msSiteModeClearIconOverlay();
  498. }
  499. }]);
  500. return MSAgent$$1;
  501. }(AbstractAgent);
  502. /**
  503. * Notification agent for old Chrome versions (and some) Firefox
  504. */
  505. var WebKitAgent$$1 =
  506. /*#__PURE__*/
  507. function (_AbstractAgent) {
  508. _inherits(WebKitAgent$$1, _AbstractAgent);
  509. function WebKitAgent$$1() {
  510. _classCallCheck(this, WebKitAgent$$1);
  511. return _possibleConstructorReturn(this, (WebKitAgent$$1.__proto__ || Object.getPrototypeOf(WebKitAgent$$1)).apply(this, arguments));
  512. }
  513. _createClass(WebKitAgent$$1, [{
  514. key: "isSupported",
  515. /**
  516. * Returns a boolean denoting support
  517. * @returns {Boolean} boolean denoting whether webkit notifications are supported
  518. */
  519. value: function isSupported() {
  520. return this._win.webkitNotifications !== undefined;
  521. }
  522. /**
  523. * Creates a new notification
  524. * @param title - notification title
  525. * @param options - notification options array
  526. * @returns {Notification}
  527. */
  528. }, {
  529. key: "create",
  530. value: function create(title, options) {
  531. var notification = this._win.webkitNotifications.createNotification(options.icon, title, options.body);
  532. notification.show();
  533. return notification;
  534. }
  535. /**
  536. * Close a given notification
  537. * @param notification - notification to close
  538. */
  539. }, {
  540. key: "close",
  541. value: function close(notification) {
  542. notification.cancel();
  543. }
  544. }]);
  545. return WebKitAgent$$1;
  546. }(AbstractAgent);
  547. var Push$$1 =
  548. /*#__PURE__*/
  549. function () {
  550. // Private members
  551. // Public members
  552. function Push$$1(win) {
  553. _classCallCheck(this, Push$$1);
  554. /* Private variables */
  555. /* ID to use for new notifications */
  556. this._currentId = 0;
  557. /* Map of open notifications */
  558. this._notifications = {};
  559. /* Window object */
  560. this._win = win;
  561. /* Public variables */
  562. this.Permission = new Permission(win);
  563. /* Agents */
  564. this._agents = {
  565. desktop: new DesktopAgent$$1(win),
  566. chrome: new MobileChromeAgent$$1(win),
  567. firefox: new MobileFirefoxAgent$$1(win),
  568. ms: new MSAgent$$1(win),
  569. webkit: new WebKitAgent$$1(win)
  570. };
  571. this._configuration = {
  572. serviceWorker: '/serviceWorker.min.js',
  573. fallback: function fallback(payload) {}
  574. };
  575. }
  576. /**
  577. * Closes a notification
  578. * @param id ID of notification
  579. * @returns {boolean} denotes whether the operation was successful
  580. * @private
  581. */
  582. _createClass(Push$$1, [{
  583. key: "_closeNotification",
  584. value: function _closeNotification(id) {
  585. var success = true;
  586. var notification = this._notifications[id];
  587. if (notification !== undefined) {
  588. success = this._removeNotification(id);
  589. /* Safari 6+, Firefox 22+, Chrome 22+, Opera 25+ */
  590. if (this._agents.desktop.isSupported()) this._agents.desktop.close(notification);else if (this._agents.webkit.isSupported())
  591. /* Legacy WebKit browsers */
  592. this._agents.webkit.close(notification);else if (this._agents.ms.isSupported())
  593. /* IE9 */
  594. this._agents.ms.close();else {
  595. success = false;
  596. throw new Error(Messages.errors.unknown_interface);
  597. }
  598. return success;
  599. }
  600. return false;
  601. }
  602. /**
  603. * Adds a notification to the global dictionary of notifications
  604. * @param {Notification} notification
  605. * @return {Integer} Dictionary key of the notification
  606. * @private
  607. */
  608. }, {
  609. key: "_addNotification",
  610. value: function _addNotification(notification) {
  611. var id = this._currentId;
  612. this._notifications[id] = notification;
  613. this._currentId++;
  614. return id;
  615. }
  616. /**
  617. * Removes a notification with the given ID
  618. * @param {Integer} id - Dictionary key/ID of the notification to remove
  619. * @return {Boolean} boolean denoting success
  620. * @private
  621. */
  622. }, {
  623. key: "_removeNotification",
  624. value: function _removeNotification(id) {
  625. var success = false;
  626. if (this._notifications.hasOwnProperty(id)) {
  627. /* We're successful if we omit the given ID from the new array */
  628. delete this._notifications[id];
  629. success = true;
  630. }
  631. return success;
  632. }
  633. /**
  634. * Creates the wrapper for a given notification
  635. *
  636. * @param {Integer} id - Dictionary key/ID of the notification
  637. * @param {Map} options - Options used to create the notification
  638. * @returns {Map} wrapper hashmap object
  639. * @private
  640. */
  641. }, {
  642. key: "_prepareNotification",
  643. value: function _prepareNotification(id, options) {
  644. var _this = this;
  645. var wrapper;
  646. /* Wrapper used to get/close notification later on */
  647. wrapper = {
  648. get: function get() {
  649. return _this._notifications[id];
  650. },
  651. close: function close() {
  652. _this._closeNotification(id);
  653. }
  654. };
  655. /* Autoclose timeout */
  656. if (options.timeout) {
  657. setTimeout(function () {
  658. wrapper.close();
  659. }, options.timeout);
  660. }
  661. return wrapper;
  662. }
  663. /**
  664. * Find the most recent notification from a ServiceWorker and add it to the global array
  665. * @param notifications
  666. * @private
  667. */
  668. }, {
  669. key: "_serviceWorkerCallback",
  670. value: function _serviceWorkerCallback(notifications, options, resolve) {
  671. var _this2 = this;
  672. var id = this._addNotification(notifications[notifications.length - 1]);
  673. /* Listen for close requests from the ServiceWorker */
  674. if (navigator && navigator.serviceWorker) {
  675. navigator.serviceWorker.addEventListener('message', function (event) {
  676. var data = JSON.parse(event.data);
  677. if (data.action === 'close' && Number.isInteger(data.id)) _this2._removeNotification(data.id);
  678. });
  679. resolve(this._prepareNotification(id, options));
  680. }
  681. resolve(null);
  682. }
  683. /**
  684. * Callback function for the 'create' method
  685. * @return {void}
  686. * @private
  687. */
  688. }, {
  689. key: "_createCallback",
  690. value: function _createCallback(title, options, resolve) {
  691. var _this3 = this;
  692. var notification = null;
  693. var onClose;
  694. /* Set empty settings if none are specified */
  695. options = options || {};
  696. /* onClose event handler */
  697. onClose = function onClose(id) {
  698. /* A bit redundant, but covers the cases when close() isn't explicitly called */
  699. _this3._removeNotification(id);
  700. if (Util.isFunction(options.onClose)) {
  701. options.onClose.call(_this3, notification);
  702. }
  703. };
  704. /* Safari 6+, Firefox 22+, Chrome 22+, Opera 25+ */
  705. if (this._agents.desktop.isSupported()) {
  706. try {
  707. /* Create a notification using the API if possible */
  708. notification = this._agents.desktop.create(title, options);
  709. } catch (e) {
  710. var id = this._currentId;
  711. var sw = this.config().serviceWorker;
  712. var cb = function cb(notifications) {
  713. return _this3._serviceWorkerCallback(notifications, options, resolve);
  714. };
  715. /* Create a Chrome ServiceWorker notification if it isn't supported */
  716. if (this._agents.chrome.isSupported()) {
  717. this._agents.chrome.create(id, title, options, sw, cb);
  718. }
  719. }
  720. /* Legacy WebKit browsers */
  721. } else if (this._agents.webkit.isSupported()) notification = this._agents.webkit.create(title, options);else if (this._agents.firefox.isSupported())
  722. /* Firefox Mobile */
  723. this._agents.firefox.create(title, options);else if (this._agents.ms.isSupported())
  724. /* IE9 */
  725. notification = this._agents.ms.create(title, options);else {
  726. /* Default fallback */
  727. options.title = title;
  728. this.config().fallback(options);
  729. }
  730. if (notification !== null) {
  731. var _id = this._addNotification(notification);
  732. var wrapper = this._prepareNotification(_id, options);
  733. /* Notification callbacks */
  734. if (Util.isFunction(options.onShow)) notification.addEventListener('show', options.onShow);
  735. if (Util.isFunction(options.onError)) notification.addEventListener('error', options.onError);
  736. if (Util.isFunction(options.onClick)) notification.addEventListener('click', options.onClick);
  737. notification.addEventListener('close', function () {
  738. onClose(_id);
  739. });
  740. notification.addEventListener('cancel', function () {
  741. onClose(_id);
  742. });
  743. /* Return the wrapper so the user can call close() */
  744. resolve(wrapper);
  745. }
  746. /* By default, pass an empty wrapper */
  747. resolve(null);
  748. }
  749. /**
  750. * Creates and displays a new notification
  751. * @param {Array} options
  752. * @return {Promise}
  753. */
  754. }, {
  755. key: "create",
  756. value: function create(title, options) {
  757. var _this4 = this;
  758. var promiseCallback;
  759. /* Fail if no or an invalid title is provided */
  760. if (!Util.isString(title)) {
  761. throw new Error(Messages.errors.invalid_title);
  762. }
  763. /* Request permission if it isn't granted */
  764. if (!this.Permission.has()) {
  765. promiseCallback = function promiseCallback(resolve, reject) {
  766. _this4.Permission.request().then(function () {
  767. _this4._createCallback(title, options, resolve);
  768. }).catch(function () {
  769. reject(Messages.errors.permission_denied);
  770. });
  771. };
  772. } else {
  773. promiseCallback = function promiseCallback(resolve, reject) {
  774. try {
  775. _this4._createCallback(title, options, resolve);
  776. } catch (e) {
  777. reject(e);
  778. }
  779. };
  780. }
  781. return new Promise(promiseCallback);
  782. }
  783. /**
  784. * Returns the notification count
  785. * @return {Integer} The notification count
  786. */
  787. }, {
  788. key: "count",
  789. value: function count() {
  790. var count = 0;
  791. var key;
  792. for (key in this._notifications) {
  793. if (this._notifications.hasOwnProperty(key)) count++;
  794. }
  795. return count;
  796. }
  797. /**
  798. * Closes a notification with the given tag
  799. * @param {String} tag - Tag of the notification to close
  800. * @return {Boolean} boolean denoting success
  801. */
  802. }, {
  803. key: "close",
  804. value: function close(tag) {
  805. var key, notification;
  806. for (key in this._notifications) {
  807. if (this._notifications.hasOwnProperty(key)) {
  808. notification = this._notifications[key];
  809. /* Run only if the tags match */
  810. if (notification.tag === tag) {
  811. /* Call the notification's close() method */
  812. return this._closeNotification(key);
  813. }
  814. }
  815. }
  816. }
  817. /**
  818. * Clears all notifications
  819. * @return {Boolean} boolean denoting whether the clear was successful in closing all notifications
  820. */
  821. }, {
  822. key: "clear",
  823. value: function clear() {
  824. var key,
  825. success = true;
  826. for (key in this._notifications) {
  827. if (this._notifications.hasOwnProperty(key)) success = success && this._closeNotification(key);
  828. }
  829. return success;
  830. }
  831. /**
  832. * Denotes whether Push is supported in the current browser
  833. * @returns {boolean}
  834. */
  835. }, {
  836. key: "supported",
  837. value: function supported() {
  838. var supported = false;
  839. for (var agent in this._agents) {
  840. if (this._agents.hasOwnProperty(agent)) supported = supported || this._agents[agent].isSupported();
  841. }
  842. return supported;
  843. }
  844. /**
  845. * Modifies settings or returns all settings if no parameter passed
  846. * @param settings
  847. */
  848. }, {
  849. key: "config",
  850. value: function config(settings) {
  851. if (typeof settings !== 'undefined' || settings !== null && Util.isObject(settings)) Util.objectMerge(this._configuration, settings);
  852. return this._configuration;
  853. }
  854. /**
  855. * Copies the functions from a plugin to the main library
  856. * @param plugin
  857. */
  858. }, {
  859. key: "extend",
  860. value: function extend(manifest) {
  861. var plugin,
  862. Plugin,
  863. hasProp = {}.hasOwnProperty;
  864. if (!hasProp.call(manifest, 'plugin')) {
  865. throw new Error(Messages.errors.invalid_plugin);
  866. } else {
  867. if (hasProp.call(manifest, 'config') && Util.isObject(manifest.config) && manifest.config !== null) {
  868. this.config(manifest.config);
  869. }
  870. Plugin = manifest.plugin;
  871. plugin = new Plugin(this.config());
  872. for (var member in plugin) {
  873. if (hasProp.call(plugin, member) && Util.isFunction(plugin[member])) // $FlowFixMe
  874. this[member] = plugin[member];
  875. }
  876. }
  877. }
  878. }]);
  879. return Push$$1;
  880. }();
  881. var index = new Push$$1(typeof window !== 'undefined' ? window : global);
  882. return index;
  883. })));
  884. //# sourceMappingURL=push.js.map