diff --git a/demo/www/app/home/home.js b/demo/www/app/home/home.js index 465ecc784..e53e5b1ae 100644 --- a/demo/www/app/home/home.js +++ b/demo/www/app/home/home.js @@ -1,6 +1,12 @@ import {Page, NavController} from 'ionic/ionic' -import {ActionSheet, Camera, StatusBar, Toast} from 'ionic-native'; +import { + ActionSheet, + Camera, + Device, + StatusBar, + Toast +} from 'ionic-native'; import {Plugin} from '../plugin/plugin'; @@ -14,6 +20,7 @@ export class HomePage { this.plugins = [ ActionSheet, Camera, + Device, StatusBar, Toast ]; diff --git a/demo/www/app/plugin/plugin.js b/demo/www/app/plugin/plugin.js index fb0633a47..ca3a0ccef 100644 --- a/demo/www/app/plugin/plugin.js +++ b/demo/www/app/plugin/plugin.js @@ -59,12 +59,18 @@ export class Plugin { addPixelsY: -40 // added a negative value to move it up a bit (default 0) }); console.log('Doing method', method, 'on Plugin', this.plugin, 'args:', args); - // TODO: Pass args - this.plugin[method].apply(this.plugin, args).then(() => { - console.log('Success', arguments); - }, (err) => { - console.error('Error', err); - }); + + let v = this.plugin[method].apply(this.plugin, args); + + if(v && v.then) { + v.then(() => { + console.log('Success', arguments); + }, (err) => { + console.error('Error', err); + }); + } else { + console.log('Response: ', v); + } } } diff --git a/dist/index.d.ts b/dist/index.d.ts index 11b585e83..087d76f2a 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1,4 +1,5 @@ export * from './plugins/actionsheet'; export * from './plugins/camera'; +export * from './plugins/device'; export * from './plugins/statusbar'; export * from './plugins/toast'; diff --git a/dist/index.js b/dist/index.js index f8eacb329..955757b45 100644 --- a/dist/index.js +++ b/dist/index.js @@ -4,6 +4,7 @@ function __export(m) { var DEVICE_READY_TIMEOUT = 2000; __export(require('./plugins/actionsheet')); __export(require('./plugins/camera')); +__export(require('./plugins/device')); __export(require('./plugins/statusbar')); __export(require('./plugins/toast')); var didFireReady = false; @@ -11,7 +12,7 @@ window.addEventListener('deviceready', function () { didFireReady = true; }); setTimeout(function () { - if (!didFireReady) { + if (!didFireReady && window.cordova) { console.warn('Native: deviceready did not fire within ' + DEVICE_READY_TIMEOUT + 'ms. This can happen when plugins are in an inconsistent state. Try removing plugins from plugins/ and reinstalling them.'); } }, DEVICE_READY_TIMEOUT); diff --git a/dist/plugins/device.d.ts b/dist/plugins/device.d.ts new file mode 100644 index 000000000..3e06c17ba --- /dev/null +++ b/dist/plugins/device.d.ts @@ -0,0 +1,3 @@ +export declare class Device { + static getDevice(): any; +} diff --git a/dist/plugins/device.js b/dist/plugins/device.js new file mode 100644 index 000000000..344a31516 --- /dev/null +++ b/dist/plugins/device.js @@ -0,0 +1,29 @@ +if (typeof __decorate !== "function") __decorate = function (decorators, target, key, desc) { + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc); + switch (arguments.length) { + case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target); + case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0); + case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc); + } +}; +var plugin_1 = require('./plugin'); +var Device = (function () { + function Device() { + } + Device.getDevice = function () { + return window.device; + }; + Object.defineProperty(Device, "getDevice", + __decorate([ + plugin_1.RequiresPlugin + ], Device, "getDevice", Object.getOwnPropertyDescriptor(Device, "getDevice"))); + Device = __decorate([ + plugin_1.Plugin({ + name: 'Device', + plugin: 'cordova-plugin-device', + pluginRef: 'device' + }) + ], Device); + return Device; +})(); +exports.Device = Device; diff --git a/dist/plugins/plugin.d.ts b/dist/plugins/plugin.d.ts index ad30755d7..69a89a259 100644 --- a/dist/plugins/plugin.d.ts +++ b/dist/plugins/plugin.d.ts @@ -1,3 +1,8 @@ +export declare const getPlugin: (pluginRef: string) => any; +export declare const isInstalled: (pluginRef: string) => boolean; +export declare const pluginWarn: (pluginName: string, method: string, plugin: string) => void; +export declare const cordovaWarn: (pluginName: string, method: string) => void; export declare const wrap: (pluginObj: any, methodName: any, opts?: any) => (...args: any[]) => any; export declare function Plugin(config: any): (cls: any) => any; export declare function Cordova(opts?: any): (obj: any, methodName: any) => void; +export declare function RequiresPlugin(target: Function, key: string, descriptor: TypedPropertyDescriptor): TypedPropertyDescriptor; diff --git a/dist/plugins/plugin.js b/dist/plugins/plugin.js index 5a8ea9178..88ef6bd91 100644 --- a/dist/plugins/plugin.js +++ b/dist/plugins/plugin.js @@ -1,4 +1,28 @@ var util_1 = require('../util'); +exports.getPlugin = function (pluginRef) { + return util_1.get(window, pluginRef); +}; +exports.isInstalled = function (pluginRef) { + return !!exports.getPlugin(pluginRef); +}; +exports.pluginWarn = function (pluginName, method, plugin) { + if (method) { + console.warn('Native: tried calling ' + pluginName + '.' + method + + ', but the ' + pluginName + ' plugin is not installed. Install the ' + + plugin + ' plugin'); + } + else { + console.warn('Native: tried accessing the ' + pluginName + ' plugin but it\'s not installed. Install the ' + plugin + ' plugin'); + } +}; +exports.cordovaWarn = function (pluginName, method) { + if (method) { + console.warn('Native: tried calling ' + pluginName + '.' + method + ', but Cordova is not available. Make sure to include cordova.js or run in a device/simulator'); + } + else { + console.warn('Native: tried accessing the ' + pluginName + ' plugin but Cordova is not available. Make sure to include cordova.js or run in a device/simulator'); + } +}; exports.wrap = function (pluginObj, methodName, opts) { if (opts === void 0) { opts = {}; } return function () { @@ -8,10 +32,11 @@ exports.wrap = function (pluginObj, methodName, opts) { } return new Promise(function (resolve, reject) { if (!window.cordova) { - console.warn('Native: tried calling ' + pluginObj.name + '.' + methodName + ', but Cordova is not available. Make sure to include cordova.js or run in a device/simulator'); + exports.cordovaWarn(pluginObj.name, methodName); reject({ error: 'cordova_not_available' }); + return; } if (typeof opts.successIndex !== 'undefined') { args[opts.successIndex] = resolve; @@ -19,9 +44,9 @@ exports.wrap = function (pluginObj, methodName, opts) { if (typeof opts.errorIndex !== 'undefined') { args[opts.errorIndex] = reject; } - var pluginInstance = util_1.get(window, pluginObj.pluginRef); + var pluginInstance = exports.getPlugin(pluginObj.pluginRef); if (!pluginInstance) { - console.warn('Native: tried calling ' + pluginObj.name + '.' + methodName + ', but the ' + pluginObj.name + ' plugin is not installed. Install the ' + pluginObj.plugin + ' plugin'); + exports.pluginWarn(pluginObj.name, methodName, pluginObj.name); reject({ error: 'plugin_not_installed' }); @@ -31,13 +56,6 @@ exports.wrap = function (pluginObj, methodName, opts) { }); }; }; -var PluginDecotor = (function () { - function PluginDecotor(cls, config) { - this.cls = cls; - this.config = config; - } - return PluginDecotor; -})(); function Plugin(config) { return function (cls) { // Add these fields to the class @@ -58,3 +76,25 @@ function Cordova(opts) { }; } exports.Cordova = Cordova; +function RequiresPlugin(target, key, descriptor) { + var originalMethod = descriptor.value; + descriptor.value = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i - 0] = arguments[_i]; + } + console.log('Calling', this); + if (!window.cordova) { + exports.cordovaWarn(this.name, null); + return; + } + var pluginInstance = exports.getPlugin(this.pluginRef); + if (!pluginInstance) { + exports.pluginWarn(this.name, null, this.name); + return; + } + originalMethod.apply(this, args); + }; + return descriptor; +} +exports.RequiresPlugin = RequiresPlugin; diff --git a/dist/src/index.d.ts b/dist/src/index.d.ts index 017265146..68333def4 100644 --- a/dist/src/index.d.ts +++ b/dist/src/index.d.ts @@ -1,4 +1,5 @@ export * from './plugins/actionsheet'; export * from './plugins/camera'; +export * from './plugins/device'; export * from './plugins/statusbar'; export * from './plugins/toast'; diff --git a/dist/src/index.js b/dist/src/index.js index 78496447a..0244dd084 100644 --- a/dist/src/index.js +++ b/dist/src/index.js @@ -4,6 +4,7 @@ function __export(m) { var DEVICE_READY_TIMEOUT = 2000; __export(require('./plugins/actionsheet')); __export(require('./plugins/camera')); +__export(require('./plugins/device')); __export(require('./plugins/statusbar')); __export(require('./plugins/toast')); var didFireReady = false; diff --git a/dist/src/plugins/device.d.ts b/dist/src/plugins/device.d.ts new file mode 100644 index 000000000..b477e0aaf --- /dev/null +++ b/dist/src/plugins/device.d.ts @@ -0,0 +1,3 @@ +export declare class Device { + static getDevice(): any; +} diff --git a/dist/src/plugins/device.js b/dist/src/plugins/device.js new file mode 100644 index 000000000..7c3066933 --- /dev/null +++ b/dist/src/plugins/device.js @@ -0,0 +1,33 @@ +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +var plugin_1 = require('./plugin'); +var Device = (function () { + function Device() { + } + Device.getDevice = function () { + return window.device; + }; + __decorate([ + plugin_1.RequiresPlugin, + __metadata('design:type', Function), + __metadata('design:paramtypes', []), + __metadata('design:returntype', void 0) + ], Device, "getDevice", null); + Device = __decorate([ + plugin_1.Plugin({ + name: 'Device', + plugin: 'cordova-plugin-device', + pluginRef: 'device' + }), + __metadata('design:paramtypes', []) + ], Device); + return Device; +})(); +exports.Device = Device; diff --git a/dist/src/plugins/plugin.d.ts b/dist/src/plugins/plugin.d.ts index 8185a016c..329a12ec2 100644 --- a/dist/src/plugins/plugin.d.ts +++ b/dist/src/plugins/plugin.d.ts @@ -1,3 +1,8 @@ +export declare const getPlugin: (pluginRef: string) => any; +export declare const isInstalled: (pluginRef: string) => boolean; +export declare const pluginWarn: (pluginName: string, method: string, plugin: string) => void; +export declare const cordovaWarn: (pluginName: string, method: string) => void; export declare const wrap: (pluginObj: any, methodName: any, opts?: any) => (...args: any[]) => any; export declare function Plugin(config: any): (cls: any) => any; export declare function Cordova(opts?: any): (obj: any, methodName: any) => void; +export declare function RequiresPlugin(target: Function, key: string, descriptor: TypedPropertyDescriptor): TypedPropertyDescriptor; diff --git a/dist/src/plugins/plugin.js b/dist/src/plugins/plugin.js index 9116a0146..dc7513bf3 100644 --- a/dist/src/plugins/plugin.js +++ b/dist/src/plugins/plugin.js @@ -1,4 +1,28 @@ var util_1 = require('../util'); +exports.getPlugin = function (pluginRef) { + return util_1.get(window, pluginRef); +}; +exports.isInstalled = function (pluginRef) { + return !!exports.getPlugin(pluginRef); +}; +exports.pluginWarn = function (pluginName, method, plugin) { + if (method) { + console.warn('Native: tried calling ' + pluginName + '.' + method + + ', but the ' + pluginName + ' plugin is not installed. Install the ' + + plugin + ' plugin'); + } + else { + console.warn('Native: tried accessing the ' + pluginName + ' plugin but it\'s not installed. Install the ' + plugin + ' plugin'); + } +}; +exports.cordovaWarn = function (pluginName, method) { + if (method) { + console.warn('Native: tried calling ' + pluginName + '.' + method + ', but Cordova is not available. Make sure to include cordova.js or run in a device/simulator'); + } + else { + console.warn('Native: tried accessing the ' + pluginName + ' plugin but Cordova is not available. Make sure to include cordova.js or run in a device/simulator'); + } +}; exports.wrap = function (pluginObj, methodName, opts) { if (opts === void 0) { opts = {}; } return function () { @@ -8,10 +32,11 @@ exports.wrap = function (pluginObj, methodName, opts) { } return new Promise(function (resolve, reject) { if (!window.cordova) { - console.warn('Native: tried calling ' + pluginObj.name + '.' + methodName + ', but Cordova is not available. Make sure to include cordova.js or run in a device/simulator'); + exports.cordovaWarn(pluginObj.name, methodName); reject({ error: 'cordova_not_available' }); + return; } if (typeof opts.successIndex !== 'undefined') { args[opts.successIndex] = resolve; @@ -19,9 +44,9 @@ exports.wrap = function (pluginObj, methodName, opts) { if (typeof opts.errorIndex !== 'undefined') { args[opts.errorIndex] = reject; } - var pluginInstance = util_1.get(window, pluginObj.pluginRef); + var pluginInstance = exports.getPlugin(pluginObj.pluginRef); if (!pluginInstance) { - console.warn('Native: tried calling ' + pluginObj.name + '.' + methodName + ', but the ' + pluginObj.name + ' plugin is not installed. Install the ' + pluginObj.plugin + ' plugin'); + exports.pluginWarn(pluginObj.name, methodName, pluginObj.name); reject({ error: 'plugin_not_installed' }); @@ -31,13 +56,6 @@ exports.wrap = function (pluginObj, methodName, opts) { }); }; }; -var PluginDecotor = (function () { - function PluginDecotor(cls, config) { - this.cls = cls; - this.config = config; - } - return PluginDecotor; -})(); function Plugin(config) { return function (cls) { for (var k in config) { @@ -57,3 +75,25 @@ function Cordova(opts) { }; } exports.Cordova = Cordova; +function RequiresPlugin(target, key, descriptor) { + var originalMethod = descriptor.value; + descriptor.value = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i - 0] = arguments[_i]; + } + console.log('Calling', this); + if (!window.cordova) { + exports.cordovaWarn(this.name, null); + return; + } + var pluginInstance = exports.getPlugin(this.pluginRef); + if (!pluginInstance) { + exports.pluginWarn(this.name, null, this.name); + return; + } + originalMethod.apply(this, args); + }; + return descriptor; +} +exports.RequiresPlugin = RequiresPlugin; diff --git a/src/index.ts b/src/index.ts index 7aa97e861..38cee2294 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,11 +2,16 @@ const DEVICE_READY_TIMEOUT = 2000; export * from './plugins/actionsheet'; export * from './plugins/camera'; +export * from './plugins/device'; export * from './plugins/statusbar'; export * from './plugins/toast'; -declare var window; +// To help developers using cordova, we listen for the device ready event and +// log an error if it didn't fire in a reasonable amount of time. Generally, +// when this happens, developers should remove and reinstall plugins, since +// an inconsistent plugin is often the culprit. +declare var window; let didFireReady = false; window.addEventListener('deviceready', function() { diff --git a/src/plugins/device.ts b/src/plugins/device.ts new file mode 100644 index 000000000..b29fe9013 --- /dev/null +++ b/src/plugins/device.ts @@ -0,0 +1,16 @@ +import {Plugin, RequiresPlugin} from './plugin'; + +declare var window; + +@Plugin({ + name: 'Device', + plugin: 'cordova-plugin-device', + pluginRef: 'device' +}) +export class Device { + + @RequiresPlugin + static getDevice() { + return window.device; + } +} diff --git a/src/plugins/plugin.ts b/src/plugins/plugin.ts index 7d50fa800..d07dd7d38 100644 --- a/src/plugins/plugin.ts +++ b/src/plugins/plugin.ts @@ -3,15 +3,40 @@ import {get} from '../util'; declare var window; declare var Promise; + +export const getPlugin = function(pluginRef: string): any { + return get(window, pluginRef); +} +export const isInstalled = function(pluginRef: string): boolean { + return !!getPlugin(pluginRef); +} +export const pluginWarn = function(pluginName: string, method: string, plugin: string) { + if(method) { + console.warn('Native: tried calling ' + pluginName + '.' + method + + ', but the ' + pluginName + ' plugin is not installed. Install the ' + + plugin + ' plugin'); + } else { + console.warn('Native: tried accessing the ' + pluginName + ' plugin but it\'s not installed. Install the ' + plugin + ' plugin'); + } +} +export const cordovaWarn = function(pluginName: string, method: string) { + if(method) { + console.warn('Native: tried calling ' + pluginName + '.' + method + ', but Cordova is not available. Make sure to include cordova.js or run in a device/simulator'); + } else { + console.warn('Native: tried accessing the ' + pluginName + ' plugin but Cordova is not available. Make sure to include cordova.js or run in a device/simulator'); + } +} + export const wrap = function(pluginObj, methodName, opts: any = {}) { return (...args) => { return new Promise((resolve, reject) => { if(!window.cordova) { - console.warn('Native: tried calling ' + pluginObj.name + '.' + methodName + ', but Cordova is not available. Make sure to include cordova.js or run in a device/simulator'); + cordovaWarn(pluginObj.name, methodName); reject({ error: 'cordova_not_available' }) + return; } if(typeof opts.successIndex !== 'undefined') { @@ -21,10 +46,10 @@ export const wrap = function(pluginObj, methodName, opts: any = {}) { args[opts.errorIndex] = reject; } - let pluginInstance = get(window, pluginObj.pluginRef); + let pluginInstance = getPlugin(pluginObj.pluginRef); if(!pluginInstance) { - console.warn('Native: tried calling ' + pluginObj.name + '.' + methodName + ', but the ' + pluginObj.name + ' plugin is not installed. Install the ' + pluginObj.plugin + ' plugin'); + pluginWarn(pluginObj.name, methodName, pluginObj.name); reject({ error: 'plugin_not_installed' }); @@ -36,15 +61,6 @@ export const wrap = function(pluginObj, methodName, opts: any = {}) { } } -class PluginDecotor { - cls: any; - config: any; - - constructor(cls, config) { - this.cls = cls; - this.config = config; - } -} export function Plugin(config) { return function(cls) { @@ -62,7 +78,27 @@ export function Cordova(opts:any = {}) { if(opts.promise) { console.log('TODO: Promise'); } - obj[methodName] = wrap(obj, methodName, opts).bind(obj); } } + +export function RequiresPlugin(target: Function, key: string, descriptor: TypedPropertyDescriptor) { + let originalMethod = descriptor.value; + + descriptor.value = function(...args: any[]) { + console.log('Calling', this); + if(!window.cordova) { + cordovaWarn(this.name, null); + return; + } + + let pluginInstance = getPlugin(this.pluginRef); + if(!pluginInstance) { + pluginWarn(this.name, null, this.name); + return; + } + originalMethod.apply(this, args); + } + + return descriptor; +} diff --git a/tsconfig.json b/tsconfig.json index 1c2845dc5..6372caf55 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,6 +19,7 @@ "src/plugin-config.ts", "src/plugins/actionsheet.ts", "src/plugins/camera.ts", + "src/plugins/device.ts", "src/plugins/plugin.ts", "src/plugins/statusbar.ts", "src/plugins/toast.ts",