This commit is contained in:
Ibrahim Hadeed 2016-06-11 00:33:34 -04:00
commit 29d5632d62
10 changed files with 252 additions and 136 deletions

View File

@ -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. 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 ### '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. 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.

View File

@ -23,8 +23,7 @@ Geolocation.getCurrentPosition().then(pos => {
console.log('lat: ' + pos.coords.latitude + ', lon: ' + pos.coords.longitude); console.log('lat: ' + pos.coords.latitude + ', lon: ' + pos.coords.longitude);
}); });
let watch = Geolocation.watchPosition(); let watch = Geolocation.watchPosition().subscribe(pos => {
watch.subscribe(pos => {
console.log('lat: ' + pos.coords.latitude + ', lon: ' + pos.coords.longitude); console.log('lat: ' + pos.coords.latitude + ', lon: ' + pos.coords.longitude);
}); });

View File

@ -22,6 +22,7 @@ module.exports = function(currentVersion) {
.processor(require('./processors/jekyll')) .processor(require('./processors/jekyll'))
.processor(require('./processors/remove-private-members')) .processor(require('./processors/remove-private-members'))
.processor(require('./processors/hide-private-api')) .processor(require('./processors/hide-private-api'))
.processor(require('./processors/collect-inputs-outputs'))
// for debugging docs // for debugging docs
// .processor(function test(){ // .processor(function test(){

View File

@ -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;
}
});
}
};
};

View File

@ -55,13 +55,13 @@ docType: "<$ doc.docType $>"
<@- macro functionSyntax(fn) @> <@- macro functionSyntax(fn) @>
<@- set sep = joiner(',&nbsp;') -@> <@- set sep = joiner(',&nbsp;') -@>
<code><$ fn.name $>(<@- for param in fn.params @><$ sep() $> <code><$ fn.name $><@- if not fn.isProperty @>(<@ endif -@><@- for param in fn.params @><$ sep() $>
<@- if param.type.optional @>[<@ endif -@> <@- if param.type.optional @>[<@ endif -@>
<$ param.name $> <$ param.name $>
<@- if param.type.optional @>]<@ endif -@> <@- if param.type.optional @>]<@ endif -@>
<@ endfor @>)</code> <@ endfor @><@- if not fn.isProperty @>)<@ endif -@></code>
<@ if fn.alias @><small>(alias: <$ fn.alias $>)</small><@ endif @> <@ if fn.alias @><small>(alias: <$ fn.alias $>)</small><@ endif @>
<@ endmacro -@> <@ endmacro -@>
<@ macro typeList(types) -@> <@ macro typeList(types) -@>
@ -203,7 +203,7 @@ docType: "<$ doc.docType $>"
<@ endif @> <@ endif @>
<@- if doc.statics.length -@> <@- if doc.statics.length -@>
<h2>Static Methods</h2> <h2>Static Members</h2>
<@- for method in doc.statics @><@ if not method.internal @> <@- for method in doc.statics @><@ if not method.internal @>
<div id="<$ method.name $>"></div> <div id="<$ method.name $>"></div>
<h3><$ functionSyntax(method) $></h3> <h3><$ functionSyntax(method) $></h3>
@ -244,7 +244,7 @@ docType: "<$ doc.docType $>"
<!-- methods on the class --> <!-- methods on the class -->
<@- if doc.members and doc.members.length @> <@- if doc.members and doc.members.length @>
<h2>Instance Methods</h2> <h2>Instance Members</h2>
<@- for method in doc.members @> <@- for method in doc.members @>
<div id="<$ method.name $>"></div> <div id="<$ method.name $>"></div>

View File

@ -68,6 +68,7 @@ import {WebIntent} from './plugins/webintent';
export * from './plugins/googlemaps'; export * from './plugins/googlemaps';
export * from './plugins/3dtouch'; export * from './plugins/3dtouch';
export * from './plugins/httpd'; export * from './plugins/httpd';
export * from './plugins/contacts';
export { export {
ActionSheet, ActionSheet,
AdMob, AdMob,

View File

@ -1,6 +1,7 @@
import {Plugin, Cordova} from './plugin'; import {Plugin, Cordova, InstanceProperty, CordovaInstance} from './plugin';
declare var window: any,
export interface ContactProperties { navigator: any;
export interface IContactProperties {
/** A globally unique identifier. */ /** A globally unique identifier. */
id?: string; id?: string;
/** The name of this Contact, suitable for display to end users. */ /** 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. */ /** A casual name by which to address the contact. */
nickname?: string; nickname?: string;
/** An array of all the contact's phone numbers. */ /** An array of all the contact's phone numbers. */
phoneNumbers?: ContactField[]; phoneNumbers?: IContactField[];
/** An array of all the contact's email addresses. */ /** An array of all the contact's email addresses. */
emails?: ContactField[]; emails?: IContactField[];
/** An array of all the contact's addresses. */ /** An array of all the contact's addresses. */
addresses?: ContactAddress[]; addresses?: ContactAddress[];
/** An array of all the contact's IM addresses. */ /** An array of all the contact's IM addresses. */
ims?: ContactField[]; ims?: IContactField[];
/** An array of all the contact's organizations. */ /** An array of all the contact's organizations. */
organizations?: ContactOrganization[]; organizations?: ContactOrganization[];
/** The birthday of the contact. */ /** The birthday of the contact. */
@ -24,45 +25,51 @@ export interface ContactProperties {
/** A note about the contact. */ /** A note about the contact. */
note?: string; note?: string;
/** An array of the contact's photos. */ /** An array of the contact's photos. */
photos?: ContactField[]; photos?: IContactField[];
/** An array of all the user-defined categories associated with the contact. */ /** 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. */ /** An array of web pages associated with the contact. */
urls?: ContactField[]; urls?: IContactField[];
} }
export class Contact {
export interface Contact extends ContactProperties { private _objectInstance: any;
/** @InstanceProperty get id(): string {return; }
* Returns a new Contact object that is a deep copy of the calling object, with the id property set to null @InstanceProperty get displayName(): string {return; }
*/ @InstanceProperty get nickname(): ContactName {return; }
clone(): Contact; @InstanceProperty get phoneNumbers(): string {return; }
/** @InstanceProperty get emails(): IContactField[] {return; }
* Removes the contact from the device contacts database, otherwise executes an error callback with a ContactError object. @InstanceProperty get addresses(): ContactAddress[] {return; }
* @param onSuccess Success callback function invoked on success operation. @InstanceProperty get ims(): IContactField[] {return; }
* @param onError Error callback function, invoked when an error occurs. @InstanceProperty get organizations(): ContactOrganization[] {return; }
*/ @InstanceProperty get birthday(): Date {return; }
remove( @InstanceProperty get note(): string {return; }
onSuccess?: () => void, @InstanceProperty get photos(): IContactField[] {return; }
onError?: (error: Error) => void): void; @InstanceProperty get categories(): IContactField[] {return; }
/** @InstanceProperty get urls(): IContactField[] {return; }
* Saves a new contact to the device contacts database, or updates an existing contact if a contact with the same id already exists. constructor () {
* @param onSuccess Success callback function invoked on success operation with che Contact object. this._objectInstance = navigator.contacts.create();
* @param onError Error callback function, invoked when an error occurs. }
*/ clone(): Contact {
save( let newContact = new Contact();
onSuccess?: (contact: Contact) => void, for (let prop in this) {
onError?: (error: Error) => void): void; if (prop === 'id') return;
newContact[prop] = this[prop];
}
return newContact;
}
@CordovaInstance()
remove(): Promise<any> {return; }
@CordovaInstance()
save(): Promise<any> {return; }
} }
interface IContactError {
interface ContactError {
/** Error code */ /** Error code */
code: number; code: number;
/** Error message */ /** Error message */
message: string; message: string;
} }
declare var ContactError: { declare var ContactError: {
new(code: number): ContactError; new(code: number): IContactError;
UNKNOWN_ERROR: number; UNKNOWN_ERROR: number;
INVALID_ARGUMENT_ERROR: number; INVALID_ARGUMENT_ERROR: number;
TIMEOUT_ERROR: number; TIMEOUT_ERROR: number;
@ -71,8 +78,7 @@ declare var ContactError: {
NOT_SUPPORTED_ERROR: number; NOT_SUPPORTED_ERROR: number;
PERMISSION_DENIED_ERROR: number PERMISSION_DENIED_ERROR: number
}; };
export interface IContactName {
export interface ContactName {
/** The complete name of the contact. */ /** The complete name of the contact. */
formatted?: string; formatted?: string;
/** The contact's family name. */ /** The contact's family name. */
@ -86,18 +92,20 @@ export interface ContactName {
/** The contact's suffix (example Esq.). */ /** The contact's suffix (example Esq.). */
honorificSuffix?: string; 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: { export interface IContactField {
/** Constructor for ContactName object */
new(formatted?: string,
familyName?: string,
givenName?: string,
middleName?: string,
honorificPrefix?: string,
honorificSuffix?: string): ContactName
};
export interface ContactField {
/** A string that indicates what type of field this is, home for example. */ /** A string that indicates what type of field this is, home for example. */
type: string; type: string;
/** The value of the field, such as a phone number or email address. */ /** The value of the field, such as a phone number or email address. */
@ -106,14 +114,17 @@ export interface ContactField {
pref: boolean; pref: boolean;
} }
declare var ContactField: { export class ContactField implements IContactField {
/** Constructor for ContactField object */ private _objectInstance: any;
new(type?: string, constructor(type?: string, value?: string, pref?: boolean) {
value?: string, this._objectInstance = new window.ContactField(type, value, pref);
pref?: boolean): ContactField }
}; @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. */ /** Set to true if this ContactAddress contains the user's preferred value. */
pref?: boolean; pref?: boolean;
/** A string indicating what type of field this is, home for example. */ /** A string indicating what type of field this is, home for example. */
@ -132,19 +143,29 @@ export interface ContactAddress {
country?: string; country?: string;
} }
declare var ContactAddress: { export class ContactAddress implements IContactAddress {
/** Constructor of ContactAddress object */ private _objectInstance: any;
new(pref?: boolean, constructor (pref?: boolean,
type?: string, type?: string,
formatted?: string, formatted?: string,
streetAddress?: string, streetAddress?: string,
locality?: string, locality?: string,
region?: string, region?: string,
postalCode?: string, postalCode?: string,
country?: string): ContactAddress 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. */ /** Set to true if this ContactOrganization contains the user's preferred value. */
pref?: boolean; pref?: boolean;
/** A string that indicates what type of field this is, home for example. */ /** A string that indicates what type of field this is, home for example. */
@ -157,17 +178,20 @@ export interface ContactOrganization {
title?: string; title?: string;
} }
declare var ContactOrganization: { export class ContactOrganization implements IContactOrganization {
/** Constructor for ContactOrganization object */ private _objectInstance: any;
new(pref?: boolean, constructor () {
type?: string, this._objectInstance = new window.ContactOrganization();
name?: string, }
department?: string, @InstanceProperty get pref(): boolean {return; }
title?: string): ContactOrganization @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. */ /** Search options to filter navigator.contacts. */
interface ContactFindOptions { export interface IContactFindOptions {
/** The search string used to find navigator.contacts. */ /** The search string used to find navigator.contacts. */
filter?: string; filter?: string;
/** Determines if the find operation returns multiple navigator.contacts. */ /** Determines if the find operation returns multiple navigator.contacts. */
@ -176,35 +200,34 @@ interface ContactFindOptions {
desiredFields?: string[]; desiredFields?: string[];
} }
declare var ContactFindOptions: { export class ContactFindOptions implements IContactFindOptions {
/** Constructor for ContactFindOptions object */ private _objectInstance: any;
new(filter?: string, constructor () {
multiple?: boolean, this._objectInstance = new window.ContactFindOptions();
desiredFields?: string[]): ContactFindOptions }
}; @InstanceProperty get filter(): string {return; }
@InstanceProperty get multiple(): boolean {return; }
declare var Contact: { @InstanceProperty get desiredFields(): any {return; }
new(): Contact @InstanceProperty get hasPhoneNumber(): boolean {return; }
}; }
/** /**
* @name Contacts * @name Contacts
* @description * @description
* Access and manage Contacts on the device. * 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 * @usage
* *
* ```js * ```js
* import {Contacts} from 'ionic-native'; * import {Contact} from 'ionic-native';
* *
* *
* *
* Contacts.create({ * let contact = new Contact();
* displayName: "Mr. Ionitron" * contact.displayName = "Mr. Ionitron";
* }).then((contact) => {}, (err) => {}) * 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' repo: 'https://github.com/apache/cordova-plugin-contacts'
}) })
export class Contacts { export class Contacts {
/** static create(): Contact {
* Create a new Contact object. return new Contact();
* }
* @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();
};
/** /**
* Search for contacts in the Contacts list. * Search for contacts in the Contacts list.
* *
@ -250,12 +263,10 @@ export class Contacts {
errorIndex: 2 errorIndex: 2
}) })
static find(fields: string[], options?: any): Promise<any> { return; } static find(fields: string[], options?: any): Promise<any> { return; }
/** /**
* Select a single Contact. * Select a single Contact.
* @return Returns a Promise that resolves with the selected Contact * @return Returns a Promise that resolves with the selected Contact
*/ */
@Cordova() @Cordova()
static pickContact(): Promise<any> { return; } static pickContact(): Promise<any> {return; }
} }

View File

@ -5,14 +5,19 @@ export interface DeeplinkMatch {
/** /**
* The route info for the matched route * 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 * any internal native data available as "extras" at the time
* the route was matched (for example, Facebook sometimes adds extra data) * the route was matched (for example, Facebook sometimes adds extra data)
*/ */
args: any; $link: any;
} }
/** /**

View File

@ -1,4 +1,5 @@
import {CordovaInstance, Plugin} from './plugin'; import {CordovaInstance, Plugin} from './plugin';
import {Observable} from 'rxjs/Observable';
declare var Media: any; declare var Media: any;
/** /**
* @name MediaPlugin * @name MediaPlugin
@ -8,23 +9,47 @@ declare var Media: any;
* import {MediaPlugin} from 'ionic-native'; * import {MediaPlugin} from 'ionic-native';
* *
* *
* ...
* *
* * // Create a MediaPlugin instance. Expects path to file or url as argument
* // Playing a file
* var file = new MediaPlugin("path/to/file.mp3"); * 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 * // play the file
* file.play(); * 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); * file.seekTo(10000);
* *
* // stop plying the file * // stop playing the file
* file.stop(); * 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 * // Recording to a file
* var newFile = new MediaPlugin("path/to/file.mp3"); * var newFile = new MediaPlugin("path/to/file.mp3");
@ -52,6 +77,8 @@ export class MediaPlugin {
// Properties // Properties
private _objectInstance: any; private _objectInstance: any;
status: Observable<any>;
init: Promise<any>;
// Methods // Methods
/** /**
@ -59,8 +86,12 @@ export class MediaPlugin {
* @param src {string} A URI containing the audio content. * @param src {string} A URI containing the audio content.
*/ */
constructor (src: string) { constructor (src: string) {
// TODO handle success, error, and status let res, rej, next;
this._objectInstance = new Media(src); this.init = new Promise<any>((resolve, reject) => {res = resolve; rej = reject; });
this.status = new Observable((observer) => {
next = data => observer.next(data);
});
this._objectInstance = new Media(src, res, rej, next);
} }
/** /**

View File

@ -141,10 +141,12 @@ function wrapObservable(pluginObj: any, methodName: string, args: any[], opts: a
return () => { return () => {
try { try {
if (opts.clearWithArgs) { if (opts.clearFunction) {
return get(window, pluginObj.pluginRef)[opts.clearFunction].apply(pluginObj, args); 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) { } catch (e) {
console.warn('Unable to clear the previous observable watch for', pluginObj.name, methodName); console.warn('Unable to clear the previous observable watch for', pluginObj.name, methodName);
console.error(e); console.error(e);
@ -323,13 +325,13 @@ export function CordovaProperty(target: Function, key: string, descriptor: Typed
* @param descriptor * @param descriptor
* @constructor * @constructor
*/ */
export function InstanceProperty(target: Function, key: string, descriptor: TypedPropertyDescriptor<any>) { export function InstanceProperty(target: any, key: string, descriptor: TypedPropertyDescriptor<any>) {
descriptor.get = function() { descriptor.get = function() {
return this._objectInstance[key]; return this._objectInstance[key];
}; };
descriptor.set = function(...args: any[]) { descriptor.set = function(...args: any[]) {
return this._objectInstance[key] = args[0]; this._objectInstance[key] = args[0];
}; };
return descriptor; return descriptor;