local-notification.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  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 : false,
  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. timeout : 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.2'
  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.priority) {
  516. options.priority = parseToInt('priority', options);
  517. }
  518. if (options.foreground === true) {
  519. options.priority = Math.max(options.priority, 1);
  520. }
  521. if (options.foreground === false) {
  522. options.priority = Math.min(options.priority, 0);
  523. }
  524. if (options.defaults) {
  525. options.defaults = parseToInt('defaults', options);
  526. }
  527. if (options.smallIcon && !options.smallIcon.match(/^res:/)) {
  528. console.warn('Property "smallIcon" must be of kind res://...');
  529. }
  530. if (typeof options.timeout === 'boolean') {
  531. options.timeout = options.timeout ? 3600000 : null;
  532. }
  533. if (options.timeout) {
  534. options.timeout = parseToInt('timeout', options);
  535. }
  536. options.data = JSON.stringify(options.data);
  537. this._convertTrigger(options);
  538. this._convertActions(options);
  539. this._convertProgressBar(options);
  540. return options;
  541. };
  542. /**
  543. * Convert the passed values to their required type, modifying them
  544. * directly for Android and passing the converted list back for iOS.
  545. *
  546. * @param [ Map ] options Set of custom values.
  547. *
  548. * @return [ Map ] Interaction object with category & actions.
  549. */
  550. exports._convertActions = function (options) {
  551. var actions = [];
  552. if (!options.actions)
  553. return null;
  554. for (var i = 0, len = options.actions.length; i < len; i++) {
  555. var action = options.actions[i];
  556. if (!action.id) {
  557. console.warn('Action with title ' + action.title + ' ' +
  558. 'has no id and will not be added.');
  559. continue;
  560. }
  561. action.id = action.id.toString();
  562. actions.push(action);
  563. }
  564. options.actions = actions;
  565. return options;
  566. };
  567. /**
  568. * Convert the passed values for the trigger to their required type.
  569. *
  570. * @param [ Map ] options Set of custom values.
  571. *
  572. * @return [ Map ] Interaction object with trigger spec.
  573. */
  574. exports._convertTrigger = function (options) {
  575. var trigger = options.trigger || {},
  576. date = this._getValueFor(trigger, 'at', 'firstAt', 'date');
  577. var dateToNum = function (date) {
  578. var num = typeof date == 'object' ? date.getTime() : date;
  579. return Math.round(num);
  580. };
  581. if (!options.trigger)
  582. return;
  583. if (!trigger.type) {
  584. trigger.type = trigger.center ? 'location' : 'calendar';
  585. }
  586. var isCal = trigger.type == 'calendar';
  587. if (isCal && !date) {
  588. date = this._getValueFor(options, 'at', 'firstAt', 'date');
  589. }
  590. if (isCal && !trigger.every && options.every) {
  591. trigger.every = options.every;
  592. }
  593. if (isCal && (trigger.in || trigger.every)) {
  594. date = null;
  595. }
  596. if (isCal && date) {
  597. trigger.at = dateToNum(date);
  598. }
  599. if (isCal && trigger.firstAt) {
  600. trigger.firstAt = dateToNum(trigger.firstAt);
  601. }
  602. if (isCal && trigger.before) {
  603. trigger.before = dateToNum(trigger.before);
  604. }
  605. if (isCal && trigger.after) {
  606. trigger.after = dateToNum(trigger.after);
  607. }
  608. if (!trigger.count && device.platform == 'windows') {
  609. trigger.count = trigger.every ? 5 : 1;
  610. }
  611. if (trigger.count && device.platform == 'iOS') {
  612. console.warn('trigger: { count: } is not supported on iOS.');
  613. }
  614. if (!isCal) {
  615. trigger.notifyOnEntry = !!trigger.notifyOnEntry;
  616. trigger.notifyOnExit = trigger.notifyOnExit === true;
  617. trigger.radius = trigger.radius || 5;
  618. trigger.single = !!trigger.single;
  619. }
  620. if (!isCal || trigger.at) {
  621. delete trigger.every;
  622. }
  623. delete options.every;
  624. delete options.at;
  625. delete options.firstAt;
  626. delete options.date;
  627. options.trigger = trigger;
  628. return options;
  629. };
  630. /**
  631. * Convert the passed values for the progressBar to their required type.
  632. *
  633. * @param [ Map ] options Set of custom values.
  634. *
  635. * @return [ Map ] Interaction object with trigger spec.
  636. */
  637. exports._convertProgressBar = function (options) {
  638. var isAndroid = device.platform == 'Android',
  639. cfg = options.progressBar;
  640. if (cfg === undefined)
  641. return;
  642. if (typeof cfg === 'boolean') {
  643. cfg = options.progressBar = { enabled: cfg };
  644. }
  645. if (typeof cfg.enabled !== 'boolean') {
  646. cfg.enabled = !!(cfg.value || cfg.maxValue || cfg.indeterminate !== null);
  647. }
  648. cfg.value = cfg.value || 0;
  649. if (isAndroid) {
  650. cfg.maxValue = cfg.maxValue || 100;
  651. cfg.indeterminate = !!cfg.indeterminate;
  652. }
  653. cfg.enabled = !!cfg.enabled;
  654. if (cfg.enabled && options.clock === true) {
  655. options.clock = 'chronometer';
  656. }
  657. return options;
  658. };
  659. /**
  660. * Create a callback function to get executed within a specific scope.
  661. *
  662. * @param [ Function ] fn The function to be exec as the callback.
  663. * @param [ Object ] scope The callback function's scope.
  664. *
  665. * @return [ Function ]
  666. */
  667. exports._createCallbackFn = function (fn, scope) {
  668. if (typeof fn != 'function')
  669. return;
  670. return function () {
  671. fn.apply(scope || this, arguments);
  672. };
  673. };
  674. /**
  675. * Convert the IDs to numbers.
  676. *
  677. * @param [ Array ] ids
  678. *
  679. * @return [ Array<Number> ]
  680. */
  681. exports._convertIds = function (ids) {
  682. var convertedIds = [];
  683. for (var i = 0, len = ids.length; i < len; i++) {
  684. convertedIds.push(Number(ids[i]));
  685. }
  686. return convertedIds;
  687. };
  688. /**
  689. * First found value for the given keys.
  690. *
  691. * @param [ Object ] options Object with key-value properties.
  692. * @param [ *Array<String> ] keys List of keys.
  693. *
  694. * @return [ Object ]
  695. */
  696. exports._getValueFor = function (options) {
  697. var keys = Array.apply(null, arguments).slice(1);
  698. for (var i = 0, key = keys[i], len = keys.length; i < len; key = keys[++i]) {
  699. if (options.hasOwnProperty(key)) {
  700. return options[key];
  701. }
  702. }
  703. return null;
  704. };
  705. /**
  706. * Convert a value to an array.
  707. *
  708. * @param [ Object ] obj Any kind of object.
  709. *
  710. * @return [ Array ] An array with the object as first item.
  711. */
  712. exports._toArray = function (obj) {
  713. return Array.isArray(obj) ? Array.from(obj) : [obj];
  714. };
  715. /**
  716. * Execute the native counterpart.
  717. *
  718. * @param [ String ] action The name of the action.
  719. * @param [ Array ] args Array of arguments.
  720. * @param [ Function] callback The callback function.
  721. * @param [ Object ] scope The scope for the function.
  722. *
  723. * @return [ Void ]
  724. */
  725. exports._exec = function (action, args, callback, scope) {
  726. var fn = this._createCallbackFn(callback, scope),
  727. params = [];
  728. if (Array.isArray(args)) {
  729. params = args;
  730. } else if (args) {
  731. params.push(args);
  732. }
  733. exec(fn, null, 'LocalNotification', action, params);
  734. };
  735. /**
  736. * Set the launch details if the app was launched by clicking on a toast.
  737. *
  738. * @return [ Void ]
  739. */
  740. exports._setLaunchDetails = function () {
  741. exports._exec('launch', null, function (details) {
  742. if (details) {
  743. exports.launchDetails = details;
  744. }
  745. });
  746. };
  747. // Polyfill for Object.assign
  748. if (typeof Object.assign != 'function') {
  749. Object.assign = function(target) {
  750. 'use strict';
  751. if (target == null) {
  752. throw new TypeError('Cannot convert undefined or null to object');
  753. }
  754. target = Object(target);
  755. for (var index = 1; index < arguments.length; index++) {
  756. var source = arguments[index];
  757. if (source != null) {
  758. for (var key in source) {
  759. if (Object.prototype.hasOwnProperty.call(source, key)) {
  760. target[key] = source[key];
  761. }
  762. }
  763. }
  764. }
  765. return target;
  766. };
  767. }
  768. // Polyfill for Array.from
  769. // Production steps of ECMA-262, Edition 6, 22.1.2.1
  770. // Reference: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.from
  771. if (!Array.from) {
  772. Array.from = (function () {
  773. var toStr = Object.prototype.toString;
  774. var isCallable = function (fn) {
  775. return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
  776. };
  777. var toInteger = function (value) {
  778. var number = Number(value);
  779. if (isNaN(number)) { return 0; }
  780. if (number === 0 || !isFinite(number)) { return number; }
  781. return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
  782. };
  783. var maxSafeInteger = Math.pow(2, 53) - 1;
  784. var toLength = function (value) {
  785. var len = toInteger(value);
  786. return Math.min(Math.max(len, 0), maxSafeInteger);
  787. };
  788. // The length property of the from method is 1.
  789. return function from(arrayLike/*, mapFn, thisArg */) {
  790. // 1. Let C be the this value.
  791. var C = this;
  792. // 2. Let items be ToObject(arrayLike).
  793. var items = Object(arrayLike);
  794. // 3. ReturnIfAbrupt(items).
  795. if (arrayLike == null) {
  796. throw new TypeError("Array.from requires an array-like object - not null or undefined");
  797. }
  798. // 4. If mapfn is undefined, then let mapping be false.
  799. var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
  800. var T;
  801. if (typeof mapFn !== 'undefined') {
  802. // 5. else
  803. // 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
  804. if (!isCallable(mapFn)) {
  805. throw new TypeError('Array.from: when provided, the second argument must be a function');
  806. }
  807. // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
  808. if (arguments.length > 2) {
  809. T = arguments[2];
  810. }
  811. }
  812. // 10. Let lenValue be Get(items, "length").
  813. // 11. Let len be ToLength(lenValue).
  814. var len = toLength(items.length);
  815. // 13. If IsConstructor(C) is true, then
  816. // 13. a. Let A be the result of calling the [[Construct]] internal method of C with an argument list containing the single item len.
  817. // 14. a. Else, Let A be ArrayCreate(len).
  818. var A = isCallable(C) ? Object(new C(len)) : new Array(len);
  819. // 16. Let k be 0.
  820. var k = 0;
  821. // 17. Repeat, while k < len… (also steps a - h)
  822. var kValue;
  823. while (k < len) {
  824. kValue = items[k];
  825. if (mapFn) {
  826. A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
  827. } else {
  828. A[k] = kValue;
  829. }
  830. k += 1;
  831. }
  832. // 18. Let putStatus be Put(A, "length", len, true).
  833. A.length = len;
  834. // 20. Return A.
  835. return A;
  836. };
  837. }());
  838. }
  839. // Called after 'deviceready' event
  840. channel.deviceready.subscribe(function () {
  841. if (!window.skipLocalNotificationReady) {
  842. exports.fireQueuedEvents();
  843. }
  844. });
  845. // Called before 'deviceready' event
  846. channel.onCordovaReady.subscribe(function () {
  847. channel.onCordovaInfoReady.subscribe(function () {
  848. exports._setLaunchDetails();
  849. });
  850. });