123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. import { Observable } from 'rxjs/Observable';
  2. import { fromEvent } from 'rxjs/observable/fromEvent';
  3. import { checkReady } from './bootstrap';
  4. import { cordovaWarn, getPlugin, getPromise, pluginWarn } from './util';
  5. checkReady();
  6. // declare const window;
  7. // declare var Promise;
  8. export var ERR_CORDOVA_NOT_AVAILABLE = { error: 'cordova_not_available' };
  9. export var ERR_PLUGIN_NOT_INSTALLED = { error: 'plugin_not_installed' };
  10. export function checkAvailability(plugin, methodName, pluginName) {
  11. var pluginRef, pluginInstance, pluginPackage;
  12. if (typeof plugin === 'string') {
  13. pluginRef = plugin;
  14. }
  15. else {
  16. pluginRef = plugin.constructor.getPluginRef();
  17. pluginName = plugin.constructor.getPluginName();
  18. pluginPackage = plugin.constructor.getPluginInstallName();
  19. }
  20. pluginInstance = getPlugin(pluginRef);
  21. if (!pluginInstance ||
  22. (!!methodName && typeof pluginInstance[methodName] === 'undefined')) {
  23. if (!window.cordova) {
  24. cordovaWarn(pluginName, methodName);
  25. return ERR_CORDOVA_NOT_AVAILABLE;
  26. }
  27. pluginWarn(pluginName, pluginPackage, methodName);
  28. return ERR_PLUGIN_NOT_INSTALLED;
  29. }
  30. return true;
  31. }
  32. /**
  33. * Checks if _objectInstance exists and has the method/property
  34. * @private
  35. */
  36. export function instanceAvailability(pluginObj, methodName) {
  37. return (pluginObj._objectInstance &&
  38. (!methodName ||
  39. typeof pluginObj._objectInstance[methodName] !== 'undefined'));
  40. }
  41. function setIndex(args, opts, resolve, reject) {
  42. if (opts === void 0) { opts = {}; }
  43. // ignore resolve and reject in case sync
  44. if (opts.sync) {
  45. return args;
  46. }
  47. // If the plugin method expects myMethod(success, err, options)
  48. if (opts.callbackOrder === 'reverse') {
  49. // Get those arguments in the order [resolve, reject, ...restOfArgs]
  50. args.unshift(reject);
  51. args.unshift(resolve);
  52. }
  53. else if (opts.callbackStyle === 'node') {
  54. args.push(function (err, result) {
  55. if (err) {
  56. reject(err);
  57. }
  58. else {
  59. resolve(result);
  60. }
  61. });
  62. }
  63. else if (opts.callbackStyle === 'object' &&
  64. opts.successName &&
  65. opts.errorName) {
  66. var obj = {};
  67. obj[opts.successName] = resolve;
  68. obj[opts.errorName] = reject;
  69. args.push(obj);
  70. }
  71. else if (typeof opts.successIndex !== 'undefined' ||
  72. typeof opts.errorIndex !== 'undefined') {
  73. var setSuccessIndex = function () {
  74. // If we've specified a success/error index
  75. if (opts.successIndex > args.length) {
  76. args[opts.successIndex] = resolve;
  77. }
  78. else {
  79. args.splice(opts.successIndex, 0, resolve);
  80. }
  81. };
  82. var setErrorIndex = function () {
  83. // We don't want that the reject cb gets spliced into the position of an optional argument that has not been defined and thus causing non expected behaviour.
  84. if (opts.errorIndex > args.length) {
  85. args[opts.errorIndex] = reject; // insert the reject fn at the correct specific index
  86. }
  87. else {
  88. args.splice(opts.errorIndex, 0, reject); // otherwise just splice it into the array
  89. }
  90. };
  91. if (opts.successIndex > opts.errorIndex) {
  92. setErrorIndex();
  93. setSuccessIndex();
  94. }
  95. else {
  96. setSuccessIndex();
  97. setErrorIndex();
  98. }
  99. }
  100. else {
  101. // Otherwise, let's tack them on to the end of the argument list
  102. // which is 90% of cases
  103. args.push(resolve);
  104. args.push(reject);
  105. }
  106. return args;
  107. }
  108. function callCordovaPlugin(pluginObj, methodName, args, opts, resolve, reject) {
  109. if (opts === void 0) { opts = {}; }
  110. // Try to figure out where the success/error callbacks need to be bound
  111. // to our promise resolve/reject handlers.
  112. args = setIndex(args, opts, resolve, reject);
  113. var availabilityCheck = checkAvailability(pluginObj, methodName);
  114. if (availabilityCheck === true) {
  115. var pluginInstance = getPlugin(pluginObj.constructor.getPluginRef());
  116. return pluginInstance[methodName].apply(pluginInstance, args);
  117. }
  118. else {
  119. return availabilityCheck;
  120. }
  121. }
  122. function wrapPromise(pluginObj, methodName, args, opts) {
  123. if (opts === void 0) { opts = {}; }
  124. var pluginResult, rej;
  125. var p = getPromise(function (resolve, reject) {
  126. if (opts.destruct) {
  127. pluginResult = callCordovaPlugin(pluginObj, methodName, args, opts, function () {
  128. var args = [];
  129. for (var _i = 0; _i < arguments.length; _i++) {
  130. args[_i] = arguments[_i];
  131. }
  132. return resolve(args);
  133. }, function () {
  134. var args = [];
  135. for (var _i = 0; _i < arguments.length; _i++) {
  136. args[_i] = arguments[_i];
  137. }
  138. return reject(args);
  139. });
  140. }
  141. else {
  142. pluginResult = callCordovaPlugin(pluginObj, methodName, args, opts, resolve, reject);
  143. }
  144. rej = reject;
  145. });
  146. // Angular throws an error on unhandled rejection, but in this case we have already printed
  147. // a warning that Cordova is undefined or the plugin is uninstalled, so there is no reason
  148. // to error
  149. if (pluginResult && pluginResult.error) {
  150. p.catch(function () { });
  151. typeof rej === 'function' && rej(pluginResult.error);
  152. }
  153. return p;
  154. }
  155. function wrapOtherPromise(pluginObj, methodName, args, opts) {
  156. if (opts === void 0) { opts = {}; }
  157. return getPromise(function (resolve, reject) {
  158. var pluginResult = callCordovaPlugin(pluginObj, methodName, args, opts);
  159. if (pluginResult) {
  160. if (pluginResult.error) {
  161. reject(pluginResult.error);
  162. }
  163. else if (pluginResult.then) {
  164. pluginResult.then(resolve).catch(reject);
  165. }
  166. }
  167. else {
  168. reject({ error: 'unexpected_error' });
  169. }
  170. });
  171. }
  172. function wrapObservable(pluginObj, methodName, args, opts) {
  173. if (opts === void 0) { opts = {}; }
  174. return new Observable(function (observer) {
  175. var pluginResult;
  176. if (opts.destruct) {
  177. pluginResult = callCordovaPlugin(pluginObj, methodName, args, opts, function () {
  178. var args = [];
  179. for (var _i = 0; _i < arguments.length; _i++) {
  180. args[_i] = arguments[_i];
  181. }
  182. return observer.next(args);
  183. }, function () {
  184. var args = [];
  185. for (var _i = 0; _i < arguments.length; _i++) {
  186. args[_i] = arguments[_i];
  187. }
  188. return observer.error(args);
  189. });
  190. }
  191. else {
  192. pluginResult = callCordovaPlugin(pluginObj, methodName, args, opts, observer.next.bind(observer), observer.error.bind(observer));
  193. }
  194. if (pluginResult && pluginResult.error) {
  195. observer.error(pluginResult.error);
  196. observer.complete();
  197. }
  198. return function () {
  199. try {
  200. if (opts.clearFunction) {
  201. if (opts.clearWithArgs) {
  202. return callCordovaPlugin(pluginObj, opts.clearFunction, args, opts, observer.next.bind(observer), observer.error.bind(observer));
  203. }
  204. return callCordovaPlugin(pluginObj, opts.clearFunction, []);
  205. }
  206. }
  207. catch (e) {
  208. console.warn('Unable to clear the previous observable watch for', pluginObj.constructor.getPluginName(), methodName);
  209. console.warn(e);
  210. }
  211. };
  212. });
  213. }
  214. function callInstance(pluginObj, methodName, args, opts, resolve, reject) {
  215. if (opts === void 0) { opts = {}; }
  216. args = setIndex(args, opts, resolve, reject);
  217. if (instanceAvailability(pluginObj, methodName)) {
  218. return pluginObj._objectInstance[methodName].apply(pluginObj._objectInstance, args);
  219. }
  220. }
  221. /**
  222. * Wrap the event with an observable
  223. * @private
  224. * @param event even name
  225. * @param element The element to attach the event listener to
  226. * @returns {Observable}
  227. */
  228. export function wrapEventObservable(event, element) {
  229. if (element === void 0) { element = window; }
  230. return fromEvent(element, event);
  231. }
  232. /**
  233. * Certain plugins expect the user to override methods in the plugin. For example,
  234. * window.cordova.plugins.backgroundMode.onactivate = function() { ... }.
  235. *
  236. * Unfortunately, this is brittle and would be better wrapped as an Observable. overrideFunction
  237. * does just this.
  238. * @private
  239. */
  240. export function overrideFunction(pluginObj, methodName, args, opts) {
  241. if (opts === void 0) { opts = {}; }
  242. return new Observable(function (observer) {
  243. var availabilityCheck = checkAvailability(pluginObj, null, pluginObj.constructor.getPluginName());
  244. if (availabilityCheck === true) {
  245. var pluginInstance_1 = getPlugin(pluginObj.constructor.getPluginRef());
  246. pluginInstance_1[methodName] = observer.next.bind(observer);
  247. return function () { return (pluginInstance_1[methodName] = function () { }); };
  248. }
  249. else {
  250. observer.error(availabilityCheck);
  251. observer.complete();
  252. }
  253. });
  254. }
  255. /**
  256. * @private
  257. */
  258. export var wrap = function (pluginObj, methodName, opts) {
  259. if (opts === void 0) { opts = {}; }
  260. return function () {
  261. var args = [];
  262. for (var _i = 0; _i < arguments.length; _i++) {
  263. args[_i] = arguments[_i];
  264. }
  265. if (opts.sync) {
  266. // Sync doesn't wrap the plugin with a promise or observable, it returns the result as-is
  267. return callCordovaPlugin(pluginObj, methodName, args, opts);
  268. }
  269. else if (opts.observable) {
  270. return wrapObservable(pluginObj, methodName, args, opts);
  271. }
  272. else if (opts.eventObservable && opts.event) {
  273. return wrapEventObservable(opts.event, opts.element);
  274. }
  275. else if (opts.otherPromise) {
  276. return wrapOtherPromise(pluginObj, methodName, args, opts);
  277. }
  278. else {
  279. return wrapPromise(pluginObj, methodName, args, opts);
  280. }
  281. };
  282. };
  283. /**
  284. * @private
  285. */
  286. export function wrapInstance(pluginObj, methodName, opts) {
  287. if (opts === void 0) { opts = {}; }
  288. return function () {
  289. var args = [];
  290. for (var _i = 0; _i < arguments.length; _i++) {
  291. args[_i] = arguments[_i];
  292. }
  293. if (opts.sync) {
  294. return callInstance(pluginObj, methodName, args, opts);
  295. }
  296. else if (opts.observable) {
  297. return new Observable(function (observer) {
  298. var pluginResult;
  299. if (opts.destruct) {
  300. pluginResult = callInstance(pluginObj, methodName, args, opts, function () {
  301. var args = [];
  302. for (var _i = 0; _i < arguments.length; _i++) {
  303. args[_i] = arguments[_i];
  304. }
  305. return observer.next(args);
  306. }, function () {
  307. var args = [];
  308. for (var _i = 0; _i < arguments.length; _i++) {
  309. args[_i] = arguments[_i];
  310. }
  311. return observer.error(args);
  312. });
  313. }
  314. else {
  315. pluginResult = callInstance(pluginObj, methodName, args, opts, observer.next.bind(observer), observer.error.bind(observer));
  316. }
  317. if (pluginResult && pluginResult.error) {
  318. observer.error(pluginResult.error);
  319. observer.complete();
  320. }
  321. return function () {
  322. try {
  323. if (opts.clearWithArgs) {
  324. return callInstance(pluginObj, opts.clearFunction, args, opts, observer.next.bind(observer), observer.error.bind(observer));
  325. }
  326. return callInstance(pluginObj, opts.clearFunction, []);
  327. }
  328. catch (e) {
  329. console.warn('Unable to clear the previous observable watch for', pluginObj.constructor.getPluginName(), methodName);
  330. console.warn(e);
  331. }
  332. };
  333. });
  334. }
  335. else if (opts.otherPromise) {
  336. return getPromise(function (resolve, reject) {
  337. var result;
  338. if (opts.destruct) {
  339. result = callInstance(pluginObj, methodName, args, opts, function () {
  340. var args = [];
  341. for (var _i = 0; _i < arguments.length; _i++) {
  342. args[_i] = arguments[_i];
  343. }
  344. return resolve(args);
  345. }, function () {
  346. var args = [];
  347. for (var _i = 0; _i < arguments.length; _i++) {
  348. args[_i] = arguments[_i];
  349. }
  350. return reject(args);
  351. });
  352. }
  353. else {
  354. result = callInstance(pluginObj, methodName, args, opts, resolve, reject);
  355. }
  356. if (result && !!result.then) {
  357. result.then(resolve, reject);
  358. }
  359. else {
  360. reject();
  361. }
  362. });
  363. }
  364. else {
  365. var pluginResult_1, rej_1;
  366. var p = getPromise(function (resolve, reject) {
  367. if (opts.destruct) {
  368. pluginResult_1 = callInstance(pluginObj, methodName, args, opts, function () {
  369. var args = [];
  370. for (var _i = 0; _i < arguments.length; _i++) {
  371. args[_i] = arguments[_i];
  372. }
  373. return resolve(args);
  374. }, function () {
  375. var args = [];
  376. for (var _i = 0; _i < arguments.length; _i++) {
  377. args[_i] = arguments[_i];
  378. }
  379. return reject(args);
  380. });
  381. }
  382. else {
  383. pluginResult_1 = callInstance(pluginObj, methodName, args, opts, resolve, reject);
  384. }
  385. rej_1 = reject;
  386. });
  387. // Angular throws an error on unhandled rejection, but in this case we have already printed
  388. // a warning that Cordova is undefined or the plugin is uninstalled, so there is no reason
  389. // to error
  390. if (pluginResult_1 && pluginResult_1.error) {
  391. p.catch(function () { });
  392. typeof rej_1 === 'function' && rej_1(pluginResult_1.error);
  393. }
  394. return p;
  395. }
  396. };
  397. }
  398. //# sourceMappingURL=plugin.js.map