You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2013/01/22 02:57:59 UTC
[11/52] [partial] support for 2.4.0rc1. "vendored" the platform libs
in. added Gord and Braden as contributors. removed dependency on unzip and
axed the old download-cordova code.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.h b/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.h
new file mode 100644
index 0000000..0384656
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.h
@@ -0,0 +1,150 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import "CDVPlugin.h"
+
+#define CDV_FORMAT_SHORT 0
+#define CDV_FORMAT_MEDIUM 1
+#define CDV_FORMAT_LONG 2
+#define CDV_FORMAT_FULL 3
+#define CDV_SELECTOR_MONTHS 0
+#define CDV_SELECTOR_DAYS 1
+
+enum CDVGlobalizationError {
+ CDV_UNKNOWN_ERROR = 0,
+ CDV_FORMATTING_ERROR = 1,
+ CDV_PARSING_ERROR = 2,
+ CDV_PATTERN_ERROR = 3,
+};
+typedef NSUInteger CDVGlobalizationError;
+
+@interface CDVGlobalization : CDVPlugin {
+ CFLocaleRef currentLocale;
+}
+
+- (void)getPreferredLanguage:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+/**
+ * Returns the string identifier for the clients current locale setting.
+ * It returns the locale identifier string to the successCB callback with a
+ * properties object as a parameter. If there is an error getting the locale,
+ * then the errorCB callback is invoked.
+ */
+- (void)getLocaleName:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+/**
+ * Returns a date formatted as a string according to the clients user preferences and
+ * calendar using the time zone of the client. It returns the formatted date string to the
+ * successCB callback with a properties object as a parameter. If there is an error
+ * formatting the date, then the errorCB callback is invoked.
+ *
+ * options: "date" contains the number of milliseconds that represents the JavaScript date
+ */
+- (void)dateToString:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+/**
+ * Parses a date formatted as a string according to the clients user
+ * preferences and calendar using the time zone of the client and returns
+ * the corresponding date object. It returns the date to the successCB
+ * callback with a properties object as a parameter. If there is an error
+ * parsing the date string, then the errorCB callback is invoked.
+ *
+ * options: "dateString" contains the JavaScript string to parse for a date
+ */
+- (void)stringToDate:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+/**
+ * Returns a pattern string for formatting and parsing dates according to the clients
+ * user preferences. It returns the pattern to the successCB callback with a
+ * properties object as a parameter. If there is an error obtaining the pattern,
+ * then the errorCB callback is invoked.
+ *
+ */
+- (void)getDatePattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+/**
+ * Returns an array of either the names of the months or days of the week
+ * according to the clients user preferences and calendar. It returns the array of names to the
+ * successCB callback with a properties object as a parameter. If there is an error obtaining the
+ * names, then the errorCB callback is invoked.
+ *
+ */
+- (void)getDateNames:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+/**
+ * Returns whether daylight savings time is in effect for a given date using the clients
+ * time zone and calendar. It returns whether or not daylight savings time is in effect
+ * to the successCB callback with a properties object as a parameter. If there is an error
+ * reading the date, then the errorCB callback is invoked.
+ *
+ * options: "date" contains the number of milliseconds that represents the JavaScript date
+ *
+ */
+- (void)isDayLightSavingsTime:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+/**
+ * Returns the first day of the week according to the clients user preferences and calendar.
+ * The days of the week are numbered starting from 1 where 1 is considered to be Sunday.
+ * It returns the day to the successCB callback with a properties object as a parameter.
+ * If there is an error obtaining the pattern, then the errorCB callback is invoked.
+ *
+ */
+- (void)getFirstDayOfWeek:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+/**
+ * Returns a number formatted as a string according to the clients user preferences.
+ * It returns the formatted number string to the successCB callback with a properties object as a
+ * parameter. If there is an error formatting the number, then the errorCB callback is invoked.
+ *
+ * options: "number" contains the JavaScript number to format
+ *
+ */
+- (void)numberToString:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+/**
+ * Parses a number formatted as a string according to the clients user preferences and
+ * returns the corresponding number. It returns the number to the successCB callback with a
+ * properties object as a parameter. If there is an error parsing the number string, then
+ * the errorCB callback is invoked.
+ *
+ * options: "numberString" contains the JavaScript string to parse for a number
+ *
+ */
+- (void)stringToNumber:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+/**
+ * Returns a pattern string for formatting and parsing numbers according to the clients user
+ * preferences. It returns the pattern to the successCB callback with a properties object as a
+ * parameter. If there is an error obtaining the pattern, then the errorCB callback is invoked.
+ *
+ */
+- (void)getNumberPattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+/**
+ * Returns a pattern string for formatting and parsing currency values according to the clients
+ * user preferences and ISO 4217 currency code. It returns the pattern to the successCB callback with a
+ * properties object as a parameter. If there is an error obtaining the pattern, then the errorCB
+ * callback is invoked.
+ *
+ * options: "currencyCode" contains the ISO currency code from JavaScript
+ */
+- (void)getCurrencyPattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m b/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m
new file mode 100644
index 0000000..4d960cd
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m
@@ -0,0 +1,790 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVGlobalization.h"
+
+@implementation CDVGlobalization
+
+- (id)initWithWebView:(UIWebView*)theWebView
+{
+ self = (CDVGlobalization*)[super initWithWebView:theWebView];
+ if (self) {
+ currentLocale = CFLocaleCopyCurrent();
+ }
+ return self;
+}
+
+- (void)getPreferredLanguage:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+ NSString* callbackId = [arguments objectAtIndex:0];
+ CDVPluginResult* result = nil;
+
+ NSLog(@"log1");
+ // Source: http://stackoverflow.com/questions/3910244/getting-current-device-language-in-ios
+ // (should be OK)
+ NSString* language = [[NSLocale preferredLanguages] objectAtIndex:0];
+
+ if (language) {
+ NSDictionary* dictionary = [NSDictionary dictionaryWithObject:language forKey:@"value"];
+
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
+ messageAsDictionary:dictionary];
+ } else {
+ // TBD is this ever expected to happen?
+ NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
+ [dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"];
+ [dictionary setValue:@"Unknown error" forKey:@"message"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:callbackId];
+}
+
+- (void)getLocaleName:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+ CDVPluginResult* result = nil;
+ NSString* callbackId = [arguments objectAtIndex:0];
+ NSDictionary* dictionary = nil;
+
+ NSLocale* locale = [NSLocale currentLocale];
+
+ if (locale) {
+ dictionary = [NSDictionary dictionaryWithObject:[locale localeIdentifier] forKey:@"value"];
+
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
+ } else {
+ NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
+ [dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"];
+ [dictionary setValue:@"Unknown error" forKey:@"message"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:callbackId];
+}
+
+- (void)dateToString:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+ CFDateFormatterStyle style = kCFDateFormatterShortStyle;
+ CFDateFormatterStyle dateStyle = kCFDateFormatterShortStyle;
+ CFDateFormatterStyle timeStyle = kCFDateFormatterShortStyle;
+ NSDate* date = nil;
+ NSString* dateString = nil;
+ CDVPluginResult* result = nil;
+ NSString* callBackId = [arguments objectAtIndex:0];
+
+ id milliseconds = [options valueForKey:@"date"];
+
+ if (milliseconds && [milliseconds isKindOfClass:[NSNumber class]]) {
+ // get the number of seconds since 1970 and create the date object
+ date = [NSDate dateWithTimeIntervalSince1970:[milliseconds doubleValue] / 1000];
+ }
+
+ // see if any options have been specified
+ id items = [options valueForKey:@"options"];
+ if (items && [items isKindOfClass:[NSMutableDictionary class]]) {
+ NSEnumerator* enumerator = [items keyEnumerator];
+ id key;
+
+ // iterate through all the options
+ while ((key = [enumerator nextObject])) {
+ id item = [items valueForKey:key];
+
+ // make sure that only string values are present
+ if ([item isKindOfClass:[NSString class]]) {
+ // get the desired format length
+ if ([key isEqualToString:@"formatLength"]) {
+ if ([item isEqualToString:@"short"]) {
+ style = kCFDateFormatterShortStyle;
+ } else if ([item isEqualToString:@"medium"]) {
+ style = kCFDateFormatterMediumStyle;
+ } else if ([item isEqualToString:@"long"]) {
+ style = kCFDateFormatterLongStyle;
+ } else if ([item isEqualToString:@"full"]) {
+ style = kCFDateFormatterFullStyle;
+ }
+ }
+ // get the type of date and time to generate
+ else if ([key isEqualToString:@"selector"]) {
+ if ([item isEqualToString:@"date"]) {
+ dateStyle = style;
+ timeStyle = kCFDateFormatterNoStyle;
+ } else if ([item isEqualToString:@"time"]) {
+ dateStyle = kCFDateFormatterNoStyle;
+ timeStyle = style;
+ } else if ([item isEqualToString:@"date and time"]) {
+ dateStyle = style;
+ timeStyle = style;
+ }
+ }
+ }
+ }
+ }
+
+ // create the formatter using the user's current default locale and formats for dates and times
+ CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
+ currentLocale,
+ dateStyle,
+ timeStyle);
+ // if we have a valid date object then call the formatter
+ if (date) {
+ dateString = (__bridge_transfer NSString*)CFDateFormatterCreateStringWithDate(kCFAllocatorDefault,
+ formatter,
+ (__bridge CFDateRef)date);
+ }
+
+ // if the date was converted to a string successfully then return the result
+ if (dateString) {
+ NSDictionary* dictionary = [NSDictionary dictionaryWithObject:dateString forKey:@"value"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
+ }
+ // error
+ else {
+ // DLog(@"GlobalizationCommand dateToString unable to format %@", [date description]);
+ NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
+ [dictionary setValue:[NSNumber numberWithInt:CDV_FORMATTING_ERROR] forKey:@"code"];
+ [dictionary setValue:@"Formatting error" forKey:@"message"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:callBackId];
+
+ CFRelease(formatter);
+}
+
+- (void)stringToDate:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+ CFDateFormatterStyle style = kCFDateFormatterShortStyle;
+ CFDateFormatterStyle dateStyle = kCFDateFormatterShortStyle;
+ CFDateFormatterStyle timeStyle = kCFDateFormatterShortStyle;
+ CDVPluginResult* result = nil;
+ NSString* callBackId = [arguments objectAtIndex:0];
+ NSString* dateString = nil;
+ NSDateComponents* comps = nil;
+
+ // get the string that is to be parsed for a date
+ id ms = [options valueForKey:@"dateString"];
+
+ if (ms && [ms isKindOfClass:[NSString class]]) {
+ dateString = ms;
+ }
+
+ // see if any options have been specified
+ id items = [options valueForKey:@"options"];
+ if (items && [items isKindOfClass:[NSMutableDictionary class]]) {
+ NSEnumerator* enumerator = [items keyEnumerator];
+ id key;
+
+ // iterate through all the options
+ while ((key = [enumerator nextObject])) {
+ id item = [items valueForKey:key];
+
+ // make sure that only string values are present
+ if ([item isKindOfClass:[NSString class]]) {
+ // get the desired format length
+ if ([key isEqualToString:@"formatLength"]) {
+ if ([item isEqualToString:@"short"]) {
+ style = kCFDateFormatterShortStyle;
+ } else if ([item isEqualToString:@"medium"]) {
+ style = kCFDateFormatterMediumStyle;
+ } else if ([item isEqualToString:@"long"]) {
+ style = kCFDateFormatterLongStyle;
+ } else if ([item isEqualToString:@"full"]) {
+ style = kCFDateFormatterFullStyle;
+ }
+ }
+ // get the type of date and time to generate
+ else if ([key isEqualToString:@"selector"]) {
+ if ([item isEqualToString:@"date"]) {
+ dateStyle = style;
+ timeStyle = kCFDateFormatterNoStyle;
+ } else if ([item isEqualToString:@"time"]) {
+ dateStyle = kCFDateFormatterNoStyle;
+ timeStyle = style;
+ } else if ([item isEqualToString:@"date and time"]) {
+ dateStyle = style;
+ timeStyle = style;
+ }
+ }
+ }
+ }
+ }
+
+ // get the user's default settings for date and time formats
+ CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
+ currentLocale,
+ dateStyle,
+ timeStyle);
+
+ // set the parsing to be more lenient
+ CFDateFormatterSetProperty(formatter, kCFDateFormatterIsLenient, kCFBooleanTrue);
+
+ // parse tha date and time string
+ CFDateRef date = CFDateFormatterCreateDateFromString(kCFAllocatorDefault,
+ formatter,
+ (__bridge CFStringRef)dateString,
+ NULL);
+
+ // if we were able to parse the date then get the date and time components
+ if (date != NULL) {
+ NSCalendar* calendar = [NSCalendar currentCalendar];
+
+ unsigned unitFlags = NSYearCalendarUnit |
+ NSMonthCalendarUnit |
+ NSDayCalendarUnit |
+ NSHourCalendarUnit |
+ NSMinuteCalendarUnit |
+ NSSecondCalendarUnit;
+
+ comps = [calendar components:unitFlags fromDate:(__bridge NSDate*)date];
+ CFRelease(date);
+ }
+
+ // put the various elements of the date and time into a dictionary
+ if (comps != nil) {
+ NSArray* keys = [NSArray arrayWithObjects:@"year", @"month", @"day", @"hour", @"minute", @"second", @"millisecond", nil];
+ NSArray* values = [NSArray arrayWithObjects:[NSNumber numberWithInt:[comps year]],
+ [NSNumber numberWithInt:[comps month] - 1],
+ [NSNumber numberWithInt:[comps day]],
+ [NSNumber numberWithInt:[comps hour]],
+ [NSNumber numberWithInt:[comps minute]],
+ [NSNumber numberWithInt:[comps second]],
+ [NSNumber numberWithInt:0], /* iOS does not provide milliseconds */
+ nil];
+
+ NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
+ }
+ // error
+ else {
+ // Dlog(@"GlobalizationCommand stringToDate unable to parse %@", dateString);
+ NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
+ [dictionary setValue:[NSNumber numberWithInt:CDV_PARSING_ERROR] forKey:@"code"];
+ [dictionary setValue:@"unable to parse" forKey:@"message"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:callBackId];
+
+ CFRelease(formatter);
+}
+
+- (void)getDatePattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+ CFDateFormatterStyle style = kCFDateFormatterShortStyle;
+ CFDateFormatterStyle dateStyle = kCFDateFormatterShortStyle;
+ CFDateFormatterStyle timeStyle = kCFDateFormatterShortStyle;
+ CDVPluginResult* result = nil;
+ NSString* callBackId = [arguments objectAtIndex:0];
+
+ // see if any options have been specified
+ id items = [options valueForKey:@"options"];
+
+ if (items && [items isKindOfClass:[NSMutableDictionary class]]) {
+ NSEnumerator* enumerator = [items keyEnumerator];
+ id key;
+
+ // iterate through all the options
+ while ((key = [enumerator nextObject])) {
+ id item = [items valueForKey:key];
+
+ // make sure that only string values are present
+ if ([item isKindOfClass:[NSString class]]) {
+ // get the desired format length
+ if ([key isEqualToString:@"formatLength"]) {
+ if ([item isEqualToString:@"short"]) {
+ style = kCFDateFormatterShortStyle;
+ } else if ([item isEqualToString:@"medium"]) {
+ style = kCFDateFormatterMediumStyle;
+ } else if ([item isEqualToString:@"long"]) {
+ style = kCFDateFormatterLongStyle;
+ } else if ([item isEqualToString:@"full"]) {
+ style = kCFDateFormatterFullStyle;
+ }
+ }
+ // get the type of date and time to generate
+ else if ([key isEqualToString:@"selector"]) {
+ if ([item isEqualToString:@"date"]) {
+ dateStyle = style;
+ timeStyle = kCFDateFormatterNoStyle;
+ } else if ([item isEqualToString:@"time"]) {
+ dateStyle = kCFDateFormatterNoStyle;
+ timeStyle = style;
+ } else if ([item isEqualToString:@"date and time"]) {
+ dateStyle = style;
+ timeStyle = style;
+ }
+ }
+ }
+ }
+ }
+
+ // get the user's default settings for date and time formats
+ CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
+ currentLocale,
+ dateStyle,
+ timeStyle);
+
+ // get the date pattern to apply when formatting and parsing
+ CFStringRef datePattern = CFDateFormatterGetFormat(formatter);
+ // get the user's current time zone information
+ CFTimeZoneRef timezone = (CFTimeZoneRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterTimeZone);
+
+ // put the pattern and time zone information into the dictionary
+ if ((datePattern != nil) && (timezone != nil)) {
+ NSArray* keys = [NSArray arrayWithObjects:@"pattern", @"timezone", @"utc_offset", @"dst_offset", nil];
+ NSArray* values = [NSArray arrayWithObjects:((__bridge NSString*)datePattern),
+ [((__bridge NSTimeZone*)timezone)abbreviation],
+ [NSNumber numberWithLong:[((__bridge NSTimeZone*)timezone)secondsFromGMT]],
+ [NSNumber numberWithDouble:[((__bridge NSTimeZone*)timezone)daylightSavingTimeOffset]],
+ nil];
+
+ NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
+ }
+ // error
+ else {
+ NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
+ [dictionary setValue:[NSNumber numberWithInt:CDV_PATTERN_ERROR] forKey:@"code"];
+ [dictionary setValue:@"Pattern error" forKey:@"message"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:callBackId];
+
+ if (timezone) {
+ CFRelease(timezone);
+ }
+ CFRelease(formatter);
+}
+
+- (void)getDateNames:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+ int style = CDV_FORMAT_LONG;
+ int selector = CDV_SELECTOR_MONTHS;
+ CFStringRef dataStyle = kCFDateFormatterMonthSymbols;
+ CDVPluginResult* result = nil;
+ NSString* callBackId = [arguments objectAtIndex:0];
+
+ // see if any options have been specified
+ id items = [options valueForKey:@"options"];
+
+ if (items && [items isKindOfClass:[NSMutableDictionary class]]) {
+ NSEnumerator* enumerator = [items keyEnumerator];
+ id key;
+
+ // iterate through all the options
+ while ((key = [enumerator nextObject])) {
+ id item = [items valueForKey:key];
+
+ // make sure that only string values are present
+ if ([item isKindOfClass:[NSString class]]) {
+ // get the desired type of name
+ if ([key isEqualToString:@"type"]) {
+ if ([item isEqualToString:@"narrow"]) {
+ style = CDV_FORMAT_SHORT;
+ } else if ([item isEqualToString:@"wide"]) {
+ style = CDV_FORMAT_LONG;
+ }
+ }
+ // determine if months or days are needed
+ else if ([key isEqualToString:@"item"]) {
+ if ([item isEqualToString:@"months"]) {
+ selector = CDV_SELECTOR_MONTHS;
+ } else if ([item isEqualToString:@"days"]) {
+ selector = CDV_SELECTOR_DAYS;
+ }
+ }
+ }
+ }
+ }
+
+ CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
+ currentLocale,
+ kCFDateFormatterFullStyle,
+ kCFDateFormatterFullStyle);
+
+ if ((selector == CDV_SELECTOR_MONTHS) && (style == CDV_FORMAT_LONG)) {
+ dataStyle = kCFDateFormatterMonthSymbols;
+ } else if ((selector == CDV_SELECTOR_MONTHS) && (style == CDV_FORMAT_SHORT)) {
+ dataStyle = kCFDateFormatterShortMonthSymbols;
+ } else if ((selector == CDV_SELECTOR_DAYS) && (style == CDV_FORMAT_LONG)) {
+ dataStyle = kCFDateFormatterWeekdaySymbols;
+ } else if ((selector == CDV_SELECTOR_DAYS) && (style == CDV_FORMAT_SHORT)) {
+ dataStyle = kCFDateFormatterShortWeekdaySymbols;
+ }
+
+ CFArrayRef names = (CFArrayRef)CFDateFormatterCopyProperty(formatter, dataStyle);
+
+ if (names) {
+ NSDictionary* dictionary = [NSDictionary dictionaryWithObject:((__bridge NSArray*)names) forKey:@"value"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
+ CFRelease(names);
+ }
+ // error
+ else {
+ NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
+ [dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"];
+ [dictionary setValue:@"Unknown error" forKey:@"message"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:callBackId];
+
+ CFRelease(formatter);
+}
+
+- (void)isDayLightSavingsTime:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+ NSDate* date = nil;
+ CDVPluginResult* result = nil;
+ NSString* callBackId = [arguments objectAtIndex:0];
+
+ id milliseconds = [options valueForKey:@"date"];
+
+ if (milliseconds && [milliseconds isKindOfClass:[NSNumber class]]) {
+ // get the number of seconds since 1970 and create the date object
+ date = [NSDate dateWithTimeIntervalSince1970:[milliseconds doubleValue] / 1000];
+ }
+
+ if (date) {
+ // get the current calendar for the user and check if the date is using DST
+ NSCalendar* calendar = [NSCalendar currentCalendar];
+ NSTimeZone* timezone = [calendar timeZone];
+ NSNumber* dst = [NSNumber numberWithBool:[timezone isDaylightSavingTimeForDate:date]];
+
+ NSDictionary* dictionary = [NSDictionary dictionaryWithObject:dst forKey:@"dst"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
+ }
+ // error
+ else {
+ NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
+ [dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"];
+ [dictionary setValue:@"Unknown error" forKey:@"message"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
+ }
+ [self.commandDelegate sendPluginResult:result callbackId:callBackId];
+}
+
+- (void)getFirstDayOfWeek:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+ CDVPluginResult* result = nil;
+ NSString* callBackId = [arguments objectAtIndex:0];
+
+ NSCalendar* calendar = [NSCalendar autoupdatingCurrentCalendar];
+
+ NSNumber* day = [NSNumber numberWithInt:[calendar firstWeekday]];
+
+ if (day) {
+ NSDictionary* dictionary = [NSDictionary dictionaryWithObject:day forKey:@"value"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
+ }
+ // error
+ else {
+ NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
+ [dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"];
+ [dictionary setValue:@"Unknown error" forKey:@"message"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:callBackId];
+}
+
+- (void)numberToString:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+ CDVPluginResult* result = nil;
+ NSString* callBackId = [arguments objectAtIndex:0];
+ CFNumberFormatterStyle style = kCFNumberFormatterDecimalStyle;
+ NSNumber* number = nil;
+
+ id value = [options valueForKey:@"number"];
+
+ if (value && [value isKindOfClass:[NSNumber class]]) {
+ number = (NSNumber*)value;
+ }
+
+ // see if any options have been specified
+ id items = [options valueForKey:@"options"];
+ if (items && [items isKindOfClass:[NSMutableDictionary class]]) {
+ NSEnumerator* enumerator = [items keyEnumerator];
+ id key;
+
+ // iterate through all the options
+ while ((key = [enumerator nextObject])) {
+ id item = [items valueForKey:key];
+
+ // make sure that only string values are present
+ if ([item isKindOfClass:[NSString class]]) {
+ // get the desired style of formatting
+ if ([key isEqualToString:@"type"]) {
+ if ([item isEqualToString:@"percent"]) {
+ style = kCFNumberFormatterPercentStyle;
+ } else if ([item isEqualToString:@"currency"]) {
+ style = kCFNumberFormatterCurrencyStyle;
+ } else if ([item isEqualToString:@"decimal"]) {
+ style = kCFNumberFormatterDecimalStyle;
+ }
+ }
+ }
+ }
+ }
+
+ CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
+ currentLocale,
+ style);
+
+ // get the localized string based upon the locale and user preferences
+ NSString* numberString = (__bridge_transfer NSString*)CFNumberFormatterCreateStringWithNumber(kCFAllocatorDefault,
+ formatter,
+ (__bridge CFNumberRef)number);
+
+ if (numberString) {
+ NSDictionary* dictionary = [NSDictionary dictionaryWithObject:numberString forKey:@"value"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
+ }
+ // error
+ else {
+ // DLog(@"GlobalizationCommand numberToString unable to format %@", [number stringValue]);
+ NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
+ [dictionary setValue:[NSNumber numberWithInt:CDV_FORMATTING_ERROR] forKey:@"code"];
+ [dictionary setValue:@"Unable to format" forKey:@"message"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:callBackId];
+
+ CFRelease(formatter);
+}
+
+- (void)stringToNumber:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+ CDVPluginResult* result = nil;
+ NSString* callBackId = [arguments objectAtIndex:0];
+ CFNumberFormatterStyle style = kCFNumberFormatterDecimalStyle;
+ NSString* numberString = nil;
+ double doubleValue;
+
+ id value = [options valueForKey:@"numberString"];
+
+ if (value && [value isKindOfClass:[NSString class]]) {
+ numberString = (NSString*)value;
+ }
+
+ // see if any options have been specified
+ id items = [options valueForKey:@"options"];
+ if (items && [items isKindOfClass:[NSMutableDictionary class]]) {
+ NSEnumerator* enumerator = [items keyEnumerator];
+ id key;
+
+ // iterate through all the options
+ while ((key = [enumerator nextObject])) {
+ id item = [items valueForKey:key];
+
+ // make sure that only string values are present
+ if ([item isKindOfClass:[NSString class]]) {
+ // get the desired style of formatting
+ if ([key isEqualToString:@"type"]) {
+ if ([item isEqualToString:@"percent"]) {
+ style = kCFNumberFormatterPercentStyle;
+ } else if ([item isEqualToString:@"currency"]) {
+ style = kCFNumberFormatterCurrencyStyle;
+ } else if ([item isEqualToString:@"decimal"]) {
+ style = kCFNumberFormatterDecimalStyle;
+ }
+ }
+ }
+ }
+ }
+
+ CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
+ currentLocale,
+ style);
+
+ // we need to make this lenient so as to avoid problems with parsing currencies that have non-breaking space characters
+ if (style == kCFNumberFormatterCurrencyStyle) {
+ CFNumberFormatterSetProperty(formatter, kCFNumberFormatterIsLenient, kCFBooleanTrue);
+ }
+
+ // parse againist the largest type to avoid data loss
+ Boolean rc = CFNumberFormatterGetValueFromString(formatter,
+ (__bridge CFStringRef)numberString,
+ NULL,
+ kCFNumberDoubleType,
+ &doubleValue);
+
+ if (rc) {
+ NSDictionary* dictionary = [NSDictionary dictionaryWithObject:[NSNumber numberWithDouble:doubleValue] forKey:@"value"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
+ }
+ // error
+ else {
+ // DLog(@"GlobalizationCommand stringToNumber unable to parse %@", numberString);
+ NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
+ [dictionary setValue:[NSNumber numberWithInt:CDV_PARSING_ERROR] forKey:@"code"];
+ [dictionary setValue:@"Unable to parse" forKey:@"message"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:callBackId];
+
+ CFRelease(formatter);
+}
+
+- (void)getNumberPattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+ CDVPluginResult* result = nil;
+ NSString* callBackId = [arguments objectAtIndex:0];
+ CFNumberFormatterStyle style = kCFNumberFormatterDecimalStyle;
+ CFStringRef symbolType = NULL;
+ NSString* symbol = @"";
+
+ // see if any options have been specified
+ id items = [options valueForKey:@"options"];
+
+ if (items && [items isKindOfClass:[NSMutableDictionary class]]) {
+ NSEnumerator* enumerator = [items keyEnumerator];
+ id key;
+
+ // iterate through all the options
+ while ((key = [enumerator nextObject])) {
+ id item = [items valueForKey:key];
+
+ // make sure that only string values are present
+ if ([item isKindOfClass:[NSString class]]) {
+ // get the desired style of formatting
+ if ([key isEqualToString:@"type"]) {
+ if ([item isEqualToString:@"percent"]) {
+ style = kCFNumberFormatterPercentStyle;
+ } else if ([item isEqualToString:@"currency"]) {
+ style = kCFNumberFormatterCurrencyStyle;
+ } else if ([item isEqualToString:@"decimal"]) {
+ style = kCFNumberFormatterDecimalStyle;
+ }
+ }
+ }
+ }
+ }
+
+ CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
+ currentLocale,
+ style);
+
+ NSString* numberPattern = (__bridge NSString*)CFNumberFormatterGetFormat(formatter);
+
+ if (style == kCFNumberFormatterCurrencyStyle) {
+ symbolType = kCFNumberFormatterCurrencySymbol;
+ } else if (style == kCFNumberFormatterPercentStyle) {
+ symbolType = kCFNumberFormatterPercentSymbol;
+ }
+
+ if (symbolType) {
+ symbol = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, symbolType);
+ }
+
+ NSString* decimal = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterDecimalSeparator);
+ NSString* grouping = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterGroupingSeparator);
+ NSString* posSign = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterPlusSign);
+ NSString* negSign = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterMinusSign);
+ NSNumber* fracDigits = (__bridge_transfer NSNumber*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterMinFractionDigits);
+ NSNumber* roundingDigits = (__bridge_transfer NSNumber*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterRoundingIncrement);
+
+ // put the pattern information into the dictionary
+ if (numberPattern != nil) {
+ NSArray* keys = [NSArray arrayWithObjects:@"pattern", @"symbol", @"fraction", @"rounding",
+ @"positive", @"negative", @"decimal", @"grouping", nil];
+ NSArray* values = [NSArray arrayWithObjects:numberPattern, symbol, fracDigits, roundingDigits,
+ posSign, negSign, decimal, grouping, nil];
+ NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
+ }
+ // error
+ else {
+ NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
+ [dictionary setValue:[NSNumber numberWithInt:CDV_PATTERN_ERROR] forKey:@"code"];
+ [dictionary setValue:@"Pattern error" forKey:@"message"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:callBackId];
+
+ CFRelease(formatter);
+}
+
+- (void)getCurrencyPattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+ CDVPluginResult* result = nil;
+ NSString* callBackId = [arguments objectAtIndex:0];
+ NSString* currencyCode = nil;
+ NSString* numberPattern = nil;
+ NSString* decimal = nil;
+ NSString* grouping = nil;
+ int32_t defaultFractionDigits;
+ double roundingIncrement;
+ Boolean rc;
+
+ id value = [options valueForKey:@"currencyCode"];
+
+ if (value && [value isKindOfClass:[NSString class]]) {
+ currencyCode = (NSString*)value;
+ }
+
+ // first see if there is base currency info available and fill in the currency_info structure
+ rc = CFNumberFormatterGetDecimalInfoForCurrencyCode((__bridge CFStringRef)currencyCode, &defaultFractionDigits, &roundingIncrement);
+
+ // now set the currency code in the formatter
+ if (rc) {
+ CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
+ currentLocale,
+ kCFNumberFormatterCurrencyStyle);
+
+ CFNumberFormatterSetProperty(formatter, kCFNumberFormatterCurrencyCode, (__bridge CFStringRef)currencyCode);
+ CFNumberFormatterSetProperty(formatter, kCFNumberFormatterInternationalCurrencySymbol, (__bridge CFStringRef)currencyCode);
+
+ numberPattern = (__bridge NSString*)CFNumberFormatterGetFormat(formatter);
+ decimal = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterCurrencyDecimalSeparator);
+ grouping = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterCurrencyGroupingSeparator);
+
+ NSArray* keys = [NSArray arrayWithObjects:@"pattern", @"code", @"fraction", @"rounding",
+ @"decimal", @"grouping", nil];
+ NSArray* values = [NSArray arrayWithObjects:numberPattern, currencyCode, [NSNumber numberWithInt:defaultFractionDigits],
+ [NSNumber numberWithDouble:roundingIncrement], decimal, grouping, nil];
+ NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
+ CFRelease(formatter);
+ }
+ // error
+ else {
+ // DLog(@"GlobalizationCommand getCurrencyPattern unable to get pattern for %@", currencyCode);
+ NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2];
+ [dictionary setValue:[NSNumber numberWithInt:CDV_PATTERN_ERROR] forKey:@"code"];
+ [dictionary setValue:@"Unable to get pattern" forKey:@"message"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:callBackId];
+}
+
+- (void)dealloc
+{
+ if (currentLocale) {
+ CFRelease(currentLocale);
+ currentLocale = nil;
+ }
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
new file mode 100644
index 0000000..0a3ef70
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
@@ -0,0 +1,85 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVPlugin.h"
+#import "CDVInvokedUrlCommand.h"
+#import "CDVScreenOrientationDelegate.h"
+
+@class CDVInAppBrowserViewController;
+
+@protocol CDVInAppBrowserNavigationDelegate <NSObject>
+
+- (void)browserLoadStart:(NSURL*)url;
+- (void)browserLoadStop:(NSURL*)url;
+- (void)browserExit;
+
+@end
+
+@interface CDVInAppBrowser : CDVPlugin <CDVInAppBrowserNavigationDelegate>{}
+
+@property (nonatomic, retain) CDVInAppBrowserViewController* inAppBrowserViewController;
+@property (nonatomic, copy) NSString* callbackId;
+
+- (void)open:(CDVInvokedUrlCommand*)command;
+- (void)close:(CDVInvokedUrlCommand*)command;
+
+@end
+
+@interface CDVInAppBrowserViewController : UIViewController <UIWebViewDelegate>{
+ @private
+ NSURL* _requestedURL;
+ NSString* _userAgent;
+ NSString* _prevUserAgent;
+ BOOL _isPDF;
+}
+
+@property (nonatomic, strong) IBOutlet UIWebView* webView;
+@property (nonatomic, strong) IBOutlet UIBarButtonItem* closeButton;
+@property (nonatomic, strong) IBOutlet UILabel* addressLabel;
+@property (nonatomic, strong) IBOutlet UIBarButtonItem* backButton;
+@property (nonatomic, strong) IBOutlet UIBarButtonItem* forwardButton;
+@property (nonatomic, strong) IBOutlet UIActivityIndicatorView* spinner;
+@property (nonatomic, strong) IBOutlet UIToolbar* toolbar;
+
+@property (nonatomic, weak) id <CDVScreenOrientationDelegate> orientationDelegate;
+@property (nonatomic, weak) id <CDVInAppBrowserNavigationDelegate> navigationDelegate;
+
+- (void)close;
+- (void)navigateTo:(NSURL*)url;
+- (void)showLocationBar:(BOOL)show;
+
+- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent;
+
+@end
+
+@interface CDVInAppBrowserOptions : NSObject {}
+
+@property (nonatomic, assign) BOOL location;
+@property (nonatomic, copy) NSString* presentationstyle;
+@property (nonatomic, copy) NSString* transitionstyle;
+
+@property (nonatomic, assign) BOOL enableviewportscale;
+@property (nonatomic, assign) BOOL mediaplaybackrequiresuseraction;
+@property (nonatomic, assign) BOOL allowinlinemediaplayback;
+@property (nonatomic, assign) BOOL keyboarddisplayrequiresuseraction;
+@property (nonatomic, assign) BOOL suppressesincrementalrendering;
+
++ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options;
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
new file mode 100644
index 0000000..6d7b770
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
@@ -0,0 +1,564 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVInAppBrowser.h"
+#import "CDVPluginResult.h"
+#import "CDVViewController.h"
+#import "CDVUserAgentUtil.h"
+
+#define kInAppBrowserTargetSelf @"_self"
+#define kInAppBrowserTargetSystem @"_system"
+#define kInAppBrowserTargetBlank @"_blank"
+
+#define TOOLBAR_HEIGHT 44.0
+#define LOCATIONBAR_HEIGHT 21.0
+#define FOOTER_HEIGHT ((TOOLBAR_HEIGHT) + (LOCATIONBAR_HEIGHT))
+
+#pragma mark CDVInAppBrowser
+
+@implementation CDVInAppBrowser
+
+- (CDVInAppBrowser*)initWithWebView:(UIWebView*)theWebView
+{
+ self = [super initWithWebView:theWebView];
+ if (self != nil) {
+ // your initialization here
+ }
+
+ return self;
+}
+
+- (void)onReset
+{
+ [self close:nil];
+}
+
+- (void)close:(CDVInvokedUrlCommand*)command
+{
+ if (self.inAppBrowserViewController != nil) {
+ [self.inAppBrowserViewController close];
+ self.inAppBrowserViewController = nil;
+ }
+
+ self.callbackId = nil;
+}
+
+- (void)open:(CDVInvokedUrlCommand*)command
+{
+ CDVPluginResult* pluginResult;
+
+ NSString* url = [command argumentAtIndex:0];
+ NSString* target = [command argumentAtIndex:1 withDefault:kInAppBrowserTargetSelf];
+ NSString* options = [command argumentAtIndex:2 withDefault:@"" andClass:[NSString class]];
+
+ self.callbackId = command.callbackId;
+
+ if (url != nil) {
+ NSURL* baseUrl = [self.webView.request URL];
+ NSURL* absoluteUrl = [[NSURL URLWithString:url relativeToURL:baseUrl] absoluteURL];
+ if ([target isEqualToString:kInAppBrowserTargetSelf]) {
+ [self openInCordovaWebView:absoluteUrl withOptions:options];
+ } else if ([target isEqualToString:kInAppBrowserTargetSystem]) {
+ [self openInSystem:absoluteUrl];
+ } else { // _blank or anything else
+ [self openInInAppBrowser:absoluteUrl withOptions:options];
+ }
+
+ pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
+ } else {
+ pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"incorrect number of arguments"];
+ }
+
+ [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
+ [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
+}
+
+- (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options
+{
+ if (self.inAppBrowserViewController == nil) {
+ NSString* originalUA = [CDVUserAgentUtil originalUserAgent];
+ self.inAppBrowserViewController = [[CDVInAppBrowserViewController alloc] initWithUserAgent:originalUA prevUserAgent:[self.commandDelegate userAgent]];
+ self.inAppBrowserViewController.navigationDelegate = self;
+
+ if ([self.viewController conformsToProtocol:@protocol(CDVScreenOrientationDelegate)]) {
+ self.inAppBrowserViewController.orientationDelegate = (UIViewController <CDVScreenOrientationDelegate>*)self.viewController;
+ }
+ }
+
+ CDVInAppBrowserOptions* browserOptions = [CDVInAppBrowserOptions parseOptions:options];
+ [self.inAppBrowserViewController showLocationBar:browserOptions.location];
+
+ // Set Presentation Style
+ UIModalPresentationStyle presentationStyle = UIModalPresentationFullScreen; // default
+ if (browserOptions.presentationstyle != nil) {
+ if ([browserOptions.presentationstyle isEqualToString:@"pagesheet"]) {
+ presentationStyle = UIModalPresentationPageSheet;
+ } else if ([browserOptions.presentationstyle isEqualToString:@"formsheet"]) {
+ presentationStyle = UIModalPresentationFormSheet;
+ }
+ }
+ self.inAppBrowserViewController.modalPresentationStyle = presentationStyle;
+
+ // Set Transition Style
+ UIModalTransitionStyle transitionStyle = UIModalTransitionStyleCoverVertical; // default
+ if (browserOptions.transitionstyle != nil) {
+ if ([browserOptions.transitionstyle isEqualToString:@"fliphorizontal"]) {
+ transitionStyle = UIModalTransitionStyleFlipHorizontal;
+ } else if ([browserOptions.transitionstyle isEqualToString:@"crossdissolve"]) {
+ transitionStyle = UIModalTransitionStyleCrossDissolve;
+ }
+ }
+ self.inAppBrowserViewController.modalTransitionStyle = transitionStyle;
+
+ // UIWebView options
+ self.inAppBrowserViewController.webView.scalesPageToFit = browserOptions.enableviewportscale;
+ self.inAppBrowserViewController.webView.mediaPlaybackRequiresUserAction = browserOptions.mediaplaybackrequiresuseraction;
+ self.inAppBrowserViewController.webView.allowsInlineMediaPlayback = browserOptions.allowinlinemediaplayback;
+ self.inAppBrowserViewController.webView.keyboardDisplayRequiresUserAction = browserOptions.keyboarddisplayrequiresuseraction;
+ self.inAppBrowserViewController.webView.suppressesIncrementalRendering = browserOptions.suppressesincrementalrendering;
+
+ if (self.viewController.modalViewController != self.inAppBrowserViewController) {
+ [self.viewController presentModalViewController:self.inAppBrowserViewController animated:YES];
+ }
+ [self.inAppBrowserViewController navigateTo:url];
+}
+
+- (void)openInCordovaWebView:(NSURL*)url withOptions:(NSString*)options
+{
+ BOOL passesWhitelist = YES;
+
+ if ([self.viewController isKindOfClass:[CDVViewController class]]) {
+ CDVViewController* vc = (CDVViewController*)self.viewController;
+ if ([vc.whitelist schemeIsAllowed:[url scheme]]) {
+ passesWhitelist = [vc.whitelist URLIsAllowed:url];
+ }
+ } else { // something went wrong, we can't get the whitelist
+ passesWhitelist = NO;
+ }
+
+ if (passesWhitelist) {
+ NSURLRequest* request = [NSURLRequest requestWithURL:url];
+ [self.webView loadRequest:request];
+ } else { // this assumes the InAppBrowser can be excepted from the white-list
+ [self openInInAppBrowser:url withOptions:options];
+ }
+}
+
+- (void)openInSystem:(NSURL*)url
+{
+ if ([[UIApplication sharedApplication] canOpenURL:url]) {
+ [[UIApplication sharedApplication] openURL:url];
+ } else { // handle any custom schemes to plugins
+ [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]];
+ }
+}
+
+#pragma mark CDVInAppBrowserNavigationDelegate
+
+- (void)browserLoadStart:(NSURL*)url
+{
+ if (self.callbackId != nil) {
+ CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
+ messageAsDictionary:@ {@"type":@"loadstart", @"url":[url absoluteString]}];
+ [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
+
+ [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
+ }
+}
+
+- (void)browserLoadStop:(NSURL*)url
+{
+ if (self.callbackId != nil) {
+ CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
+ messageAsDictionary:@ {@"type":@"loadstop", @"url":[url absoluteString]}];
+ [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
+
+ [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
+ }
+}
+
+- (void)browserExit
+{
+ if (self.callbackId != nil) {
+ CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
+ messageAsDictionary:@ {@"type":@"exit"}];
+ [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
+
+ [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
+ }
+ // Don't recycle the ViewController since it may be consuming a lot of memory.
+ // Also - this is required for the PDF/User-Agent bug work-around.
+ self.inAppBrowserViewController = nil;
+}
+
+@end
+
+#pragma mark CDVInAppBrowserViewController
+
+@implementation CDVInAppBrowserViewController
+
+- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent
+{
+ self = [super init];
+ if (self != nil) {
+ _userAgent = userAgent;
+ _prevUserAgent = prevUserAgent;
+ [self createViews];
+ }
+
+ return self;
+}
+
+- (void)createViews
+{
+ // We create the views in code for primarily for ease of upgrades and not requiring an external .xib to be included
+
+ CGRect webViewBounds = self.view.bounds;
+
+ webViewBounds.size.height -= FOOTER_HEIGHT;
+
+ if (!self.webView) {
+ [CDVUserAgentUtil setUserAgent:_userAgent];
+
+ self.webView = [[UIWebView alloc] initWithFrame:webViewBounds];
+ self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
+
+ [self.view addSubview:self.webView];
+ [self.view sendSubviewToBack:self.webView];
+
+ self.webView.delegate = self;
+ self.webView.backgroundColor = [UIColor whiteColor];
+
+ self.webView.clearsContextBeforeDrawing = YES;
+ self.webView.clipsToBounds = YES;
+ self.webView.contentMode = UIViewContentModeScaleToFill;
+ self.webView.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+ self.webView.multipleTouchEnabled = YES;
+ self.webView.opaque = YES;
+ self.webView.scalesPageToFit = NO;
+ self.webView.userInteractionEnabled = YES;
+ }
+
+ self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
+ self.spinner.alpha = 1.000;
+ self.spinner.autoresizesSubviews = YES;
+ self.spinner.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
+ self.spinner.clearsContextBeforeDrawing = NO;
+ self.spinner.clipsToBounds = NO;
+ self.spinner.contentMode = UIViewContentModeScaleToFill;
+ self.spinner.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+ self.spinner.frame = CGRectMake(454.0, 231.0, 20.0, 20.0);
+ self.spinner.hidden = YES;
+ self.spinner.hidesWhenStopped = YES;
+ self.spinner.multipleTouchEnabled = NO;
+ self.spinner.opaque = NO;
+ self.spinner.userInteractionEnabled = NO;
+ [self.spinner stopAnimating];
+
+ self.closeButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(close)];
+ self.closeButton.enabled = YES;
+ self.closeButton.imageInsets = UIEdgeInsetsZero;
+ self.closeButton.style = UIBarButtonItemStylePlain;
+ self.closeButton.width = 32.000;
+
+ UIBarButtonItem* flexibleSpaceButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
+
+ UIBarButtonItem* fixedSpaceButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
+ fixedSpaceButton.width = 20;
+
+ self.toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, (self.view.bounds.size.height - TOOLBAR_HEIGHT), self.view.bounds.size.width, TOOLBAR_HEIGHT)];
+ self.toolbar.alpha = 1.000;
+ self.toolbar.autoresizesSubviews = YES;
+ self.toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
+ self.toolbar.barStyle = UIBarStyleBlackOpaque;
+ self.toolbar.clearsContextBeforeDrawing = NO;
+ self.toolbar.clipsToBounds = NO;
+ self.toolbar.contentMode = UIViewContentModeScaleToFill;
+ self.toolbar.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+ self.toolbar.hidden = NO;
+ self.toolbar.multipleTouchEnabled = NO;
+ self.toolbar.opaque = NO;
+ self.toolbar.userInteractionEnabled = YES;
+
+ CGFloat labelInset = 5.0;
+ self.addressLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelInset, (self.view.bounds.size.height - FOOTER_HEIGHT), self.view.bounds.size.width - labelInset, LOCATIONBAR_HEIGHT)];
+ self.addressLabel.adjustsFontSizeToFitWidth = NO;
+ self.addressLabel.alpha = 1.000;
+ self.addressLabel.autoresizesSubviews = YES;
+ self.addressLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin;
+ self.addressLabel.backgroundColor = [UIColor clearColor];
+ self.addressLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
+ self.addressLabel.clearsContextBeforeDrawing = YES;
+ self.addressLabel.clipsToBounds = YES;
+ self.addressLabel.contentMode = UIViewContentModeScaleToFill;
+ self.addressLabel.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+ self.addressLabel.enabled = YES;
+ self.addressLabel.hidden = NO;
+ self.addressLabel.lineBreakMode = UILineBreakModeTailTruncation;
+ self.addressLabel.minimumFontSize = 10.000;
+ self.addressLabel.multipleTouchEnabled = NO;
+ self.addressLabel.numberOfLines = 1;
+ self.addressLabel.opaque = NO;
+ self.addressLabel.shadowOffset = CGSizeMake(0.0, -1.0);
+ self.addressLabel.text = @"Loading...";
+ self.addressLabel.textAlignment = UITextAlignmentLeft;
+ self.addressLabel.textColor = [UIColor colorWithWhite:1.000 alpha:1.000];
+ self.addressLabel.userInteractionEnabled = NO;
+
+ NSString* frontArrowString = @"►"; // create arrow from Unicode char
+ self.forwardButton = [[UIBarButtonItem alloc] initWithTitle:frontArrowString style:UIBarButtonItemStylePlain target:self action:@selector(goForward:)];
+ self.forwardButton.enabled = YES;
+ self.forwardButton.imageInsets = UIEdgeInsetsZero;
+
+ NSString* backArrowString = @"◄"; // create arrow from Unicode char
+ self.backButton = [[UIBarButtonItem alloc] initWithTitle:backArrowString style:UIBarButtonItemStylePlain target:self action:@selector(goBack:)];
+ self.backButton.enabled = YES;
+ self.backButton.imageInsets = UIEdgeInsetsZero;
+
+ [self.toolbar setItems:@[self.closeButton, flexibleSpaceButton, self.backButton, fixedSpaceButton, self.forwardButton]];
+
+ self.view.backgroundColor = [UIColor grayColor];
+ [self.view addSubview:self.toolbar];
+ [self.view addSubview:self.addressLabel];
+ [self.view addSubview:self.spinner];
+}
+
+- (void)showLocationBar:(BOOL)show
+{
+ CGRect addressLabelFrame = self.addressLabel.frame;
+ BOOL locationBarVisible = (addressLabelFrame.size.height > 0);
+
+ // prevent double show/hide
+ if (locationBarVisible == show) {
+ return;
+ }
+
+ if (show) {
+ CGRect webViewBounds = self.view.bounds;
+ webViewBounds.size.height -= FOOTER_HEIGHT;
+ self.webView.frame = webViewBounds;
+
+ CGRect addressLabelFrame = self.addressLabel.frame;
+ addressLabelFrame.size.height = LOCATIONBAR_HEIGHT;
+ self.addressLabel.frame = addressLabelFrame;
+ } else {
+ CGRect webViewBounds = self.view.bounds;
+ webViewBounds.size.height -= TOOLBAR_HEIGHT;
+ self.webView.frame = webViewBounds;
+
+ CGRect addressLabelFrame = self.addressLabel.frame;
+ addressLabelFrame.size.height = 0;
+ self.addressLabel.frame = addressLabelFrame;
+ }
+}
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+}
+
+- (void)viewDidUnload
+{
+ [self.webView loadHTMLString:nil baseURL:nil];
+ [super viewDidUnload];
+}
+
+- (void)close
+{
+ if ([self respondsToSelector:@selector(presentingViewController)]) {
+ [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];
+ } else {
+ [[self parentViewController] dismissModalViewControllerAnimated:YES];
+ }
+
+ if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserExit)]) {
+ [self.navigationDelegate browserExit];
+ }
+}
+
+- (void)navigateTo:(NSURL*)url
+{
+ NSURLRequest* request = [NSURLRequest requestWithURL:url];
+
+ [self.webView loadRequest:request];
+}
+
+- (void)goBack:(id)sender
+{
+ [self.webView goBack];
+}
+
+- (void)goForward:(id)sender
+{
+ [self.webView goForward];
+}
+
+#pragma mark UIWebViewDelegate
+
+- (void)webViewDidStartLoad:(UIWebView*)theWebView
+{
+ // loading url, start spinner, update back/forward
+
+ self.addressLabel.text = @"Loading...";
+ self.backButton.enabled = theWebView.canGoBack;
+ self.forwardButton.enabled = theWebView.canGoForward;
+
+ [self.spinner startAnimating];
+
+ NSURL* url = theWebView.request.URL;
+ // This is probably a bug, but it works on iOS 5 and 6 to know when a PDF
+ // is being loaded.
+ _isPDF = [[url absoluteString] length] == 0;
+
+ if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadStart:)]) {
+ if (url == nil) {
+ url = _requestedURL;
+ }
+ [self.navigationDelegate browserLoadStart:url];
+ }
+}
+
+- (void)webViewDidFinishLoad:(UIWebView*)theWebView
+{
+ // update url, stop spinner, update back/forward
+
+ self.addressLabel.text = theWebView.request.URL.absoluteString;
+ self.backButton.enabled = theWebView.canGoBack;
+ self.forwardButton.enabled = theWebView.canGoForward;
+
+ [self.spinner stopAnimating];
+
+ // Work around a bug where the first time a PDF is opened, all UIWebViews
+ // reload their User-Agent from NSUserDefaults.
+ // This work-around makes the following assumptions:
+ // 1. The app has only a single Cordova Webview. If not, then the app should
+ // take it upon themselves to load a PDF in the background as a part of
+ // their start-up flow.
+ // 2. That the PDF does not require any additional network requests. We change
+ // the user-agent here back to that of the CDVViewController, so requests
+ // from it must pass through its white-list. This *does* break PDFs that
+ // contain links to other remote PDF/websites.
+ // More info at https://issues.apache.org/jira/browse/CB-2225
+ if (_isPDF) {
+ [CDVUserAgentUtil setUserAgent:_prevUserAgent];
+ }
+
+ if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadStop:)]) {
+ NSURL* url = theWebView.request.URL;
+ [self.navigationDelegate browserLoadStop:url];
+ }
+}
+
+- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error
+{
+ // log fail message, stop spinner, update back/forward
+ NSLog(@"webView:didFailLoadWithError - %@", [error localizedDescription]);
+
+ self.backButton.enabled = theWebView.canGoBack;
+ self.forwardButton.enabled = theWebView.canGoForward;
+ [self.spinner stopAnimating];
+
+ self.addressLabel.text = @"Load Error";
+}
+
+#pragma mark CDVScreenOrientationDelegate
+
+- (BOOL)shouldAutorotate
+{
+ if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotate)]) {
+ return [self.orientationDelegate shouldAutorotate];
+ }
+ return YES;
+}
+
+- (NSUInteger)supportedInterfaceOrientations
+{
+ if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(supportedInterfaceOrientations)]) {
+ return [self.orientationDelegate supportedInterfaceOrientations];
+ }
+
+ return 1 << UIInterfaceOrientationPortrait;
+}
+
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
+{
+ if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) {
+ return [self.orientationDelegate shouldAutorotateToInterfaceOrientation:interfaceOrientation];
+ }
+
+ return YES;
+}
+
+@end
+
+@implementation CDVInAppBrowserOptions
+
+- (id)init
+{
+ if (self = [super init]) {
+ // default values
+ self.location = YES;
+
+ self.enableviewportscale = NO;
+ self.mediaplaybackrequiresuseraction = NO;
+ self.allowinlinemediaplayback = NO;
+ self.keyboarddisplayrequiresuseraction = YES;
+ self.suppressesincrementalrendering = NO;
+ }
+
+ return self;
+}
+
++ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options
+{
+ CDVInAppBrowserOptions* obj = [[CDVInAppBrowserOptions alloc] init];
+
+ // NOTE: this parsing does not handle quotes within values
+ NSArray* pairs = [options componentsSeparatedByString:@","];
+
+ // parse keys and values, set the properties
+ for (NSString* pair in pairs) {
+ NSArray* keyvalue = [pair componentsSeparatedByString:@"="];
+
+ if ([keyvalue count] == 2) {
+ NSString* key = [[keyvalue objectAtIndex:0] lowercaseString];
+ NSString* value = [[keyvalue objectAtIndex:1] lowercaseString];
+
+ BOOL isBoolean = [value isEqualToString:@"yes"] || [value isEqualToString:@"no"];
+ NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init];
+ [numberFormatter setAllowsFloats:YES];
+ BOOL isNumber = [numberFormatter numberFromString:value] != nil;
+
+ // set the property according to the key name
+ if ([obj respondsToSelector:NSSelectorFromString(key)]) {
+ if (isNumber) {
+ [obj setValue:[numberFormatter numberFromString:value] forKey:key];
+ } else if (isBoolean) {
+ [obj setValue:[NSNumber numberWithBool:[value isEqualToString:@"yes"]] forKey:key];
+ } else {
+ [obj setValue:value forKey:key];
+ }
+ }
+ }
+ }
+
+ return obj;
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h b/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h
new file mode 100644
index 0000000..6eb0099
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h
@@ -0,0 +1,57 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+@interface CDVInvokedUrlCommand : NSObject {
+ NSString* _callbackId;
+ NSString* _className;
+ NSString* _methodName;
+ NSArray* _arguments;
+}
+
+@property (nonatomic, readonly) NSArray* arguments;
+@property (nonatomic, readonly) NSString* callbackId;
+@property (nonatomic, readonly) NSString* className;
+@property (nonatomic, readonly) NSString* methodName;
+
++ (CDVInvokedUrlCommand*)commandFromJson:(NSArray*)jsonEntry;
+
+- (id)initWithArguments:(NSArray*)arguments
+ callbackId :(NSString*)callbackId
+ className :(NSString*)className
+ methodName :(NSString*)methodName;
+
+- (id)initFromJson:(NSArray*)jsonEntry;
+
+// The first NSDictionary found in the arguments will be returned in legacyDict.
+// The arguments array with be prepended with the callbackId and have the first
+// dict removed from it.
+- (void)legacyArguments:(NSMutableArray**)legacyArguments andDict:(NSMutableDictionary**)legacyDict;
+
+// Returns the argument at the given index.
+// If index >= the number of arguments, returns nil.
+// If the argument at the given index is NSNull, returns nil.
+- (id)argumentAtIndex:(NSUInteger)index;
+// Same as above, but returns defaultValue instead of nil.
+- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue;
+// Same as above, but returns defaultValue instead of nil, and if the argument is not of the expected class, returns defaultValue
+- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue andClass:(Class)aClass;
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.m b/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.m
new file mode 100644
index 0000000..6c7a856
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.m
@@ -0,0 +1,140 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVInvokedUrlCommand.h"
+#import "CDVJSON.h"
+#import "NSData+Base64.h"
+
+@implementation CDVInvokedUrlCommand
+
+@synthesize arguments = _arguments;
+@synthesize callbackId = _callbackId;
+@synthesize className = _className;
+@synthesize methodName = _methodName;
+
++ (CDVInvokedUrlCommand*)commandFromJson:(NSArray*)jsonEntry
+{
+ return [[CDVInvokedUrlCommand alloc] initFromJson:jsonEntry];
+}
+
+- (id)initFromJson:(NSArray*)jsonEntry
+{
+ id tmp = [jsonEntry objectAtIndex:0];
+ NSString* callbackId = tmp == [NSNull null] ? nil : tmp;
+ NSString* className = [jsonEntry objectAtIndex:1];
+ NSString* methodName = [jsonEntry objectAtIndex:2];
+ NSMutableArray* arguments = [jsonEntry objectAtIndex:3];
+
+ return [self initWithArguments:arguments
+ callbackId:callbackId
+ className:className
+ methodName:methodName];
+}
+
+- (id)initWithArguments:(NSArray*)arguments
+ callbackId:(NSString*)callbackId
+ className:(NSString*)className
+ methodName:(NSString*)methodName
+{
+ self = [super init];
+ if (self != nil) {
+ _arguments = arguments;
+ _callbackId = callbackId;
+ _className = className;
+ _methodName = methodName;
+ }
+ [self massageArguments];
+ return self;
+}
+
+- (void)massageArguments
+{
+ NSMutableArray* newArgs = nil;
+
+ for (NSUInteger i = 0, count = [_arguments count]; i < count; ++i) {
+ id arg = [_arguments objectAtIndex:i];
+ if (![arg isKindOfClass:[NSDictionary class]]) {
+ continue;
+ }
+ NSDictionary* dict = arg;
+ NSString* type = [dict objectForKey:@"CDVType"];
+ if (!type || ![type isEqualToString:@"ArrayBuffer"]) {
+ continue;
+ }
+ NSString* data = [dict objectForKey:@"data"];
+ if (!data) {
+ continue;
+ }
+ if (newArgs == nil) {
+ newArgs = [NSMutableArray arrayWithArray:_arguments];
+ _arguments = newArgs;
+ }
+ [newArgs replaceObjectAtIndex:i withObject:[NSData dataFromBase64String:data]];
+ }
+}
+
+- (void)legacyArguments:(NSMutableArray**)legacyArguments andDict:(NSMutableDictionary**)legacyDict
+{
+ NSMutableArray* newArguments = [NSMutableArray arrayWithArray:_arguments];
+
+ for (NSUInteger i = 0; i < [newArguments count]; ++i) {
+ if ([[newArguments objectAtIndex:i] isKindOfClass:[NSDictionary class]]) {
+ if (legacyDict != NULL) {
+ *legacyDict = [newArguments objectAtIndex:i];
+ }
+ [newArguments removeObjectAtIndex:i];
+ break;
+ }
+ }
+
+ // Legacy (two versions back) has no callbackId.
+ if (_callbackId != nil) {
+ [newArguments insertObject:_callbackId atIndex:0];
+ }
+ if (legacyArguments != NULL) {
+ *legacyArguments = newArguments;
+ }
+}
+
+- (id)argumentAtIndex:(NSUInteger)index
+{
+ return [self argumentAtIndex:index withDefault:nil];
+}
+
+- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue
+{
+ return [self argumentAtIndex:index withDefault:defaultValue andClass:nil];
+}
+
+- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue andClass:(Class)aClass
+{
+ if (index >= [_arguments count]) {
+ return defaultValue;
+ }
+ id ret = [_arguments objectAtIndex:index];
+ if (ret == [NSNull null]) {
+ ret = defaultValue;
+ }
+ if ((aClass != nil) && ![ret isKindOfClass:aClass]) {
+ ret = defaultValue;
+ }
+ return ret;
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVJSON.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVJSON.h b/lib/cordova-ios/CordovaLib/Classes/CDVJSON.h
new file mode 100644
index 0000000..eaa895e
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVJSON.h
@@ -0,0 +1,30 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+@interface NSArray (CDVJSONSerializing)
+- (NSString*)JSONString;
+@end
+
+@interface NSDictionary (CDVJSONSerializing)
+- (NSString*)JSONString;
+@end
+
+@interface NSString (CDVJSONSerializing)
+- (id)JSONObject;
+@end
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVJSON.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVJSON.m b/lib/cordova-ios/CordovaLib/Classes/CDVJSON.m
new file mode 100644
index 0000000..78267e5
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVJSON.m
@@ -0,0 +1,77 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVJSON.h"
+#import <Foundation/NSJSONSerialization.h>
+
+@implementation NSArray (CDVJSONSerializing)
+
+- (NSString*)JSONString
+{
+ NSError* error = nil;
+ NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self
+ options:NSJSONWritingPrettyPrinted
+ error:&error];
+
+ if (error != nil) {
+ NSLog(@"NSArray JSONString error: %@", [error localizedDescription]);
+ return nil;
+ } else {
+ return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
+ }
+}
+
+@end
+
+@implementation NSDictionary (CDVJSONSerializing)
+
+- (NSString*)JSONString
+{
+ NSError* error = nil;
+ NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self
+ options:NSJSONWritingPrettyPrinted
+ error:&error];
+
+ if (error != nil) {
+ NSLog(@"NSDictionary JSONString error: %@", [error localizedDescription]);
+ return nil;
+ } else {
+ return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
+ }
+}
+
+@end
+
+@implementation NSString (CDVJSONSerializing)
+
+- (id)JSONObject
+{
+ NSError* error = nil;
+ id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding]
+ options:kNilOptions
+ error:&error];
+
+ if (error != nil) {
+ NSLog(@"NSString JSONObject error: %@", [error localizedDescription]);
+ }
+
+ return object;
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
new file mode 100644
index 0000000..e5e3112
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
@@ -0,0 +1,50 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVPlugin.h"
+
+#define kCDVLocalStorageErrorDomain @"kCDVLocalStorageErrorDomain"
+#define kCDVLocalStorageFileOperationError 1
+
+@interface CDVLocalStorage : CDVPlugin <UIWebViewDelegate>
+
+@property (nonatomic, readonly, strong) NSMutableArray* backupInfo;
+
+- (BOOL)shouldBackup;
+- (BOOL)shouldRestore;
+- (void)backup:(CDVInvokedUrlCommand*)command;
+- (void)restore:(CDVInvokedUrlCommand*)command;
+
++ (void)__fixupDatabaseLocationsWithBackupType:(NSString*)backupType;
+// Visible for testing.
++ (BOOL)__verifyAndFixDatabaseLocationsWithAppPlistDict:(NSMutableDictionary*)appPlistDict
+ bundlePath :(NSString*)bundlePath
+ fileManager :(NSFileManager*)fileManager;
+@end
+
+@interface CDVBackupInfo : NSObject
+
+@property (nonatomic, copy) NSString* original;
+@property (nonatomic, copy) NSString* backup;
+@property (nonatomic, copy) NSString* label;
+
+- (BOOL)shouldBackup;
+- (BOOL)shouldRestore;
+
+@end