local-notification.js 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  1. /*
  2. * Apache 2.0 License
  3. *
  4. * Copyright (c) Sebastian Katzer 2017
  5. *
  6. * This file contains Original Code and/or Modifications of Original Code
  7. * as defined in and that are subject to the Apache License
  8. * Version 2.0 (the 'License'). You may not use this file except in
  9. * compliance with the License. Please obtain a copy of the License at
  10. * http://opensource.org/licenses/Apache-2.0/ and read it before using this
  11. * file.
  12. *
  13. * The Original Code and all software distributed under the License are
  14. * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  15. * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  16. * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  18. * Please see the License for the specific language governing rights and
  19. * limitations under the License.
  20. */
  21. var exec = require('cordova/exec'),
  22. channel = require('cordova/channel');
  23. // Defaults
  24. exports._defaults = {
  25. actionGroupId : null,
  26. actions : [],
  27. attachments : [],
  28. autoClear : true,
  29. badge : null,
  30. channel : null,
  31. clock : true,
  32. color : null,
  33. data : null,
  34. defaults : 0,
  35. foreground : null,
  36. group : null,
  37. groupSummary : false,
  38. icon : null,
  39. id : 0,
  40. launch : true,
  41. led : true,
  42. lockscreen : true,
  43. mediaSession : null,
  44. number : 0,
  45. priority : 0,
  46. progressBar : false,
  47. silent : false,
  48. smallIcon : 'res://icon',
  49. sound : true,
  50. sticky : false,
  51. summary : null,
  52. text : '',
  53. timeoutAfter : false,
  54. title : '',
  55. trigger : { type : 'calendar' },
  56. vibrate : false,
  57. wakeup : true
  58. };
  59. // Event listener
  60. exports._listener = {};
  61. /**
  62. * Check permission to show notifications.
  63. *
  64. * @param [ Function ] callback The function to be exec as the callback.
  65. * @param [ Object ] scope The callback function's scope.
  66. *
  67. * @return [ Void ]
  68. */
  69. exports.hasPermission = function (callback, scope) {
  70. this._exec('check', null, callback, scope);
  71. };
  72. /**
  73. * Request permission to show notifications.
  74. *
  75. * @param [ Function ] callback The function to be exec as the callback.
  76. * @param [ Object ] scope The callback function's scope.
  77. *
  78. * @return [ Void ]
  79. */
  80. exports.requestPermission = function (callback, scope) {
  81. this._exec('request', null, callback, scope);
  82. };
  83. /**
  84. * Schedule notifications.
  85. *
  86. * @param [ Array ] notifications The notifications to schedule.
  87. * @param [ Function ] callback The function to be exec as the callback.
  88. * @param [ Object ] scope The callback function's scope.
  89. * @param [ Object ] args Optional flags how to schedule.
  90. *
  91. * @return [ Void ]
  92. */
  93. exports.schedule = function (msgs, callback, scope, args) {
  94. var fn = function (granted) {
  95. var toasts = this._toArray(msgs);
  96. if (!granted && callback) {
  97. callback.call(scope || this, false);
  98. return;
  99. }
  100. for (var i = 0, len = toasts.length; i < len; i++) {
  101. var toast = toasts[i];
  102. this._mergeWithDefaults(toast);
  103. this._convertProperties(toast);
  104. }
  105. this._exec('schedule', toasts, callback, scope);
  106. };
  107. if (args && args.skipPermission) {
  108. fn.call(this, true);
  109. } else {
  110. this.requestPermission(fn, this);
  111. }
  112. };
  113. /**
  114. * Schedule notifications.
  115. *
  116. * @param [ Array ] notifications The notifications to schedule.
  117. * @param [ Function ] callback The function to be exec as the callback.
  118. * @param [ Object ] scope The callback function's scope.
  119. * @param [ Object ] args Optional flags how to schedule.
  120. *
  121. * @return [ Void ]
  122. */
  123. exports.update = function (msgs, callback, scope, args) {
  124. var fn = function(granted) {
  125. var toasts = this._toArray(msgs);
  126. if (!granted && callback) {
  127. callback.call(scope || this, false);
  128. return;
  129. }
  130. for (var i = 0, len = toasts.length; i < len; i++) {
  131. this._convertProperties(toasts[i]);
  132. }
  133. this._exec('update', toasts, callback, scope);
  134. };
  135. if (args && args.skipPermission) {
  136. fn.call(this, true);
  137. } else {
  138. this.requestPermission(fn, this);
  139. }
  140. };
  141. /**
  142. * Clear the specified notifications by id.
  143. *
  144. * @param [ Array<Int> ] ids The IDs of the notifications.
  145. * @param [ Function ] callback The function to be exec as the callback.
  146. * @param [ Object ] scope The callback function's scope.
  147. *
  148. * @return [ Void ]
  149. */
  150. exports.clear = function (ids, callback, scope) {
  151. ids = this._toArray(ids);
  152. ids = this._convertIds(ids);
  153. this._exec('clear', ids, callback, scope);
  154. };
  155. /**
  156. * Clear all triggered notifications.
  157. *
  158. * @param [ Function ] callback The function to be exec as the callback.
  159. * @param [ Object ] scope The callback function's scope.
  160. *
  161. * @return [ Void ]
  162. */
  163. exports.clearAll = function (callback, scope) {
  164. this._exec('clearAll', null, callback, scope);
  165. };
  166. /**
  167. * Clear the specified notifications by id.
  168. *
  169. * @param [ Array<Int> ] ids The IDs of the notifications.
  170. * @param [ Function ] callback The function to be exec as the callback.
  171. * @param [ Object ] scope The callback function's scope.
  172. *
  173. * @return [ Void ]
  174. */
  175. exports.cancel = function (ids, callback, scope) {
  176. ids = this._toArray(ids);
  177. ids = this._convertIds(ids);
  178. this._exec('cancel', ids, callback, scope);
  179. };
  180. /**
  181. * Cancel all scheduled notifications.
  182. *
  183. * @param [ Function ] callback The function to be exec as the callback.
  184. * @param [ Object ] scope The callback function's scope.
  185. *
  186. * @return [ Void ]
  187. */
  188. exports.cancelAll = function (callback, scope) {
  189. this._exec('cancelAll', null, callback, scope);
  190. };
  191. /**
  192. * Check if a notification is present.
  193. *
  194. * @param [ Int ] id The ID of the notification.
  195. * @param [ Function ] callback The function to be exec as the callback.
  196. * @param [ Object ] scope The callback function's scope.
  197. *
  198. * @return [ Void ]
  199. */
  200. exports.isPresent = function (id, callback, scope) {
  201. var fn = this._createCallbackFn(callback, scope);
  202. this.getType(id, function (type) {
  203. fn(type != 'unknown');
  204. });
  205. };
  206. /**
  207. * Check if a notification is scheduled.
  208. *
  209. * @param [ Int ] id The ID of the notification.
  210. * @param [ Function ] callback The function to be exec as the callback.
  211. * @param [ Object ] scope The callback function's scope.
  212. *
  213. * @return [ Void ]
  214. */
  215. exports.isScheduled = function (id, callback, scope) {
  216. this.hasType(id, 'scheduled', callback, scope);
  217. };
  218. /**
  219. * Check if a notification was triggered.
  220. *
  221. * @param [ Int ] id The ID of the notification.
  222. * @param [ Function ] callback The function to be exec as the callback.
  223. * @param [ Object ] scope The callback function's scope.
  224. *
  225. * @return [ Void ]
  226. */
  227. exports.isTriggered = function (id, callback, scope) {
  228. this.hasType(id, 'triggered', callback, scope);
  229. };
  230. /**
  231. * Check if a notification has a given type.
  232. *
  233. * @param [ Int ] id The ID of the notification.
  234. * @param [ String ] type The type of the notification.
  235. * @param [ Function ] callback The function to be exec as the callback.
  236. * @param [ Object ] scope The callback function's scope.
  237. *
  238. * @return [ Void ]
  239. */
  240. exports.hasType = function (id, type, callback, scope) {
  241. var fn = this._createCallbackFn(callback, scope);
  242. this.getType(id, function (type2) {
  243. fn(type == type2);
  244. });
  245. };
  246. /**
  247. * Get the type (triggered, scheduled) for the notification.
  248. *
  249. * @param [ Int ] id The ID of the notification.
  250. * @param [ Function ] callback The function to be exec as the callback.
  251. * @param [ Object ] scope The callback function's scope.
  252. *
  253. * @return [ Void ]
  254. */
  255. exports.getType = function (id, callback, scope) {
  256. this._exec('type', id, callback, scope);
  257. };
  258. /**
  259. * List of all notification ids.
  260. *
  261. * @param [ Function ] callback The function to be exec as the callback.
  262. * @param [ Object ] scope The callback function's scope.
  263. *
  264. * @return [ Void ]
  265. */
  266. exports.getIds = function (callback, scope) {
  267. this._exec('ids', null, callback, scope);
  268. };
  269. /**
  270. * List of all scheduled notification IDs.
  271. *
  272. * @param [ Function ] callback The function to be exec as the callback.
  273. * @param [ Object ] scope The callback function's scope.
  274. *
  275. * @return [ Void ]
  276. */
  277. exports.getScheduledIds = function (callback, scope) {
  278. this._exec('scheduledIds', null, callback, scope);
  279. };
  280. /**
  281. * List of all triggered notification IDs.
  282. *
  283. * @param [ Function ] callback The function to be exec as the callback.
  284. * @param [ Object ] scope The callback function's scope.
  285. *
  286. * @return [ Void ]
  287. */
  288. exports.getTriggeredIds = function (callback, scope) {
  289. this._exec('triggeredIds', null, callback, scope);
  290. };
  291. /**
  292. * List of local notifications specified by id.
  293. * If called without IDs, all notification will be returned.
  294. *
  295. * @param [ Array<Int> ] ids The IDs of the notifications.
  296. * @param [ Function ] callback The function to be exec as the callback.
  297. * @param [ Object ] scope The callback function's scope.
  298. *
  299. * @return [ Void ]
  300. */
  301. exports.get = function () {
  302. var args = Array.apply(null, arguments);
  303. if (typeof args[0] == 'function') {
  304. args.unshift([]);
  305. }
  306. var ids = args[0],
  307. callback = args[1],
  308. scope = args[2];
  309. if (!Array.isArray(ids)) {
  310. this._exec('notification', Number(ids), callback, scope);
  311. return;
  312. }
  313. ids = this._convertIds(ids);
  314. this._exec('notifications', ids, callback, scope);
  315. };
  316. /**
  317. * List for all notifications.
  318. *
  319. * @param [ Function ] callback The function to be exec as the callback.
  320. * @param [ Object ] scope The callback function's scope.
  321. *
  322. * @return [ Void ]
  323. */
  324. exports.getAll = function (callback, scope) {
  325. this._exec('notifications', null, callback, scope);
  326. };
  327. /**
  328. * List of all scheduled notifications.
  329. *
  330. * @param [ Function ] callback The function to be exec as the callback.
  331. * @param [ Object ] scope The callback function's scope.
  332. */
  333. exports.getScheduled = function (callback, scope) {
  334. this._exec('scheduledNotifications', null, callback, scope);
  335. };
  336. /**
  337. * List of all triggered notifications.
  338. *
  339. * @param [ Function ] callback The function to be exec as the callback.
  340. * @param [ Object ] scope The callback function's scope.
  341. */
  342. exports.getTriggered = function (callback, scope) {
  343. this._exec('triggeredNotifications', null, callback, scope);
  344. };
  345. /**
  346. * Register an group of actions by id.
  347. *
  348. * @param [ String ] id The Id of the group.
  349. * @param [ Array] actions The action config settings.
  350. * @param [ Function ] callback The function to be exec as the callback.
  351. * @param [ Object ] scope The callback function's scope.
  352. *
  353. * @return [ Void ]
  354. */
  355. exports.addActionGroup = function (id, actions, callback, scope) {
  356. var config = { actionGroupId: id, actions: actions };
  357. this._exec('actions', config, callback, scope);
  358. };
  359. /**
  360. * The (platform specific) default settings.
  361. *
  362. * @return [ Object ]
  363. */
  364. exports.getDefaults = function () {
  365. var map = Object.assign({}, this._defaults);
  366. for (var key in map) {
  367. if (Array.isArray(map[key])) {
  368. map[key] = Array.from(map[key]);
  369. } else
  370. if (Object.prototype.isPrototypeOf(map[key])) {
  371. map[key] = Object.assign({}, map[key]);
  372. }
  373. }
  374. return map;
  375. };
  376. /**
  377. * Overwrite default settings.
  378. *
  379. * @param [ Object ] newDefaults New default values.
  380. *
  381. * @return [ Void ]
  382. */
  383. exports.setDefaults = function (newDefaults) {
  384. Object.assign(this._defaults, newDefaults);
  385. };
  386. /**
  387. * Register callback for given event.
  388. *
  389. * @param [ String ] event The name of the event.
  390. * @param [ Function ] callback The function to be exec as callback.
  391. * @param [ Object ] scope The callback function's scope.
  392. *
  393. * @return [ Void ]
  394. */
  395. exports.on = function (event, callback, scope) {
  396. var type = typeof callback;
  397. if (type !== 'function' && type !== 'string')
  398. return;
  399. if (!this._listener[event]) {
  400. this._listener[event] = [];
  401. }
  402. var item = [callback, scope || window];
  403. this._listener[event].push(item);
  404. };
  405. /**
  406. * Unregister callback for given event.
  407. *
  408. * @param [ String ] event The name of the event.
  409. * @param [ Function ] callback The function to be exec as callback.
  410. *
  411. * @return [ Void ]
  412. */
  413. exports.un = function (event, callback) {
  414. var listener = this._listener[event];
  415. if (!listener)
  416. return;
  417. for (var i = 0; i < listener.length; i++) {
  418. var fn = listener[i][0];
  419. if (fn == callback) {
  420. listener.splice(i, 1);
  421. break;
  422. }
  423. }
  424. };
  425. /**
  426. * Fire the event with given arguments.
  427. *
  428. * @param [ String ] event The event's name.
  429. * @param [ *Array] args The callback's arguments.
  430. *
  431. * @return [ Void]
  432. */
  433. exports.fireEvent = function (event) {
  434. var args = Array.apply(null, arguments).slice(1),
  435. listener = this._listener[event];
  436. if (!listener)
  437. return;
  438. if (args[0] && typeof args[0].data === 'string') {
  439. args[0].data = JSON.parse(args[0].data);
  440. }
  441. for (var i = 0; i < listener.length; i++) {
  442. var fn = listener[i][0],
  443. scope = listener[i][1];
  444. if (typeof fn !== 'function') {
  445. fn = scope[fn];
  446. }
  447. fn.apply(scope, args);
  448. }
  449. };
  450. /**
  451. * Fire queued events once the device is ready and all listeners are registered.
  452. *
  453. * @return [ Void ]
  454. */
  455. exports.fireQueuedEvents = function() {
  456. exports._exec('ready');
  457. };
  458. /**
  459. * Merge custom properties with the default values.
  460. *
  461. * @param [ Object ] options Set of custom values.
  462. *
  463. * @retrun [ Object ]
  464. */
  465. exports._mergeWithDefaults = function (options) {
  466. var values = this.getDefaults();
  467. if (values.hasOwnProperty('sticky')) {
  468. options.sticky = this._getValueFor(options, 'sticky', 'ongoing');
  469. }
  470. if (options.sticky && options.autoClear !== true) {
  471. options.autoClear = false;
  472. }
  473. Object.assign(values, options);
  474. for (var key in values) {
  475. if (values[key] !== null) {
  476. options[key] = values[key];
  477. } else {
  478. delete options[key];
  479. }
  480. if (!this._defaults.hasOwnProperty(key)) {
  481. console.warn('Unknown property: ' + key);
  482. }
  483. }
  484. options.meta = {
  485. plugin: 'cordova-plugin-local-notification',
  486. version: '0.9-beta.3'
  487. };
  488. return options;
  489. };
  490. /**
  491. * Convert the passed values to their required type.
  492. *
  493. * @param [ Object ] options Properties to convert for.
  494. *
  495. * @return [ Object ] The converted property list
  496. */
  497. exports._convertProperties = function (options) {
  498. var parseToInt = function (prop, options) {
  499. if (isNaN(options[prop])) {
  500. console.warn(prop + ' is not a number: ' + options[prop]);
  501. return this._defaults[prop];
  502. } else {
  503. return Number(options[prop]);
  504. }
  505. };
  506. if (options.id) {
  507. options.id = parseToInt('id', options);
  508. }
  509. if (options.title) {
  510. options.title = options.title.toString();
  511. }
  512. if (options.badge) {
  513. options.badge = parseToInt('badge', options);
  514. }
  515. if (options.defaults) {
  516. options.defaults = parseToInt('defaults', options);
  517. }
  518. if (options.smallIcon && !options.smallIcon.match(/^res:/)) {
  519. console.warn('Property "smallIcon" must be of kind res://...');
  520. }
  521. if (typeof options.timeout === 'boolean') {
  522. options.timeout = options.timeout ? 3600000 : null;
  523. }
  524. if (options.timeout) {
  525. options.timeout = parseToInt('timeout', options);
  526. }
  527. options.data = JSON.stringify(options.data);
  528. this._convertPriority(options);
  529. this._convertTrigger(options);
  530. this._convertActions(options);
  531. this._convertProgressBar(options);
  532. return options;
  533. };
  534. /**
  535. * Convert the passed values for the priority to their required type.
  536. *
  537. * @param [ Map ] options Set of custom values.
  538. *
  539. * @return [ Map ] Interaction object with trigger spec.
  540. */
  541. exports._convertPriority = function (options) {
  542. var prio = options.priority || options.prio || 0;
  543. if (typeof prio === 'string') {
  544. prio = { min: -2, low: -1, high: 1, max: 2 }[prio] || 0;
  545. }
  546. if (options.foreground === true) {
  547. prio = Math.max(prio, 1);
  548. }
  549. if (options.foreground === false) {
  550. prio = Math.min(prio, 0);
  551. }
  552. options.priority = prio;
  553. return options;
  554. };
  555. /**
  556. * Convert the passed values to their required type, modifying them
  557. * directly for Android and passing the converted list back for iOS.
  558. *
  559. * @param [ Map ] options Set of custom values.
  560. *
  561. * @return [ Map ] Interaction object with category & actions.
  562. */
  563. exports._convertActions = function (options) {
  564. var actions = [];
  565. if (!options.actions)
  566. return null;
  567. for (var i = 0, len = options.actions.length; i < len; i++) {
  568. var action = options.actions[i];
  569. if (!action.id) {
  570. console.warn('Action with title ' + action.title + ' ' +
  571. 'has no id and will not be added.');
  572. continue;
  573. }
  574. action.id = action.id.toString();
  575. actions.push(action);
  576. }
  577. options.actions = actions;
  578. return options;
  579. };
  580. /**
  581. * Convert the passed values for the trigger to their required type.
  582. *
  583. * @param [ Map ] options Set of custom values.
  584. *
  585. * @return [ Map ] Interaction object with trigger spec.
  586. */
  587. exports._convertTrigger = function (options) {
  588. var trigger = options.trigger || {},
  589. date = this._getValueFor(trigger, 'at', 'firstAt', 'date');
  590. var dateToNum = function (date) {
  591. var num = typeof date == 'object' ? date.getTime() : date;
  592. return Math.round(num);
  593. };
  594. if (!options.trigger)
  595. return;
  596. if (!trigger.type) {
  597. trigger.type = trigger.center ? 'location' : 'calendar';
  598. }
  599. var isCal = trigger.type == 'calendar';
  600. if (isCal && !date) {
  601. date = this._getValueFor(options, 'at', 'firstAt', 'date');
  602. }
  603. if (isCal && !trigger.every && options.every) {
  604. trigger.every = options.every;
  605. }
  606. if (isCal && (trigger.in || trigger.every)) {
  607. date = null;
  608. }
  609. if (isCal && date) {
  610. trigger.at = dateToNum(date);
  611. }
  612. if (isCal && trigger.firstAt) {
  613. trigger.firstAt = dateToNum(trigger.firstAt);
  614. }
  615. if (isCal && trigger.before) {
  616. trigger.before = dateToNum(trigger.before);
  617. }
  618. if (isCal && trigger.after) {
  619. trigger.after = dateToNum(trigger.after);
  620. }
  621. if (!trigger.count && device.platform == 'windows') {
  622. trigger.count = trigger.every ? 5 : 1;
  623. }
  624. if (trigger.count && device.platform == 'iOS') {
  625. console.warn('trigger: { count: } is not supported on iOS.');
  626. }
  627. if (!isCal) {
  628. trigger.notifyOnEntry = !!trigger.notifyOnEntry;
  629. trigger.notifyOnExit = trigger.notifyOnExit === true;
  630. trigger.radius = trigger.radius || 5;
  631. trigger.single = !!trigger.single;
  632. }
  633. if (!isCal || trigger.at) {
  634. delete trigger.every;
  635. }
  636. delete options.every;
  637. delete options.at;
  638. delete options.firstAt;
  639. delete options.date;
  640. options.trigger = trigger;
  641. return options;
  642. };
  643. /**
  644. * Convert the passed values for the progressBar to their required type.
  645. *
  646. * @param [ Map ] options Set of custom values.
  647. *
  648. * @return [ Map ] Interaction object with trigger spec.
  649. */
  650. exports._convertProgressBar = function (options) {
  651. var isAndroid = device.platform == 'Android',
  652. cfg = options.progressBar;
  653. if (cfg === undefined)
  654. return;
  655. if (typeof cfg === 'boolean') {
  656. cfg = options.progressBar = { enabled: cfg };
  657. }
  658. if (typeof cfg.enabled !== 'boolean') {
  659. cfg.enabled = !!(cfg.value || cfg.maxValue || cfg.indeterminate !== null);
  660. }
  661. cfg.value = cfg.value || 0;
  662. if (isAndroid) {
  663. cfg.maxValue = cfg.maxValue || 100;
  664. cfg.indeterminate = !!cfg.indeterminate;
  665. }
  666. cfg.enabled = !!cfg.enabled;
  667. if (cfg.enabled && options.clock === true) {
  668. options.clock = 'chronometer';
  669. }
  670. return options;
  671. };
  672. /**
  673. * Create a callback function to get executed within a specific scope.
  674. *
  675. * @param [ Function ] fn The function to be exec as the callback.
  676. * @param [ Object ] scope The callback function's scope.
  677. *
  678. * @return [ Function ]
  679. */
  680. exports._createCallbackFn = function (fn, scope) {
  681. if (typeof fn != 'function')
  682. return;
  683. return function () {
  684. fn.apply(scope || this, arguments);
  685. };
  686. };
  687. /**
  688. * Convert the IDs to numbers.
  689. *
  690. * @param [ Array ] ids
  691. *
  692. * @return [ Array<Number> ]
  693. */
  694. exports._convertIds = function (ids) {
  695. var convertedIds = [];
  696. for (var i = 0, len = ids.length; i < len; i++) {
  697. convertedIds.push(Number(ids[i]));
  698. }
  699. return convertedIds;
  700. };
  701. /**
  702. * First found value for the given keys.
  703. *
  704. * @param [ Object ] options Object with key-value properties.
  705. * @param [ *Array<String> ] keys List of keys.
  706. *
  707. * @return [ Object ]
  708. */
  709. exports._getValueFor = function (options) {
  710. var keys = Array.apply(null, arguments).slice(1);
  711. for (var i = 0, key = keys[i], len = keys.length; i < len; key = keys[++i]) {
  712. if (options.hasOwnProperty(key)) {
  713. return options[key];
  714. }
  715. }
  716. return null;
  717. };
  718. /**
  719. * Convert a value to an array.
  720. *
  721. * @param [ Object ] obj Any kind of object.
  722. *
  723. * @return [ Array ] An array with the object as first item.
  724. */
  725. exports._toArray = function (obj) {
  726. return Array.isArray(obj) ? Array.from(obj) : [obj];
  727. };
  728. /**
  729. * Execute the native counterpart.
  730. *
  731. * @param [ String ] action The name of the action.
  732. * @param [ Array ] args Array of arguments.
  733. * @param [ Function] callback The callback function.
  734. * @param [ Object ] scope The scope for the function.
  735. *
  736. * @return [ Void ]
  737. */
  738. exports._exec = function (action, args, callback, scope) {
  739. var fn = this._createCallbackFn(callback, scope),
  740. params = [];
  741. if (Array.isArray(args)) {
  742. params = args;
  743. } else if (args) {
  744. params.push(args);
  745. }
  746. exec(fn, null, 'LocalNotification', action, params);
  747. };
  748. /**
  749. * Set the launch details if the app was launched by clicking on a toast.
  750. *
  751. * @return [ Void ]
  752. */
  753. exports._setLaunchDetails = function () {
  754. exports._exec('launch', null, function (details) {
  755. if (details) {
  756. exports.launchDetails = details;
  757. }
  758. });
  759. };
  760. // Polyfill for Object.assign
  761. if (typeof Object.assign != 'function') {
  762. Object.assign = function(target) {
  763. 'use strict';
  764. if (target == null) {
  765. throw new TypeError('Cannot convert undefined or null to object');
  766. }
  767. target = Object(target);
  768. for (var index = 1; index < arguments.length; index++) {
  769. var source = arguments[index];
  770. if (source != null) {
  771. for (var key in source) {
  772. if (Object.prototype.hasOwnProperty.call(source, key)) {
  773. target[key] = source[key];
  774. }
  775. }
  776. }
  777. }
  778. return target;
  779. };
  780. }
  781. // Polyfill for Array.from
  782. // Production steps of ECMA-262, Edition 6, 22.1.2.1
  783. // Reference: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.from
  784. if (!Array.from) {
  785. Array.from = (function () {
  786. var toStr = Object.prototype.toString;
  787. var isCallable = function (fn) {
  788. return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
  789. };
  790. var toInteger = function (value) {
  791. var number = Number(value);
  792. if (isNaN(number)) { return 0; }
  793. if (number === 0 || !isFinite(number)) { return number; }
  794. return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
  795. };
  796. var maxSafeInteger = Math.pow(2, 53) - 1;
  797. var toLength = function (value) {
  798. var len = toInteger(value);
  799. return Math.min(Math.max(len, 0), maxSafeInteger);
  800. };
  801. // The length property of the from method is 1.
  802. return function from(arrayLike/*, mapFn, thisArg */) {
  803. // 1. Let C be the this value.
  804. var C = this;
  805. // 2. Let items be ToObject(arrayLike).
  806. var items = Object(arrayLike);
  807. // 3. ReturnIfAbrupt(items).
  808. if (arrayLike == null) {
  809. throw new TypeError("Array.from requires an array-like object - not null or undefined");
  810. }
  811. // 4. If mapfn is undefined, then let mapping be false.
  812. var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
  813. var T;
  814. if (typeof mapFn !== 'undefined') {
  815. // 5. else
  816. // 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
  817. if (!isCallable(mapFn)) {
  818. throw new TypeError('Array.from: when provided, the second argument must be a function');
  819. }
  820. // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
  821. if (arguments.length > 2) {
  822. T = arguments[2];
  823. }
  824. }
  825. // 10. Let lenValue be Get(items, "length").
  826. // 11. Let len be ToLength(lenValue).
  827. var len = toLength(items.length);
  828. // 13. If IsConstructor(C) is true, then
  829. // 13. a. Let A be the result of calling the [[Construct]] internal method of C with an argument list containing the single item len.
  830. // 14. a. Else, Let A be ArrayCreate(len).
  831. var A = isCallable(C) ? Object(new C(len)) : new Array(len);
  832. // 16. Let k be 0.
  833. var k = 0;
  834. // 17. Repeat, while k < len… (also steps a - h)
  835. var kValue;
  836. while (k < len) {
  837. kValue = items[k];
  838. if (mapFn) {
  839. A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
  840. } else {
  841. A[k] = kValue;
  842. }
  843. k += 1;
  844. }
  845. // 18. Let putStatus be Put(A, "length", len, true).
  846. A.length = len;
  847. // 20. Return A.
  848. return A;
  849. };
  850. }());
  851. }
  852. // Called after 'deviceready' event
  853. channel.deviceready.subscribe(function () {
  854. if (!window.skipLocalNotificationReady) {
  855. exports.fireQueuedEvents();
  856. }
  857. });
  858. // Called before 'deviceready' event
  859. channel.onCordovaReady.subscribe(function () {
  860. channel.onCordovaInfoReady.subscribe(function () {
  861. exports._setLaunchDetails();
  862. });
  863. });