diff --git a/DEVELOPER.md b/DEVELOPER.md
index fcd2cfc30..a71660f6d 100644
--- a/DEVELOPER.md
+++ b/DEVELOPER.md
@@ -96,6 +96,10 @@ The `@Cordova` decorator has a few more options now.
You need to run `npm run build_bundle` in the `ionic-native` project, this will create a `dist` directory. Then, you must go to your ionic application folder and replace your current `node_modules/ionic-native/dist/` with the newly generated one.
+### Cleaning the code
+
+You need to run `gulp tslint` to analyze the code and ensure it's consitency with the repository style. Fix any errors before submitting a PR.
+
### 'Wrapping' Up
That's it! The only thing left to do is rigorously document the plugin and it's usage. Take a look at some of the other plugins for good documentation styles.
diff --git a/README.md b/README.md
index 3fcc8b0ee..2da5cf8ed 100644
--- a/README.md
+++ b/README.md
@@ -23,8 +23,7 @@ Geolocation.getCurrentPosition().then(pos => {
console.log('lat: ' + pos.coords.latitude + ', lon: ' + pos.coords.longitude);
});
-let watch = Geolocation.watchPosition();
-watch.subscribe(pos => {
+let watch = Geolocation.watchPosition().subscribe(pos => {
console.log('lat: ' + pos.coords.latitude + ', lon: ' + pos.coords.longitude);
});
diff --git a/scripts/docs/dgeni-config.js b/scripts/docs/dgeni-config.js
index 2281a052a..a0cf4217c 100644
--- a/scripts/docs/dgeni-config.js
+++ b/scripts/docs/dgeni-config.js
@@ -22,6 +22,7 @@ module.exports = function(currentVersion) {
.processor(require('./processors/jekyll'))
.processor(require('./processors/remove-private-members'))
.processor(require('./processors/hide-private-api'))
+.processor(require('./processors/collect-inputs-outputs'))
// for debugging docs
// .processor(function test(){
diff --git a/scripts/docs/processors/collect-inputs-outputs.js b/scripts/docs/processors/collect-inputs-outputs.js
new file mode 100644
index 000000000..c8b382e65
--- /dev/null
+++ b/scripts/docs/processors/collect-inputs-outputs.js
@@ -0,0 +1,62 @@
+module.exports = function collectInputsOutputs() {
+ return {
+
+ $runBefore: ['rendering-docs'],
+ $process: function(docs) {
+ docs.forEach(function(doc) {
+
+ if (doc.members && doc.members.length) {
+ var members = [];
+ var inputs = [];
+ var outputs = [];
+
+ memberLoop:
+ for (var i in doc.members) {
+
+ // identify properties to differentiate from methods
+ if (typeof doc.members[i].parameters == 'undefined') {
+ doc.members[i].isProperty = true;
+ }
+
+ if (doc.members[i].decorators && doc.members[i].decorators.length) {
+
+ decoratorLoop:
+ for (var ii in doc.members[i].decorators) {
+
+ if (doc.members[i].decorators[ii].name == 'Input') {
+ inputs.push(parseMember(doc.members[i]));
+ continue memberLoop;
+ }
+ if (doc.members[i].decorators[ii].name == 'Output') {
+ outputs.push(parseMember(doc.members[i]));
+ continue memberLoop;
+ }
+ }
+ // not an input or output, must be a plain member
+ members.push(doc.members[i]);
+ } else {
+ members.push(doc.members[i]);
+ };
+ }
+
+ // update doc with pruned members list and add inputs and outputs
+ doc.members = members;
+ doc.inputs = inputs;
+ doc.outputs = outputs;
+ }
+
+ function parseMember(member) {
+ member.type = member.content.substring(
+ member.content.indexOf('{') + 1,
+ member.content.indexOf('}')
+ );
+ member.description = member.content.substring(
+ member.content.indexOf('}') + 1,
+ member.content.length
+ );
+ return member;
+ }
+ });
+ }
+ };
+};
diff --git a/scripts/docs/templates/common.template.html b/scripts/docs/templates/common.template.html
index 4354f8c1d..886f84874 100644
--- a/scripts/docs/templates/common.template.html
+++ b/scripts/docs/templates/common.template.html
@@ -55,13 +55,13 @@ docType: "<$ doc.docType $>"
<@- macro functionSyntax(fn) @>
-<@- set sep = joiner(', ') -@>
-<$ fn.name $>(<@- for param in fn.params @><$ sep() $>
+ <@- set sep = joiner(', ') -@>
+ <$ fn.name $><@- if not fn.isProperty @>(<@ endif -@><@- for param in fn.params @><$ sep() $>
<@- if param.type.optional @>[<@ endif -@>
<$ param.name $>
<@- if param.type.optional @>]<@ endif -@>
- <@ endfor @>)
-<@ if fn.alias @>(alias: <$ fn.alias $>)<@ endif @>
+ <@ endfor @><@- if not fn.isProperty @>)<@ endif -@>
+ <@ if fn.alias @>(alias: <$ fn.alias $>)<@ endif @>
<@ endmacro -@>
<@ macro typeList(types) -@>
@@ -203,7 +203,7 @@ docType: "<$ doc.docType $>"
<@ endif @>
<@- if doc.statics.length -@>
-
Static Methods
+Static Members
<@- for method in doc.statics @><@ if not method.internal @>
<$ functionSyntax(method) $>
@@ -244,7 +244,7 @@ docType: "<$ doc.docType $>"
<@- if doc.members and doc.members.length @>
-Instance Methods
+Instance Members
<@- for method in doc.members @>
diff --git a/src/index.ts b/src/index.ts
index 68e4b0c62..1b04fb6d6 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -68,6 +68,7 @@ import {WebIntent} from './plugins/webintent';
export * from './plugins/googlemaps';
export * from './plugins/3dtouch';
export * from './plugins/httpd';
+export * from './plugins/contacts';
export {
ActionSheet,
AdMob,
diff --git a/src/plugins/contacts.ts b/src/plugins/contacts.ts
index 16299330a..17c8cb675 100644
--- a/src/plugins/contacts.ts
+++ b/src/plugins/contacts.ts
@@ -1,6 +1,7 @@
-import {Plugin, Cordova} from './plugin';
-
-export interface ContactProperties {
+import {Plugin, Cordova, InstanceProperty, CordovaInstance} from './plugin';
+declare var window: any,
+ navigator: any;
+export interface IContactProperties {
/** A globally unique identifier. */
id?: string;
/** The name of this Contact, suitable for display to end users. */
@@ -10,13 +11,13 @@ export interface ContactProperties {
/** A casual name by which to address the contact. */
nickname?: string;
/** An array of all the contact's phone numbers. */
- phoneNumbers?: ContactField[];
+ phoneNumbers?: IContactField[];
/** An array of all the contact's email addresses. */
- emails?: ContactField[];
+ emails?: IContactField[];
/** An array of all the contact's addresses. */
addresses?: ContactAddress[];
/** An array of all the contact's IM addresses. */
- ims?: ContactField[];
+ ims?: IContactField[];
/** An array of all the contact's organizations. */
organizations?: ContactOrganization[];
/** The birthday of the contact. */
@@ -24,45 +25,51 @@ export interface ContactProperties {
/** A note about the contact. */
note?: string;
/** An array of the contact's photos. */
- photos?: ContactField[];
+ photos?: IContactField[];
/** An array of all the user-defined categories associated with the contact. */
- categories?: ContactField[];
+ categories?: IContactField[];
/** An array of web pages associated with the contact. */
- urls?: ContactField[];
+ urls?: IContactField[];
}
-
-export interface Contact extends ContactProperties {
- /**
- * Returns a new Contact object that is a deep copy of the calling object, with the id property set to null
- */
- clone(): Contact;
- /**
- * Removes the contact from the device contacts database, otherwise executes an error callback with a ContactError object.
- * @param onSuccess Success callback function invoked on success operation.
- * @param onError Error callback function, invoked when an error occurs.
- */
- remove(
- onSuccess?: () => void,
- onError?: (error: Error) => void): void;
- /**
- * Saves a new contact to the device contacts database, or updates an existing contact if a contact with the same id already exists.
- * @param onSuccess Success callback function invoked on success operation with che Contact object.
- * @param onError Error callback function, invoked when an error occurs.
- */
- save(
- onSuccess?: (contact: Contact) => void,
- onError?: (error: Error) => void): void;
+export class Contact {
+ private _objectInstance: any;
+ @InstanceProperty get id(): string {return; }
+ @InstanceProperty get displayName(): string {return; }
+ @InstanceProperty get nickname(): ContactName {return; }
+ @InstanceProperty get phoneNumbers(): string {return; }
+ @InstanceProperty get emails(): IContactField[] {return; }
+ @InstanceProperty get addresses(): ContactAddress[] {return; }
+ @InstanceProperty get ims(): IContactField[] {return; }
+ @InstanceProperty get organizations(): ContactOrganization[] {return; }
+ @InstanceProperty get birthday(): Date {return; }
+ @InstanceProperty get note(): string {return; }
+ @InstanceProperty get photos(): IContactField[] {return; }
+ @InstanceProperty get categories(): IContactField[] {return; }
+ @InstanceProperty get urls(): IContactField[] {return; }
+ constructor () {
+ this._objectInstance = navigator.contacts.create();
+ }
+ clone(): Contact {
+ let newContact = new Contact();
+ for (let prop in this) {
+ if (prop === 'id') return;
+ newContact[prop] = this[prop];
+ }
+ return newContact;
+ }
+ @CordovaInstance()
+ remove(): Promise {return; }
+ @CordovaInstance()
+ save(): Promise {return; }
}
-
-interface ContactError {
+interface IContactError {
/** Error code */
code: number;
/** Error message */
message: string;
}
-
declare var ContactError: {
- new(code: number): ContactError;
+ new(code: number): IContactError;
UNKNOWN_ERROR: number;
INVALID_ARGUMENT_ERROR: number;
TIMEOUT_ERROR: number;
@@ -71,8 +78,7 @@ declare var ContactError: {
NOT_SUPPORTED_ERROR: number;
PERMISSION_DENIED_ERROR: number
};
-
-export interface ContactName {
+export interface IContactName {
/** The complete name of the contact. */
formatted?: string;
/** The contact's family name. */
@@ -86,18 +92,20 @@ export interface ContactName {
/** The contact's suffix (example Esq.). */
honorificSuffix?: string;
}
+export class ContactName implements IContactName {
+ private _objectInstance: any;
+ constructor(formatted?: string, familyName?: string, givenName?: string, middleName?: string, honorificPrefix?: string, honorificSuffix?: string) {
+ this._objectInstance = new window.ContactName(formatted, familyName, givenName, middleName, honorificPrefix, honorificSuffix);
+ }
+ @InstanceProperty get formatted(): string {return; }
+ @InstanceProperty get familyName(): string {return; }
+ @InstanceProperty get givenName(): string {return; }
+ @InstanceProperty get middleName(): string {return; }
+ @InstanceProperty get honorificPrefix(): string {return; }
+ @InstanceProperty get honorificSuffix(): string {return; }
+}
-declare var ContactName: {
- /** Constructor for ContactName object */
- new(formatted?: string,
- familyName?: string,
- givenName?: string,
- middleName?: string,
- honorificPrefix?: string,
- honorificSuffix?: string): ContactName
-};
-
-export interface ContactField {
+export interface IContactField {
/** A string that indicates what type of field this is, home for example. */
type: string;
/** The value of the field, such as a phone number or email address. */
@@ -106,14 +114,17 @@ export interface ContactField {
pref: boolean;
}
-declare var ContactField: {
- /** Constructor for ContactField object */
- new(type?: string,
- value?: string,
- pref?: boolean): ContactField
-};
+export class ContactField implements IContactField {
+ private _objectInstance: any;
+ constructor(type?: string, value?: string, pref?: boolean) {
+ this._objectInstance = new window.ContactField(type, value, pref);
+ }
+ @InstanceProperty get type(): string {return; }
+ @InstanceProperty get value(): string {return; }
+ @InstanceProperty get pref(): boolean {return; }
+}
-export interface ContactAddress {
+export interface IContactAddress {
/** Set to true if this ContactAddress contains the user's preferred value. */
pref?: boolean;
/** A string indicating what type of field this is, home for example. */
@@ -132,19 +143,29 @@ export interface ContactAddress {
country?: string;
}
-declare var ContactAddress: {
- /** Constructor of ContactAddress object */
- new(pref?: boolean,
- type?: string,
- formatted?: string,
- streetAddress?: string,
- locality?: string,
- region?: string,
- postalCode?: string,
- country?: string): ContactAddress
-};
+export class ContactAddress implements IContactAddress {
+ private _objectInstance: any;
+ constructor (pref?: boolean,
+ type?: string,
+ formatted?: string,
+ streetAddress?: string,
+ locality?: string,
+ region?: string,
+ postalCode?: string,
+ country?: string) {
+ this._objectInstance = new window.ContactAddress(pref, type, formatted, streetAddress, locality, region, postalCode, country);
+ }
+ @InstanceProperty get pref(): boolean {return; }
+ @InstanceProperty get type(): string {return; }
+ @InstanceProperty get formatted(): string {return; }
+ @InstanceProperty get streetAddress(): string {return; }
+ @InstanceProperty get locality(): string {return; }
+ @InstanceProperty get region(): string {return; }
+ @InstanceProperty get postalCode(): string {return; }
+ @InstanceProperty get country(): string {return; }
+}
-export interface ContactOrganization {
+export interface IContactOrganization {
/** Set to true if this ContactOrganization contains the user's preferred value. */
pref?: boolean;
/** A string that indicates what type of field this is, home for example. */
@@ -157,17 +178,20 @@ export interface ContactOrganization {
title?: string;
}
-declare var ContactOrganization: {
- /** Constructor for ContactOrganization object */
- new(pref?: boolean,
- type?: string,
- name?: string,
- department?: string,
- title?: string): ContactOrganization
-};
+export class ContactOrganization implements IContactOrganization {
+ private _objectInstance: any;
+ constructor () {
+ this._objectInstance = new window.ContactOrganization();
+ }
+ @InstanceProperty get pref(): boolean {return; }
+ @InstanceProperty get type(): string {return; }
+ @InstanceProperty get name(): string {return; }
+ @InstanceProperty get department(): string {return; }
+ @InstanceProperty get title(): string {return; }
+}
/** Search options to filter navigator.contacts. */
-interface ContactFindOptions {
+export interface IContactFindOptions {
/** The search string used to find navigator.contacts. */
filter?: string;
/** Determines if the find operation returns multiple navigator.contacts. */
@@ -176,35 +200,34 @@ interface ContactFindOptions {
desiredFields?: string[];
}
-declare var ContactFindOptions: {
- /** Constructor for ContactFindOptions object */
- new(filter?: string,
- multiple?: boolean,
- desiredFields?: string[]): ContactFindOptions
-};
-
-declare var Contact: {
- new(): Contact
-};
-
+export class ContactFindOptions implements IContactFindOptions {
+ private _objectInstance: any;
+ constructor () {
+ this._objectInstance = new window.ContactFindOptions();
+ }
+ @InstanceProperty get filter(): string {return; }
+ @InstanceProperty get multiple(): boolean {return; }
+ @InstanceProperty get desiredFields(): any {return; }
+ @InstanceProperty get hasPhoneNumber(): boolean {return; }
+}
/**
* @name Contacts
* @description
* Access and manage Contacts on the device.
*
- * Requires plugin: `cordova-plugin-contacts`
- * For full info, please see the [Cordova Contacts plugin docs](https://github.com/apache/cordova-plugin-contacts)
- *
* @usage
*
* ```js
- * import {Contacts} from 'ionic-native';
+ * import {Contact} from 'ionic-native';
*
*
*
- * Contacts.create({
- * displayName: "Mr. Ionitron"
- * }).then((contact) => {}, (err) => {})
+ * let contact = new Contact();
+ * contact.displayName = "Mr. Ionitron";
+ * contact.save().then(
+ * () => console.log("Contact saved!", contact),
+ * (error: any) => console.error("Error saving contact.", error)
+ * );
* ```
*
*
@@ -215,19 +238,9 @@ declare var Contact: {
repo: 'https://github.com/apache/cordova-plugin-contacts'
})
export class Contacts {
- /**
- * Create a new Contact object.
- *
- * @param options {Object} Object whose properties the created Contact should have.
- * @return {Contact} Returns the created contact
- */
- @Cordova({
- sync: true
- })
- static create(options: ContactProperties) {
- return new Contact();
- };
-
+ static create(): Contact {
+ return new Contact();
+ }
/**
* Search for contacts in the Contacts list.
*
@@ -250,12 +263,10 @@ export class Contacts {
errorIndex: 2
})
static find(fields: string[], options?: any): Promise { return; }
-
-
/**
* Select a single Contact.
* @return Returns a Promise that resolves with the selected Contact
*/
@Cordova()
- static pickContact(): Promise { return; }
-}
+ static pickContact(): Promise {return; }
+}
\ No newline at end of file
diff --git a/src/plugins/deeplinks.ts b/src/plugins/deeplinks.ts
index 5bb060f69..d27d7da67 100644
--- a/src/plugins/deeplinks.ts
+++ b/src/plugins/deeplinks.ts
@@ -5,14 +5,19 @@ export interface DeeplinkMatch {
/**
* The route info for the matched route
*/
- routeInfo: any;
+ $route: any;
/**
- * The arguments passed to the route through GET params along with
+ * Any arguments passed either through route parameters or GET parameters
+ */
+ $args: any;
+
+ /**
+ * The deeplink object processed from the plugin, along with any
* any internal native data available as "extras" at the time
* the route was matched (for example, Facebook sometimes adds extra data)
*/
- args: any;
+ $link: any;
}
/**
diff --git a/src/plugins/media.ts b/src/plugins/media.ts
index 37c7d4715..208987185 100644
--- a/src/plugins/media.ts
+++ b/src/plugins/media.ts
@@ -1,4 +1,5 @@
import {CordovaInstance, Plugin} from './plugin';
+import {Observable} from 'rxjs/Observable';
declare var Media: any;
/**
* @name MediaPlugin
@@ -8,23 +9,47 @@ declare var Media: any;
* import {MediaPlugin} from 'ionic-native';
*
*
- * ...
*
- *
- * // Playing a file
+ * // Create a MediaPlugin instance. Expects path to file or url as argument
* var file = new MediaPlugin("path/to/file.mp3");
*
+ * // Catch the Success & Error Output
+ * // Platform Quirks
+ * // iOS calls success on completion of playback only
+ * // Android calls success on completion of playback AND on release()
+ * file.init.then(() => {
+ * console.log("Playback Finished");
+ * }, (err) => {
+ * console.log("somthing went wrong! error code: "+err.code+" message: "+err.message);
+ * });
+ *
* // play the file
* file.play();
*
- * // skip to 10 seconds
+ * // pause the file
+ * file.pause();
+ *
+ * // get current playback position
+ * file.getCurrentPosition().then((position) => {
+ * console.log(position);
+ * });
+ *
+ * // get file duration
+ * file.getDuration().then((duration) => {
+ * console.log(position);
+ * });
+ *
+ * // skip to 10 seconds (expects int value in ms)
* file.seekTo(10000);
*
- * // stop plying the file
+ * // stop playing the file
* file.stop();
*
- *
- * ...
+ * // release the native audio resource
+ * // Platform Quirks:
+ * // iOS simply create a new instance and the old one will be overwritten
+ * // Android you must call release() to destroy instances of media when you are done
+ * file.release();
*
* // Recording to a file
* var newFile = new MediaPlugin("path/to/file.mp3");
@@ -52,6 +77,8 @@ export class MediaPlugin {
// Properties
private _objectInstance: any;
+ status: Observable;
+ init: Promise;
// Methods
/**
@@ -59,8 +86,12 @@ export class MediaPlugin {
* @param src {string} A URI containing the audio content.
*/
constructor (src: string) {
- // TODO handle success, error, and status
- this._objectInstance = new Media(src);
+ let res, rej, next;
+ this.init = new Promise((resolve, reject) => {res = resolve; rej = reject; });
+ this.status = new Observable((observer) => {
+ next = data => observer.next(data);
+ });
+ this._objectInstance = new Media(src, res, rej, next);
}
/**
diff --git a/src/plugins/plugin.ts b/src/plugins/plugin.ts
index f5b385690..c6b22894b 100644
--- a/src/plugins/plugin.ts
+++ b/src/plugins/plugin.ts
@@ -141,10 +141,12 @@ function wrapObservable(pluginObj: any, methodName: string, args: any[], opts: a
return () => {
try {
- if (opts.clearWithArgs) {
- return get(window, pluginObj.pluginRef)[opts.clearFunction].apply(pluginObj, args);
+ if (opts.clearFunction) {
+ if (opts.clearWithArgs) {
+ return get(window, pluginObj.pluginRef)[opts.clearFunction].apply(pluginObj, args);
+ }
+ return get(window, pluginObj.pluginRef)[opts.clearFunction].call(pluginObj, pluginResult);
}
- return get(window, pluginObj.pluginRef)[opts.clearFunction].call(pluginObj, pluginResult);
} catch (e) {
console.warn('Unable to clear the previous observable watch for', pluginObj.name, methodName);
console.error(e);
@@ -323,13 +325,13 @@ export function CordovaProperty(target: Function, key: string, descriptor: Typed
* @param descriptor
* @constructor
*/
-export function InstanceProperty(target: Function, key: string, descriptor: TypedPropertyDescriptor) {
+export function InstanceProperty(target: any, key: string, descriptor: TypedPropertyDescriptor) {
descriptor.get = function() {
return this._objectInstance[key];
};
descriptor.set = function(...args: any[]) {
- return this._objectInstance[key] = args[0];
+ this._objectInstance[key] = args[0];
};
return descriptor;