From 5f789b53e9bb95907825f8c5d38363c54f13142a Mon Sep 17 00:00:00 2001 From: George Garside Date: Fri, 5 Apr 2013 17:47:45 +0100 Subject: [PATCH 01/32] Disable KISSmetrics whilst developing --- www/index.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/www/index.html b/www/index.html index b6ec27f..f4d94b5 100644 --- a/www/index.html +++ b/www/index.html @@ -10,6 +10,7 @@ + From f4a8d30b3a9b45c56e241d99e1063f4388f07da9 Mon Sep 17 00:00:00 2001 From: George Garside Date: Mon, 8 Apr 2013 12:54:40 +0100 Subject: [PATCH 02/32] Re-add TestFlight `uniqueIdentifier` code --- TDA-Enrichment/Classes/AppDelegate.m | 1 + 1 file changed, 1 insertion(+) diff --git a/TDA-Enrichment/Classes/AppDelegate.m b/TDA-Enrichment/Classes/AppDelegate.m index 6ab6337..6e0382e 100644 --- a/TDA-Enrichment/Classes/AppDelegate.m +++ b/TDA-Enrichment/Classes/AppDelegate.m @@ -57,6 +57,7 @@ - (id)init - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { // TestFlight init + [TestFlight setDeviceIdentifier:[[UIDevice currentDevice] uniqueIdentifier]]; [TestFlight takeOff:@"d3bb9d36-e2ca-43f0-a499-52e8582879d3"]; NSURL* url = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey]; From c78c0deb3f098de394bc49ef8d5d6d6edb438e85 Mon Sep 17 00:00:00 2001 From: George Garside Date: Mon, 8 Apr 2013 12:59:11 +0100 Subject: [PATCH 03/32] Fix corrupt info plist --- TDA-Enrichment/TDA-Enrichment-Info.plist | 8 -------- 1 file changed, 8 deletions(-) diff --git a/TDA-Enrichment/TDA-Enrichment-Info.plist b/TDA-Enrichment/TDA-Enrichment-Info.plist index bf46748..f1ca469 100644 --- a/TDA-Enrichment/TDA-Enrichment-Info.plist +++ b/TDA-Enrichment/TDA-Enrichment-Info.plist @@ -39,11 +39,7 @@ CFBundlePackageType APPL CFBundleShortVersionString -<<<<<<< HEAD - 1.1.1 -======= 1.1.2 ->>>>>>> 6cc649e... Increment version and build number CFBundleSignature ???? CFBundleURLTypes @@ -62,11 +58,7 @@ CFBundleVersion -<<<<<<< HEAD - 54 -======= 56 ->>>>>>> 6cc649e... Increment version and build number LSRequiresIPhoneOS NSMainNibFile From 34afdd908942ac4a6155cb61c76416f844eae2c2 Mon Sep 17 00:00:00 2001 From: George Garside Date: Fri, 19 Apr 2013 16:43:56 +0100 Subject: [PATCH 04/32] Update CordovaLib --- CordovaLib/Classes/CDV.h | 2 + CordovaLib/Classes/CDVAvailability.h | 3 +- CordovaLib/Classes/CDVCapture.m | 48 +- CordovaLib/Classes/CDVCommandDelegate.h | 2 +- CordovaLib/Classes/CDVCommandDelegateImpl.h | 5 +- CordovaLib/Classes/CDVCommandQueue.h | 2 +- CordovaLib/Classes/CDVCommandQueue.m | 5 +- CordovaLib/Classes/CDVConfigParser.h | 27 + CordovaLib/Classes/CDVConfigParser.m | 61 +++ CordovaLib/Classes/CDVContact.m | 6 +- CordovaLib/Classes/CDVContacts.m | 34 +- CordovaLib/Classes/CDVDevice.m | 25 +- CordovaLib/Classes/CDVFileTransfer.m | 4 + CordovaLib/Classes/CDVGlobalization.h | 63 ++- CordovaLib/Classes/CDVInAppBrowser.h | 72 +++ CordovaLib/Classes/CDVInAppBrowser.m | 494 ++++++++++++++++++ CordovaLib/Classes/CDVInvokedUrlCommand.h | 9 + CordovaLib/Classes/CDVInvokedUrlCommand.m | 25 + CordovaLib/Classes/CDVLocalStorage.m | 4 +- CordovaLib/Classes/CDVPlugin.h | 9 +- CordovaLib/Classes/CDVPlugin.m | 10 + .../Classes/CDVScreenOrientationDelegate.h | 28 + CordovaLib/Classes/CDVSound.m | 32 +- CordovaLib/Classes/CDVURLProtocol.m | 101 ++-- CordovaLib/Classes/CDVViewController.h | 13 +- CordovaLib/Classes/CDVViewController.m | 186 ++++--- CordovaLib/Classes/CDVWhitelist.h | 3 + CordovaLib/Classes/CDVWhitelist.m | 7 +- .../CordovaLib.xcodeproj/project.pbxproj | 44 +- CordovaLib/VERSION | 2 +- 30 files changed, 1098 insertions(+), 228 deletions(-) create mode 100755 CordovaLib/Classes/CDVConfigParser.h create mode 100755 CordovaLib/Classes/CDVConfigParser.m create mode 100755 CordovaLib/Classes/CDVInAppBrowser.h create mode 100755 CordovaLib/Classes/CDVInAppBrowser.m create mode 100755 CordovaLib/Classes/CDVScreenOrientationDelegate.h diff --git a/CordovaLib/Classes/CDV.h b/CordovaLib/Classes/CDV.h index fef0f8d..5367799 100755 --- a/CordovaLib/Classes/CDV.h +++ b/CordovaLib/Classes/CDV.h @@ -46,6 +46,8 @@ #import "CDVSplashScreen.h" #import "CDVWhitelist.h" #import "CDVLocalStorage.h" +#import "CDVInAppBrowser.h" +#import "CDVScreenOrientationDelegate.h" #import "NSArray+Comparisons.h" #import "NSData+Base64.h" diff --git a/CordovaLib/Classes/CDVAvailability.h b/CordovaLib/Classes/CDVAvailability.h index 0db4c5d..d2e7f1b 100755 --- a/CordovaLib/Classes/CDVAvailability.h +++ b/CordovaLib/Classes/CDVAvailability.h @@ -34,6 +34,7 @@ #define __CORDOVA_2_0_0 20000 #define __CORDOVA_2_1_0 20100 #define __CORDOVA_2_2_0 20200 +#define __CORDOVA_2_3_0 20300 #define __CORDOVA_NA 99999 /* not available */ /* @@ -44,7 +45,7 @@ #endif */ #ifndef CORDOVA_VERSION_MIN_REQUIRED - #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_2_0 + #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_3_0 #endif /* diff --git a/CordovaLib/Classes/CDVCapture.m b/CordovaLib/Classes/CDVCapture.m index 07eae1f..6d52042 100755 --- a/CordovaLib/Classes/CDVCapture.m +++ b/CordovaLib/Classes/CDVCapture.m @@ -251,7 +251,7 @@ - (void)captureVideo:(CDVInvokedUrlCommand*)command // iOS 4.0 if ([pickerController respondsToSelector:@selector(cameraCaptureMode)]) { pickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo; - pickerController.videoQuality = UIImagePickerControllerQualityTypeHigh; + // pickerController.videoQuality = UIImagePickerControllerQualityTypeHigh; // pickerController.cameraDevice = UIImagePickerControllerCameraDeviceRear; // pickerController.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto; } @@ -383,12 +383,20 @@ - (void)getFormatData:(CDVInvokedUrlCommand*)command AVURLAsset* movieAsset = [[AVURLAsset alloc] initWithURL:movieURL options:nil]; CMTime duration = [movieAsset duration]; [formatData setObject:[NSNumber numberWithFloat:CMTimeGetSeconds(duration)] forKey:kW3CMediaFormatDuration]; - CGSize size = [movieAsset naturalSize]; - [formatData setObject:[NSNumber numberWithFloat:size.height] forKey:kW3CMediaFormatHeight]; - [formatData setObject:[NSNumber numberWithFloat:size.width] forKey:kW3CMediaFormatWidth]; - // not sure how to get codecs or bitrate??? - // AVMetadataItem - // AudioFile + + NSArray* allVideoTracks = [movieAsset tracksWithMediaType:AVMediaTypeVideo]; + if ([allVideoTracks count] > 0) { + AVAssetTrack* track = [[movieAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; + CGSize size = [track naturalSize]; + + [formatData setObject:[NSNumber numberWithFloat:size.height] forKey:kW3CMediaFormatHeight]; + [formatData setObject:[NSNumber numberWithFloat:size.width] forKey:kW3CMediaFormatWidth]; + // not sure how to get codecs or bitrate??? + // AVMetadataItem + // AudioFile + } else { + NSLog(@"No video tracks found for %@", fullPath); + } } else if ([mimeType rangeOfString:@"audio/"].location != NSNotFound) { if (NSClassFromString(@"AVAudioPlayer") != nil) { NSURL* fileURL = [NSURL fileURLWithPath:fullPath]; @@ -521,11 +529,12 @@ - (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker @implementation CDVAudioNavigationController #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000 -- (NSUInteger)supportedInterfaceOrientations -{ - // delegate to CVDAudioRecorderViewController - return [self.topViewController supportedInterfaceOrientations]; -} + - (NSUInteger)supportedInterfaceOrientations + { + // delegate to CVDAudioRecorderViewController + return [self.topViewController supportedInterfaceOrientations]; + } + #endif @end @@ -685,14 +694,15 @@ - (void)viewDidLoad } #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000 -- (NSUInteger)supportedInterfaceOrientations -{ - NSUInteger orientation = UIInterfaceOrientationMaskPortrait; // must support portrait - NSUInteger supported = [captureCommand.viewController supportedInterfaceOrientations]; + - (NSUInteger)supportedInterfaceOrientations + { + NSUInteger orientation = UIInterfaceOrientationMaskPortrait; // must support portrait + NSUInteger supported = [captureCommand.viewController supportedInterfaceOrientations]; + + orientation = orientation | (supported & UIInterfaceOrientationMaskPortraitUpsideDown); + return orientation; + } - orientation = orientation | (supported & UIInterfaceOrientationMaskPortraitUpsideDown); - return orientation; -} #endif - (void)viewDidUnload diff --git a/CordovaLib/Classes/CDVCommandDelegate.h b/CordovaLib/Classes/CDVCommandDelegate.h index 8f41071..4a53f98 100755 --- a/CordovaLib/Classes/CDVCommandDelegate.h +++ b/CordovaLib/Classes/CDVCommandDelegate.h @@ -27,7 +27,7 @@ - (NSString*)pathForResource:(NSString*)resourcepath; - (id)getCommandInstance:(NSString*)pluginName; -- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className CDV_DEPRECATED(2.2, "Use CDVViewController to register plugins, or use Cordova.plist."); +- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className CDV_DEPRECATED(2.2, "Use CDVViewController to register plugins, or use config.xml."); // Plugins should not be using this interface to call other plugins since it // will result in bogus callbacks being made. diff --git a/CordovaLib/Classes/CDVCommandDelegateImpl.h b/CordovaLib/Classes/CDVCommandDelegateImpl.h index f850dc6..6735136 100755 --- a/CordovaLib/Classes/CDVCommandDelegateImpl.h +++ b/CordovaLib/Classes/CDVCommandDelegateImpl.h @@ -25,8 +25,9 @@ @interface CDVCommandDelegateImpl : NSObject { @private - __unsafe_unretained CDVViewController* _viewController; - __unsafe_unretained CDVCommandQueue* _commandQueue; + __weak CDVViewController* _viewController; + @protected + __weak CDVCommandQueue* _commandQueue; } - (id)initWithViewController:(CDVViewController*)viewController; @end diff --git a/CordovaLib/Classes/CDVCommandQueue.h b/CordovaLib/Classes/CDVCommandQueue.h index d3e2b0a..ebdf844 100755 --- a/CordovaLib/Classes/CDVCommandQueue.h +++ b/CordovaLib/Classes/CDVCommandQueue.h @@ -25,7 +25,7 @@ @interface CDVCommandQueue : NSObject { @private NSInteger _lastCommandQueueFlushRequestId; - __unsafe_unretained CDVViewController* _viewController; + __weak CDVViewController* _viewController; NSMutableArray* _queue; BOOL _currentlyExecuting; } diff --git a/CordovaLib/Classes/CDVCommandQueue.m b/CordovaLib/Classes/CDVCommandQueue.m index e4e6c45..d88a730 100755 --- a/CordovaLib/Classes/CDVCommandQueue.m +++ b/CordovaLib/Classes/CDVCommandQueue.m @@ -21,6 +21,7 @@ Licensed to the Apache Software Foundation (ASF) under one #import "CDV.h" #import "CDVCommandQueue.h" #import "CDVViewController.h" +#import "CDVCommandDelegateImpl.h" @implementation CDVCommandQueue @@ -120,10 +121,10 @@ - (BOOL)execute:(CDVInvokedUrlCommand*)command } // Fetch an instance of this class - CDVPlugin* obj = [_viewController getCommandInstance:command.className]; + CDVPlugin* obj = [_viewController.commandDelegate getCommandInstance:command.className]; if (!([obj isKindOfClass:[CDVPlugin class]])) { - NSLog(@"ERROR: Plugin '%@' not found, or is not a CDVPlugin. Check your plugin mapping in Cordova.plist.", command.className); + NSLog(@"ERROR: Plugin '%@' not found, or is not a CDVPlugin. Check your plugin mapping in config.xml.", command.className); return NO; } BOOL retVal = YES; diff --git a/CordovaLib/Classes/CDVConfigParser.h b/CordovaLib/Classes/CDVConfigParser.h new file mode 100755 index 0000000..23cdd01 --- /dev/null +++ b/CordovaLib/Classes/CDVConfigParser.h @@ -0,0 +1,27 @@ +/* + 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 CDVConfigParser : NSObject { +} + +@property (nonatomic, readonly, strong) NSMutableDictionary* pluginsDict; +@property (nonatomic, readonly, strong) NSMutableDictionary* settings; +@property (nonatomic, readonly, strong) NSMutableArray* whitelistHosts; + +@end diff --git a/CordovaLib/Classes/CDVConfigParser.m b/CordovaLib/Classes/CDVConfigParser.m new file mode 100755 index 0000000..b596c9d --- /dev/null +++ b/CordovaLib/Classes/CDVConfigParser.m @@ -0,0 +1,61 @@ +/* + 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 "CDVConfigParser.h" + +@interface CDVConfigParser () + +@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginsDict; +@property (nonatomic, readwrite, strong) NSMutableDictionary* settings; +@property (nonatomic, readwrite, strong) NSMutableArray* whitelistHosts; + +@end + +@implementation CDVConfigParser + +@synthesize pluginsDict, settings, whitelistHosts; + +- (id)init +{ + self = [super init]; + if (self != nil) { + self.pluginsDict = [[NSMutableDictionary alloc] initWithCapacity:4]; + self.settings = [[NSMutableDictionary alloc] initWithCapacity:4]; + self.whitelistHosts = [[NSMutableArray alloc] initWithCapacity:1]; + } + return self; +} + +- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributeDict +{ + if ([elementName isEqualToString:@"preference"]) { + [settings setObject:[attributeDict objectForKey:@"value"] forKey:[attributeDict objectForKey:@"name"]]; + } else if ([elementName isEqualToString:@"plugin"]) { + [pluginsDict setObject:[attributeDict objectForKey:@"value"] forKey:[attributeDict objectForKey:@"name"]]; + } else if ([elementName isEqualToString:@"access"]) { + [whitelistHosts addObject:[attributeDict objectForKey:@"origin"]]; + } +} + +- (void)parser:(NSXMLParser*)parser parseErrorOccurred:(NSError*)parseError +{ + NSAssert(NO, @"config.xml parse error line %d col %d", [parser lineNumber], [parser columnNumber]); +} + +@end diff --git a/CordovaLib/Classes/CDVContact.m b/CordovaLib/Classes/CDVContact.m index 4efc84c..9389207 100755 --- a/CordovaLib/Classes/CDVContact.m +++ b/CordovaLib/Classes/CDVContact.m @@ -1146,7 +1146,7 @@ - (NSObject*)extractAddresses if (fields == nil) { // no name fields requested return nil; } - id __unsafe_unretained value; + id __weak value; NSObject* addresses; ABMultiValueRef multi = ABRecordCopyValue(self.record, kABPersonAddressProperty); CFIndex count = multi ? ABMultiValueGetCount(multi) : 0; @@ -1221,7 +1221,7 @@ - (NSObject*)extractIms NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:3]; // iOS has label property (work, home, other) for each IM but W3C contact API doesn't use CFDictionaryRef dict = (CFDictionaryRef)ABMultiValueCopyValueAtIndex(multi, i); - NSString* __unsafe_unretained value; // all values should be CFStringRefs / NSString* + NSString* __weak value; // all values should be CFStringRefs / NSString* bool bFound; if ([fields containsObject:kW3ContactFieldValue]) { // value = user name @@ -1694,7 +1694,7 @@ - (BOOL)searchContactFields:(NSArray*)fields forMVDictionaryProperty:(ABProperty for (NSString* member in fields) { NSString* abKey = [[CDVContact defaultW3CtoAB] valueForKey:member]; // im and address fields are all strings - NSString* __unsafe_unretained abValue = nil; + NSString* __weak abValue = nil; if (abKey) { NSString* testString = nil; if ([member isEqualToString:kW3ContactImType]) { diff --git a/CordovaLib/Classes/CDVContacts.m b/CordovaLib/Classes/CDVContacts.m index 429e7ec..3faf6ba 100755 --- a/CordovaLib/Classes/CDVContacts.m +++ b/CordovaLib/Classes/CDVContacts.m @@ -75,7 +75,7 @@ - (void)newContact:(CDVInvokedUrlCommand*)command NSString* callbackId = command.callbackId; CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __unsafe_unretained weakSelf = self; // play it safe to avoid retain cycles + CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError * errCode) { if (addrBook == NULL) { @@ -128,7 +128,7 @@ - (void)displayContact:(CDVInvokedUrlCommand*)command bool bEdit = [options isKindOfClass:[NSNull class]] ? false : [options existsValue:@"true" forKey:@"allowsEditing"]; CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __unsafe_unretained weakSelf = self; // play it safe to avoid retain cycles + CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError * errCode) { if (addrBook == NULL) { @@ -250,10 +250,9 @@ - (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationContr // if we got this far, user has already approved/ disapproved addressBook access ABAddressBookRef addrBook = nil; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000 - if (&ABAddressBookCreateWithOptions != NULL) { - addrBook = ABAddressBookCreateWithOptions(NULL, NULL); - } - else + if (&ABAddressBookCreateWithOptions != NULL) { + addrBook = ABAddressBookCreateWithOptions(NULL, NULL); + } else #endif { // iOS 4 & 5 @@ -289,8 +288,8 @@ - (void)search:(CDVInvokedUrlCommand*)command // which is why address book is created within the dispatch queue. // more details here: http: //blog.byadrian.net/2012/05/05/ios-addressbook-framework-and-gcd/ CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __unsafe_unretained weakSelf = self; // play it safe to avoid retain cycles - // it gets uglier, block within block..... + CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles + // it gets uglier, block within block..... [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError * errCode) { if (addrBook == NULL) { // permission was denied or other error - return error @@ -385,7 +384,7 @@ - (void)save:(CDVInvokedUrlCommand*)command [self.commandDelegate runInBackground:^{ CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __unsafe_unretained weakSelf = self; // play it safe to avoid retain cycles + CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError * errorCode) { CDVPluginResult* result = nil; @@ -456,7 +455,7 @@ - (void)remove:(CDVInvokedUrlCommand*)command NSNumber* cId = [command.arguments objectAtIndex:0]; CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __unsafe_unretained weakSelf = self; // play it safe to avoid retain cycles + CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError * errorCode) { CDVPluginResult* result = nil; @@ -564,12 +563,12 @@ - (void)createAddressBook:(CDVAddressBookWorkerBlock)workerBlock ABAddressBookRef addressBook; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000 - if (&ABAddressBookCreateWithOptions != NULL) { - CFErrorRef error = nil; - // CFIndex status = ABAddressBookGetAuthorizationStatus(); - addressBook = ABAddressBookCreateWithOptions(NULL, &error); - // NSLog(@"addressBook access: %lu", status); - ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { + if (&ABAddressBookCreateWithOptions != NULL) { + CFErrorRef error = nil; + // CFIndex status = ABAddressBookGetAuthorizationStatus(); + addressBook = ABAddressBookCreateWithOptions(NULL, &error); + // NSLog(@"addressBook access: %lu", status); + ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { // callback can occur in background, address book must be accessed on thread it was created on dispatch_sync (dispatch_get_main_queue (), ^{ if (error) { @@ -582,8 +581,7 @@ - (void)createAddressBook:(CDVAddressBookWorkerBlock)workerBlock } }); }); - } - else + } else #endif { // iOS 4 or 5 no checks needed diff --git a/CordovaLib/Classes/CDVDevice.m b/CordovaLib/Classes/CDVDevice.m index bd170e3..3fa4bb3 100755 --- a/CordovaLib/Classes/CDVDevice.m +++ b/CordovaLib/Classes/CDVDevice.m @@ -17,8 +17,28 @@ Licensed to the Apache Software Foundation (ASF) under one under the License. */ +#include +#include + #import "CDV.h" +@implementation UIDevice (ModelVersion) + +- (NSString*)modelVersion +{ + size_t size; + + sysctlbyname("hw.machine", NULL, &size, NULL, 0); + char* machine = malloc(size); + sysctlbyname("hw.machine", machine, &size, NULL, 0); + NSString* platform = [NSString stringWithUTF8String:machine]; + free(machine); + + return platform; +} + +@end + @interface CDVDevice () {} @end @@ -50,10 +70,11 @@ - (NSDictionary*)deviceProperties UIDevice* device = [UIDevice currentDevice]; NSMutableDictionary* devProps = [NSMutableDictionary dictionaryWithCapacity:4]; - [devProps setObject:[device model] forKey:@"platform"]; + [devProps setObject:[device modelVersion] forKey:@"model"]; + [devProps setObject:@"iOS" forKey:@"platform"]; [devProps setObject:[device systemVersion] forKey:@"version"]; [devProps setObject:[device uniqueAppInstanceIdentifier] forKey:@"uuid"]; - [devProps setObject:[device name] forKey:@"name"]; + [devProps setObject:[device model] forKey:@"name"]; [devProps setObject:[[self class] cordovaVersion] forKey:@"cordova"]; NSDictionary* devReturn = [NSDictionary dictionaryWithDictionary:devProps]; diff --git a/CordovaLib/Classes/CDVFileTransfer.m b/CordovaLib/Classes/CDVFileTransfer.m index ee42c6b..b25177a 100755 --- a/CordovaLib/Classes/CDVFileTransfer.m +++ b/CordovaLib/Classes/CDVFileTransfer.m @@ -302,6 +302,10 @@ - (void)abort:(CDVInvokedUrlCommand*)command if (delegate != nil) { [delegate.connection cancel]; [activeTransfers removeObjectForKey:objectId]; + + //delete uncomplete file + NSFileManager *fileMgr = [NSFileManager defaultManager]; + [fileMgr removeItemAtPath:delegate.target error:nil]; CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:CONNECTION_ABORTED AndSource:delegate.source AndTarget:delegate.target]]; [self.commandDelegate sendPluginResult:result callbackId:delegate.callbackId]; diff --git a/CordovaLib/Classes/CDVGlobalization.h b/CordovaLib/Classes/CDVGlobalization.h index a7f5a8f..0384656 100755 --- a/CordovaLib/Classes/CDVGlobalization.h +++ b/CordovaLib/Classes/CDVGlobalization.h @@ -6,9 +6,9 @@ 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 @@ -20,12 +20,12 @@ #import #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_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 +#define CDV_SELECTOR_DAYS 1 enum CDVGlobalizationError { CDV_UNKNOWN_ERROR = 0, @@ -35,33 +35,32 @@ enum CDVGlobalizationError { }; typedef NSUInteger CDVGlobalizationError; - @interface CDVGlobalization : CDVPlugin { CFLocaleRef currentLocale; } -- (void) getPreferredLanguage:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; +- (void)getPreferredLanguage:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; /** - * Returns the string identifier for the client’s current locale setting. + * 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; +- (void)getLocaleName:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; /** - * Returns a date formatted as a string according to the client’s user preferences and + * 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; +- (void)dateToString:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; /** - * Parses a date formatted as a string according to the client’s user + * 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 @@ -69,28 +68,28 @@ typedef NSUInteger CDVGlobalizationError; * * options: "dateString" contains the JavaScript string to parse for a date */ -- (void) stringToDate:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; +- (void)stringToDate:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; /** - * Returns a pattern string for formatting and parsing dates according to the client’s + * 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; +- (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 client’s user preferences and calendar. It returns the array of names to the + * 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; +- (void)getDateNames:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; /** - * Returns whether daylight savings time is in effect for a given date using the client’s + * 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. @@ -98,29 +97,29 @@ typedef NSUInteger CDVGlobalizationError; * options: "date" contains the number of milliseconds that represents the JavaScript date * */ -- (void) isDayLightSavingsTime:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; +- (void)isDayLightSavingsTime:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; /** - * Returns the first day of the week according to the client’s user preferences and calendar. + * 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; +- (void)getFirstDayOfWeek:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; /** - * Returns a number formatted as a string according to the client’s user preferences. + * 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; +- (void)numberToString:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; /** - * Parses a number formatted as a string according to the client’s user preferences and + * 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. @@ -128,24 +127,24 @@ typedef NSUInteger CDVGlobalizationError; * options: "numberString" contains the JavaScript string to parse for a number * */ -- (void) stringToNumber:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; +- (void)stringToNumber:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; /** - * Returns a pattern string for formatting and parsing numbers according to the client’s user + * 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; +- (void)getNumberPattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; /** - * Returns a pattern string for formatting and parsing currency values according to the client’s + * 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; +- (void)getCurrencyPattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; -@end \ No newline at end of file +@end diff --git a/CordovaLib/Classes/CDVInAppBrowser.h b/CordovaLib/Classes/CDVInAppBrowser.h new file mode 100755 index 0000000..51199ed --- /dev/null +++ b/CordovaLib/Classes/CDVInAppBrowser.h @@ -0,0 +1,72 @@ +/* + 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 + +- (void)browserLoadStart:(NSURL*)url; +- (void)browserLoadStop:(NSURL*)url; +- (void)browserExit; + +@end + +@interface CDVInAppBrowser : CDVPlugin {} + +@property (nonatomic, retain) CDVInAppBrowserViewController* inAppBrowserViewController; +@property (nonatomic, copy) NSString* callbackId; + +- (void)open:(CDVInvokedUrlCommand*)command; +- (void)close:(CDVInvokedUrlCommand*)command; + +@end + +@interface CDVInAppBrowserViewController : UIViewController {} + +@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 orientationDelegate; +@property (nonatomic, weak) id navigationDelegate; +@property (nonatomic, strong) NSString* userAgent; + +- (void)close; +- (void)navigateTo:(NSURL*)url; +- (void)showLocationBar:(BOOL)show; + +- (id)initWithUserAgent:(NSString*)userAgent; + +@end + +@interface CDVInAppBrowserOptions : NSObject {} + +@property (nonatomic, assign) BOOL location; + ++ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options; + +@end diff --git a/CordovaLib/Classes/CDVInAppBrowser.m b/CordovaLib/Classes/CDVInAppBrowser.m new file mode 100755 index 0000000..22fd1fc --- /dev/null +++ b/CordovaLib/Classes/CDVInAppBrowser.m @@ -0,0 +1,494 @@ +/* + 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" + +#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 = [CDVViewController originalUserAgent]; + self.inAppBrowserViewController = [[CDVInAppBrowserViewController alloc] initWithUserAgent:originalUA]; + self.inAppBrowserViewController.navigationDelegate = self; + + if ([self.viewController conformsToProtocol:@protocol(CDVScreenOrientationDelegate)]) { + self.inAppBrowserViewController.orientationDelegate = (UIViewController *)self.viewController; + } + } + + CDVInAppBrowserOptions* browserOptions = [CDVInAppBrowserOptions parseOptions:options]; + [self.inAppBrowserViewController showLocationBar:browserOptions.location]; + + 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]; + } +} + +@end + +#pragma mark CDVInAppBrowserViewController + +@implementation CDVInAppBrowserViewController + +- (id)initWithUserAgent:(NSString*)userAgent +{ + self = [super init]; + if (self != nil) { + self.userAgent = userAgent; + [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) { + // setting the UserAgent must occur before the UIWebView is instantiated. + // This is read per instantiation, so it does not affect the main Cordova UIWebView + NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:self.userAgent, @"UserAgent", nil]; + [[NSUserDefaults standardUserDefaults] registerDefaults:dict]; + + 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.scalesPageToFit = TRUE; + 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]; + + if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadStart:)]) { + [self.navigationDelegate browserLoadStart:theWebView.request.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]; + + if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadStop:)]) { + [self.navigationDelegate browserLoadStop:theWebView.request.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; + } + + 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]; + BOOL valueBool = [[value lowercaseString] isEqualToString:@"yes"]; + + // set the property according to the key name + if ([obj respondsToSelector:NSSelectorFromString(key)]) { + [obj setValue:[NSNumber numberWithBool:valueBool] forKey:key]; + } + } + } + + return obj; +} + +@end diff --git a/CordovaLib/Classes/CDVInvokedUrlCommand.h b/CordovaLib/Classes/CDVInvokedUrlCommand.h index 15a1df6..6eb0099 100755 --- a/CordovaLib/Classes/CDVInvokedUrlCommand.h +++ b/CordovaLib/Classes/CDVInvokedUrlCommand.h @@ -45,4 +45,13 @@ // 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 diff --git a/CordovaLib/Classes/CDVInvokedUrlCommand.m b/CordovaLib/Classes/CDVInvokedUrlCommand.m index fe67986..833baad 100755 --- a/CordovaLib/Classes/CDVInvokedUrlCommand.m +++ b/CordovaLib/Classes/CDVInvokedUrlCommand.m @@ -84,4 +84,29 @@ - (void)legacyArguments:(NSMutableArray**)legacyArguments andDict:(NSMutableDict } } +- (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 diff --git a/CordovaLib/Classes/CDVLocalStorage.m b/CordovaLib/Classes/CDVLocalStorage.m index 531ad4d..217f611 100755 --- a/CordovaLib/Classes/CDVLocalStorage.m +++ b/CordovaLib/Classes/CDVLocalStorage.m @@ -23,7 +23,7 @@ Licensed to the Apache Software Foundation (ASF) under one @interface CDVLocalStorage () @property (nonatomic, readwrite, strong) NSMutableArray* backupInfo; // array of CDVBackupInfo objects -@property (nonatomic, readwrite, unsafe_unretained) id webviewDelegate; +@property (nonatomic, readwrite, weak) id webviewDelegate; @end @@ -396,7 +396,7 @@ - (void)onResignActive backgroundTaskID = UIBackgroundTaskInvalid; NSLog (@"Background task to backup WebSQL/LocalStorage expired."); }]; - CDVLocalStorage __unsafe_unretained* weakSelf = self; + CDVLocalStorage __weak* weakSelf = self; [self.commandDelegate runInBackground:^{ [weakSelf backup:nil]; diff --git a/CordovaLib/Classes/CDVPlugin.h b/CordovaLib/Classes/CDVPlugin.h index f9b1377..8c59a2b 100755 --- a/CordovaLib/Classes/CDVPlugin.h +++ b/CordovaLib/Classes/CDVPlugin.h @@ -25,14 +25,14 @@ #define CDVPluginHandleOpenURLNotification @"CDVPluginHandleOpenURLNotification" #define CDVPluginResetNotification @"CDVPluginResetNotification" +#define CDVLocalNotification @"CDVLocalNotification" @interface CDVPlugin : NSObject {} -// TODO(agrieve): Make these zeroing weak refs once we drop support for 4.3. -@property (nonatomic, unsafe_unretained) UIWebView* webView; +@property (nonatomic, weak) UIWebView* webView; @property (nonatomic, strong) NSDictionary* settings; -@property (nonatomic, unsafe_unretained) UIViewController* viewController; -@property (nonatomic, unsafe_unretained) id commandDelegate; +@property (nonatomic, weak) UIViewController* viewController; +@property (nonatomic, weak) id commandDelegate; @property (readonly, assign) BOOL hasPendingOperation; @@ -51,6 +51,7 @@ - (void) onResume {} - (void) onOrientationWillChange {} - (void) onOrientationDidChange {} + - (void)didReceiveLocalNotification:(NSNotification *)notification; */ - (id)appDelegate; diff --git a/CordovaLib/Classes/CDVPlugin.m b/CordovaLib/Classes/CDVPlugin.m index 9d83f27..53023c7 100755 --- a/CordovaLib/Classes/CDVPlugin.m +++ b/CordovaLib/Classes/CDVPlugin.m @@ -59,6 +59,10 @@ - (CDVPlugin*)initWithWebView:(UIWebView*)theWebView [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResume) name:UIApplicationWillEnterForegroundNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationWillChange) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationDidChange) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; + + // Added in 2.3.0+ + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveLocalNotification:) name:CDVLocalNotification object:nil]; + */ } return self; @@ -135,4 +139,10 @@ - (NSString*)error:(CDVPluginResult*)pluginResult callbackId:(NSString*)callback return @""; } +// default implementation does nothing, ideally, we are not registered for notification if we aren't going to do anything. +//- (void)didReceiveLocalNotification:(NSNotification *)notification +//{ +// // UILocalNotification* localNotification = [notification object]; // get the payload as a LocalNotification +//} + @end diff --git a/CordovaLib/Classes/CDVScreenOrientationDelegate.h b/CordovaLib/Classes/CDVScreenOrientationDelegate.h new file mode 100755 index 0000000..7226205 --- /dev/null +++ b/CordovaLib/Classes/CDVScreenOrientationDelegate.h @@ -0,0 +1,28 @@ +/* + 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 + +@protocol CDVScreenOrientationDelegate + +- (NSUInteger)supportedInterfaceOrientations; +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; +- (BOOL)shouldAutorotate; + +@end diff --git a/CordovaLib/Classes/CDVSound.m b/CordovaLib/Classes/CDVSound.m index 6598fa1..f7a3adf 100755 --- a/CordovaLib/Classes/CDVSound.m +++ b/CordovaLib/Classes/CDVSound.m @@ -283,7 +283,7 @@ - (BOOL)prepareToPlay:(CDVAudioFile*)audioFile withId:(NSString*)mediaId // bug in AVAudioPlayer when playing downloaded data in NSData - we have to download the file and play from disk CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault); CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef); - NSString* filePath = [NSString stringWithFormat:@"%@/%@.mp3", [NSTemporaryDirectory ()stringByStandardizingPath], uuidString]; + NSString* filePath = [NSString stringWithFormat:@"%@/%@", [NSTemporaryDirectory ()stringByStandardizingPath], uuidString]; CFRelease(uuidString); CFRelease(uuidRef); @@ -355,15 +355,13 @@ - (void)seekToAudio:(CDVInvokedUrlCommand*)command CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; double position = [[command.arguments objectAtIndex:1] doubleValue]; - if ((audioFile != nil) && (audioFile.player != nil) && position) { + if ((audioFile != nil) && (audioFile.player != nil)) { double posInSeconds = position / 1000; audioFile.player.currentTime = posInSeconds; NSString* jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%f);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_POSITION, posInSeconds]; [self.commandDelegate evalJs:jsString]; } - - return; } - (void)release:(CDVInvokedUrlCommand*)command @@ -440,20 +438,28 @@ - (void)startRecordingAudio:(CDVInvokedUrlCommand*)command // create a new recorder for each start record audioFile.recorder = [[CDVAudioRecorder alloc] initWithURL:audioFile.resourceURL settings:nil error:&error]; - if (error != nil) { - errorMsg = [NSString stringWithFormat:@"Failed to initialize AVAudioRecorder: %@\n", [error localizedFailureReason]]; + bool recordingSuccess = NO; + if (error == nil) { + audioFile.recorder.delegate = self; + audioFile.recorder.mediaId = mediaId; + recordingSuccess = [audioFile.recorder record]; + if (recordingSuccess) { + NSLog(@"Started recording audio sample '%@'", audioFile.resourcePath); + jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_RUNNING]; + } + } + + if ((error != nil) || (recordingSuccess == NO)) { + if (error != nil) { + errorMsg = [NSString stringWithFormat:@"Failed to initialize AVAudioRecorder: %@\n", [error localizedFailureReason]]; + } else { + errorMsg = @"Failed to start recording using AVAudioRecorder"; + } audioFile.recorder = nil; if (self.avSession) { [self.avSession setActive:NO error:nil]; } - // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, MEDIA_ERR_ABORTED]; jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]]; - } else { - audioFile.recorder.delegate = self; - audioFile.recorder.mediaId = mediaId; - [audioFile.recorder record]; - NSLog(@"Started recording audio sample '%@'", audioFile.resourcePath); - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_RUNNING]; } } else { // file does not exist diff --git a/CordovaLib/Classes/CDVURLProtocol.m b/CordovaLib/Classes/CDVURLProtocol.m index 2e37b06..a645288 100755 --- a/CordovaLib/Classes/CDVURLProtocol.m +++ b/CordovaLib/Classes/CDVURLProtocol.m @@ -33,6 +33,37 @@ - (id)initWithBlankResponse:(NSURL*)url; // the actual pointer to avoid retaining. static NSMutableSet* gRegisteredControllers = nil; +// Returns the registered view controller that sent the given request. +// If the user-agent is not from a UIWebView, or if it's from an unregistered one, +// then nil is returned. +static CDVViewController *viewControllerForRequest(NSURLRequest* request) +{ + // The exec bridge explicitly sets the VC address in a header. + // This works around the User-Agent not being set for file: URLs. + NSString* addrString = [request valueForHTTPHeaderField:@"vc"]; + + if (addrString == nil) { + NSString* userAgent = [request valueForHTTPHeaderField:@"User-Agent"]; + if (userAgent == nil) { + return nil; + } + NSUInteger bracketLocation = [userAgent rangeOfString:@"(" options:NSBackwardsSearch].location; + if (bracketLocation == NSNotFound) { + return nil; + } + addrString = [userAgent substringFromIndex:bracketLocation + 1]; + } + + long long viewControllerAddress = [addrString longLongValue]; + @synchronized(gRegisteredControllers) { + if (![gRegisteredControllers containsObject:[NSNumber numberWithLongLong:viewControllerAddress]]) { + return nil; + } + } + + return (__bridge CDVViewController*)(void*)viewControllerAddress; +} + @implementation CDVURLProtocol + (void)registerPGHttpURLProtocol {} @@ -57,6 +88,7 @@ + (void)registerViewController:(CDVViewController*)viewController NSLog(@"WARNING: NO whitelist has been set in CDVURLProtocol."); } } + @synchronized(gRegisteredControllers) { [gRegisteredControllers addObject:[NSNumber numberWithLongLong:(long long)viewController]]; } @@ -64,55 +96,44 @@ + (void)registerViewController:(CDVViewController*)viewController + (void)unregisterViewController:(CDVViewController*)viewController { - [gRegisteredControllers removeObject:[NSNumber numberWithLongLong:(long long)viewController]]; + @synchronized(gRegisteredControllers) { + [gRegisteredControllers removeObject:[NSNumber numberWithLongLong:(long long)viewController]]; + } } + (BOOL)canInitWithRequest:(NSURLRequest*)theRequest { NSURL* theUrl = [theRequest URL]; - NSString* theScheme = [theUrl scheme]; - - if ([[theUrl path] isEqualToString:@"/!gap_exec"]) { - NSString* viewControllerAddressStr = [theRequest valueForHTTPHeaderField:@"vc"]; - if (viewControllerAddressStr == nil) { - NSLog(@"!cordova request missing vc header"); - return NO; - } - long long viewControllerAddress = [viewControllerAddressStr longLongValue]; - // Ensure that the CDVViewController has not been dealloc'ed. - CDVViewController* viewController = nil; - @synchronized(gRegisteredControllers) { - if (![gRegisteredControllers containsObject:[NSNumber numberWithLongLong:viewControllerAddress]]) { + CDVViewController* viewController = viewControllerForRequest(theRequest); + + if (viewController != nil) { + if ([[theUrl path] isEqualToString:@"/!gap_exec"]) { + NSString* queuedCommandsJSON = [theRequest valueForHTTPHeaderField:@"cmds"]; + NSString* requestId = [theRequest valueForHTTPHeaderField:@"rc"]; + if (requestId == nil) { + NSLog(@"!cordova request missing rc header"); return NO; } - viewController = (__bridge CDVViewController*)(void*)viewControllerAddress; - } - - NSString* queuedCommandsJSON = [theRequest valueForHTTPHeaderField:@"cmds"]; - NSString* requestId = [theRequest valueForHTTPHeaderField:@"rc"]; - if (requestId == nil) { - NSLog(@"!cordova request missing rc header"); - return NO; + BOOL hasCmds = [queuedCommandsJSON length] > 0; + if (hasCmds) { + SEL sel = @selector(enqueCommandBatch:); + [viewController.commandQueue performSelectorOnMainThread:sel withObject:queuedCommandsJSON waitUntilDone:NO]; + } else { + SEL sel = @selector(maybeFetchCommandsFromJs:); + [viewController.commandQueue performSelectorOnMainThread:sel withObject:[NSNumber numberWithInteger:[requestId integerValue]] waitUntilDone:NO]; + } + // Returning NO here would be 20% faster, but it spams WebInspector's console with failure messages. + // If JS->Native bridge speed is really important for an app, they should use the iframe bridge. + // Returning YES here causes the request to come through canInitWithRequest two more times. + // For this reason, we return NO when cmds exist. + return !hasCmds; } - BOOL hasCmds = [queuedCommandsJSON length] > 0; - if (hasCmds) { - SEL sel = @selector(enqueCommandBatch:); - [viewController.commandQueue performSelectorOnMainThread:sel withObject:queuedCommandsJSON waitUntilDone:NO]; - } else { - SEL sel = @selector(maybeFetchCommandsFromJs:); - [viewController.commandQueue performSelectorOnMainThread:sel withObject:[NSNumber numberWithInteger:[requestId integerValue]] waitUntilDone:NO]; + // we only care about http and https connections. + // CORS takes care of http: trying to access file: URLs. + if ([gWhitelist schemeIsAllowed:[theUrl scheme]]) { + // if it FAILS the whitelist, we return TRUE, so we can fail the connection later + return ![gWhitelist URLIsAllowed:theUrl]; } - // Returning NO here would be 20% faster, but it spams WebInspector's console with failure messages. - // If JS->Native bridge speed is really important for an app, they should use the iframe bridge. - // Returning YES here causes the request to come through canInitWithRequest two more times. - // For this reason, we return NO when cmds exist. - return !hasCmds; - } - - // we only care about http and https connections - if ([gWhitelist schemeIsAllowed:theScheme]) { - // if it FAILS the whitelist, we return TRUE, so we can fail the connection later - return ![gWhitelist URLIsAllowed:theUrl]; } return NO; diff --git a/CordovaLib/Classes/CDVViewController.h b/CordovaLib/Classes/CDVViewController.h index 0cf717f..8318398 100755 --- a/CordovaLib/Classes/CDVViewController.h +++ b/CordovaLib/Classes/CDVViewController.h @@ -24,13 +24,17 @@ #import "CDVInvokedUrlCommand.h" #import "CDVCommandDelegate.h" #import "CDVWhitelist.h" +#import "CDVScreenOrientationDelegate.h" @class CDVCommandQueue; @class CDVCommandDelegateImpl; -@interface CDVViewController : UIViewController { - @private +@interface CDVViewController : UIViewController { + @protected CDVCommandDelegateImpl* _commandDelegate; + @protected + CDVCommandQueue* _commandQueue; + NSString* _userAgent; } @property (nonatomic, strong) IBOutlet CDVCordovaView* webView; @@ -38,6 +42,7 @@ @property (nonatomic, readonly, strong) NSMutableDictionary* pluginObjects; @property (nonatomic, readonly, strong) NSDictionary* pluginsMap; @property (nonatomic, readonly, strong) NSDictionary* settings; +@property (nonatomic, readonly, strong) NSXMLParser* configParser; @property (nonatomic, readonly, strong) CDVWhitelist* whitelist; // readonly for public @property (nonatomic, readonly, assign) BOOL loadFromString; @property (nonatomic, readwrite, copy)NSString * invokeString CDV_DEPRECATED(2.0, "Use window.handleOpenURL(url instead. It is called when the app is launched through a custom scheme url."); @@ -50,9 +55,11 @@ @property (nonatomic, readwrite, copy) NSString* startPage; @property (nonatomic, readonly, strong) CDVCommandQueue* commandQueue; @property (nonatomic, readonly, strong) CDVCommandDelegateImpl* commandDelegate; +@property (nonatomic, readonly) NSString* userAgent; + (NSDictionary*)getBundlePlist:(NSString*)plistName; + (NSString*)applicationDocumentsDirectory; ++ (NSString*)originalUserAgent; - (void)printMultitaskingInfo; - (void)createGapView; @@ -67,4 +74,6 @@ - (id)getCommandInstance:(NSString*)pluginName; - (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className; +- (BOOL)URLisAllowed:(NSURL*)url; + @end diff --git a/CordovaLib/Classes/CDVViewController.m b/CordovaLib/Classes/CDVViewController.m index a47d649..f1b36df 100755 --- a/CordovaLib/Classes/CDVViewController.m +++ b/CordovaLib/Classes/CDVViewController.m @@ -21,11 +21,17 @@ Licensed to the Apache Software Foundation (ASF) under one #import "CDV.h" #import "CDVCommandQueue.h" #import "CDVCommandDelegateImpl.h" +#import "CDVConfigParser.h" #define degreesToRadian(x) (M_PI * (x) / 180.0) +#define CDV_USER_AGENT_KEY @"Cordova-User-Agent" +#define CDV_USER_AGENT_VERSION_KEY @"Cordova-User-Agent-Version" + +static NSString* gOriginalUserAgent = nil; @interface CDVViewController () +@property (nonatomic, readwrite, strong) NSXMLParser* configParser; @property (nonatomic, readwrite, strong) NSDictionary* settings; @property (nonatomic, readwrite, strong) CDVWhitelist* whitelist; @property (nonatomic, readwrite, strong) NSMutableDictionary* pluginObjects; @@ -43,10 +49,11 @@ @implementation CDVViewController @synthesize webView, supportedOrientations; @synthesize pluginObjects, pluginsMap, whitelist; -@synthesize settings, loadFromString; +@synthesize configParser, settings, loadFromString; @synthesize imageView, activityView, useSplashScreen; @synthesize wwwFolderName, startPage, invokeString, initialized; @synthesize commandDelegate = _commandDelegate; +@synthesize commandQueue = _commandQueue; - (void)__init { @@ -62,6 +69,8 @@ - (void)__init name:UIApplicationWillResignActiveNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppLocaleDidChange:) + name:NSCurrentLocaleDidChangeNotification object:nil]; if (IsAtLeastiOSVersion(@"4.0")) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillEnterForeground:) @@ -76,18 +85,13 @@ - (void)__init self.wwwFolderName = @"www"; self.startPage = @"index.html"; - [self setWantsFullScreenLayout:YES]; [self printMultitaskingInfo]; [self printDeprecationNotice]; self.initialized = YES; - // load Cordova.plist settings + // load config.xml settings [self loadSettings]; - // set the whitelist - self.whitelist = [[CDVWhitelist alloc] initWithArray:[self.settings objectForKey:@"ExternalHosts"]]; - // register this viewcontroller with the NSURLProtocol - [CDVURLProtocol registerViewController:self]; } } @@ -107,8 +111,8 @@ - (id)init - (void)printDeprecationNotice { - if (!IsAtLeastiOSVersion(@"4.2")) { - NSLog(@"CRITICAL: For Cordova 2.0, you will need to upgrade to at least iOS 4.2 or greater. Your current version of iOS is %@.", + if (!IsAtLeastiOSVersion(@"5.0")) { + NSLog(@"CRITICAL: For Cordova 2.0, you will need to upgrade to at least iOS 5.0 or greater. Your current version of iOS is %@.", [[UIDevice currentDevice] systemVersion] ); } @@ -131,28 +135,44 @@ - (void)printMultitaskingInfo NSLog(@"Multi-tasking -> Device: %@, App: %@", (backgroundSupported ? @"YES" : @"NO"), (![exitsOnSuspend intValue]) ? @"YES" : @"NO"); } +- (BOOL)URLisAllowed:(NSURL*)url +{ + if (self.whitelist == nil) { + return YES; + } + + return [self.whitelist URLIsAllowed:url]; +} + - (void)loadSettings { - self.pluginObjects = [[NSMutableDictionary alloc] initWithCapacity:4]; + CDVConfigParser* delegate = [[CDVConfigParser alloc] init]; + + // read from config.xml in the app bundle + NSString* path = [[NSBundle mainBundle] pathForResource:@"config" ofType:@"xml"]; - // read from Cordova.plist in the app bundle - NSString* appPlistName = @"Cordova"; - NSDictionary* cordovaPlist = [[self class] getBundlePlist:appPlistName]; - if (cordovaPlist == nil) { - NSLog(@"WARNING: %@.plist is missing.", appPlistName); + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { + NSAssert(NO, @"ERROR: config.xml does not exist. Please run cordova-ios/bin/cordova_plist_to_config_xml path/to/project."); return; } - self.settings = [[NSDictionary alloc] initWithDictionary:cordovaPlist]; - // read from Plugins dict in Cordova.plist in the app bundle - NSString* pluginsKey = @"Plugins"; - NSDictionary* pluginsDict = [self.settings objectForKey:@"Plugins"]; - if (pluginsDict == nil) { - NSLog(@"WARNING: %@ key in %@.plist is missing! Cordova will not work, you need to have this key.", pluginsKey, appPlistName); + NSURL* url = [NSURL fileURLWithPath:path]; + + configParser = [[NSXMLParser alloc] initWithContentsOfURL:url]; + if (configParser == nil) { + NSLog(@"Failed to initialize XML parser."); return; } + [configParser setDelegate:((id < NSXMLParserDelegate >)delegate)]; + [configParser parse]; - self.pluginsMap = [pluginsDict dictionaryWithLowercaseKeys]; + // Get the plugin dictionary, whitelist and settings from the delegate. + self.pluginsMap = [delegate.pluginsDict dictionaryWithLowercaseKeys]; + self.whitelist = [[CDVWhitelist alloc] initWithArray:delegate.whitelistHosts]; + self.settings = delegate.settings; + + // Initialize the plugin objects dict. + self.pluginObjects = [[NSMutableDictionary alloc] initWithCapacity:4]; } // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. @@ -160,17 +180,23 @@ - (void)viewDidLoad { [super viewDidLoad]; - NSString* startFilePath = [_commandDelegate pathForResource:self.startPage]; NSURL* appURL = nil; NSString* loadErr = nil; - if (startFilePath == nil) { - loadErr = [NSString stringWithFormat:@"ERROR: Start Page at '%@/%@' was not found.", self.wwwFolderName, self.startPage]; - NSLog(@"%@", loadErr); - self.loadFromString = YES; - appURL = nil; + if ([self.startPage rangeOfString:@"://"].location != NSNotFound) { + appURL = [NSURL URLWithString:self.startPage]; + } else if ([self.wwwFolderName rangeOfString:@"://"].location != NSNotFound) { + appURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/%@", self.wwwFolderName, self.startPage]]; } else { - appURL = [NSURL fileURLWithPath:startFilePath]; + NSString* startFilePath = [self.commandDelegate pathForResource:self.startPage]; + if (startFilePath == nil) { + loadErr = [NSString stringWithFormat:@"ERROR: Start Page at '%@/%@' was not found.", self.wwwFolderName, self.startPage]; + NSLog(@"%@", loadErr); + self.loadFromString = YES; + appURL = nil; + } else { + appURL = [NSURL fileURLWithPath:startFilePath]; + } } // // Fix the iOS 5.1 SECURITY_ERR bug (CB-347), this must be before the webView is instantiated //// @@ -210,14 +236,14 @@ - (void)viewDidLoad */ if ([enableLocation boolValue]) { - [[self getCommandInstance:@"Geolocation"] getLocation:[CDVInvokedUrlCommand new]]; + [[self.commandDelegate getCommandInstance:@"Geolocation"] getLocation:[CDVInvokedUrlCommand new]]; } /* * Fire up CDVLocalStorage to work-around WebKit storage limitations: on all iOS 5.1+ versions for local-only backups, but only needed on iOS 5.1 for cloud backup. */ - if (IsAtLeastiOSVersion(@"5.1") && (([backupWebStorage isEqualToString:@"local"]) || - ([backupWebStorage isEqualToString:@"cloud"] && !IsAtLeastiOSVersion(@"6.0")))) { + if (IsAtLeastiOSVersion(@"5.1") && (([backupWebStorageType isEqualToString:@"local"]) || + ([backupWebStorageType isEqualToString:@"cloud"] && !IsAtLeastiOSVersion(@"6.0")))) { [self registerPlugin:[[CDVLocalStorage alloc] initWithWebView:self.webView settings:[NSDictionary dictionaryWithObjectsAndKeys: @"backupType", backupWebStorageType, nil]] withClassName:NSStringFromClass([CDVLocalStorage class])]; } @@ -237,7 +263,7 @@ - (void)viewDidLoad BOOL bounceAllowed = (bouncePreference == nil || [bouncePreference boolValue]); // prevent webView from bouncing - // based on UIWebViewBounce key in Cordova.plist + // based on UIWebViewBounce key in config.xml if (!bounceAllowed) { if ([self.webView respondsToSelector:@selector(scrollView)]) { ((UIScrollView*)[self.webView scrollView]).bounces = NO; @@ -405,6 +431,41 @@ - (CDVCordovaView*)newCordovaViewWithFrame:(CGRect)bounds return [[CDVCordovaView alloc] initWithFrame:bounds]; } ++ (NSString*)originalUserAgent +{ + if (gOriginalUserAgent == nil) { + NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; + NSString* systemVersion = [[UIDevice currentDevice] systemVersion]; + NSString* localeStr = [[NSLocale currentLocale] localeIdentifier]; + NSString* systemAndLocale = [NSString stringWithFormat:@"%@ %@", systemVersion, localeStr]; + + NSString* cordovaUserAgentVersion = [userDefaults stringForKey:CDV_USER_AGENT_VERSION_KEY]; + gOriginalUserAgent = [userDefaults stringForKey:CDV_USER_AGENT_KEY]; + BOOL cachedValueIsOld = ![systemAndLocale isEqualToString:cordovaUserAgentVersion]; + + if ((gOriginalUserAgent == nil) || cachedValueIsOld) { + UIWebView* sampleWebView = [[UIWebView alloc] initWithFrame:CGRectZero]; + gOriginalUserAgent = [sampleWebView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"]; + + [userDefaults setObject:gOriginalUserAgent forKey:CDV_USER_AGENT_KEY]; + [userDefaults setObject:systemAndLocale forKey:CDV_USER_AGENT_VERSION_KEY]; + + [userDefaults synchronize]; + } + } + return gOriginalUserAgent; +} + +- (NSString*)userAgent +{ + if (_userAgent == nil) { + NSString* originalUserAgent = [[self class] originalUserAgent]; + // Use our address as a unique number to append to the User-Agent. + _userAgent = [NSString stringWithFormat:@"%@ (%lld)", originalUserAgent, (long long)self]; + } + return _userAgent; +} + - (void)createGapView { CGRect webViewBounds = self.view.bounds; @@ -412,6 +473,11 @@ - (void)createGapView webViewBounds.origin = self.view.bounds.origin; if (!self.webView) { + // setting the UserAgent must occur before the UIWebView is instantiated. + // This is read per instantiation, so it does not affect the main Cordova UIWebView + NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:self.userAgent, @"UserAgent", nil]; + [[NSUserDefaults standardUserDefaults] registerDefaults:dict]; + self.webView = [self newCordovaViewWithFrame:webViewBounds]; self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); @@ -419,6 +485,9 @@ - (void)createGapView [self.view sendSubviewToBack:self.webView]; self.webView.delegate = self; + + // register this viewcontroller with the NSURLProtocol, only after the User-Agent is set + [CDVURLProtocol registerViewController:self]; } } @@ -487,10 +556,9 @@ - (void)webViewDidFinishLoad:(UIWebView*)theWebView } [self didRotateFromInterfaceOrientation:(UIInterfaceOrientation)[[UIDevice currentDevice] orientation]]; - // The iOSVCAddr is used to identify the WebView instance when using one of the XHR js->native bridge modes. // The .onNativeReady().fire() will work when cordova.js is already loaded. // The _nativeReady = true; is used when this is run before cordova.js is loaded. - NSString* nativeReady = [NSString stringWithFormat:@"cordova.iOSVCAddr='%lld';try{cordova.require('cordova/channel').onNativeReady.fire();}catch(e){window._nativeReady = true;}", (long long)self]; + NSString* nativeReady = @"try{cordova.require('cordova/channel').onNativeReady.fire();}catch(e){window._nativeReady = true;}"; [self.commandDelegate evalJs:nativeReady]; } @@ -522,29 +590,6 @@ - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest* */ else if ([url isFileURL]) { return YES; - } else if ([self.whitelist schemeIsAllowed:[url scheme]]) { - if ([self.whitelist URLIsAllowed:url] == YES) { - NSNumber* openAllInWhitelistSetting = [self.settings objectForKey:@"OpenAllWhitelistURLsInWebView"]; - if ((nil != openAllInWhitelistSetting) && [openAllInWhitelistSetting boolValue]) { - NSLog(@"OpenAllWhitelistURLsInWebView set: opening in webview"); - return YES; - } - - // mainDocument will be nil for an iFrame - NSString* mainDocument = [theWebView.request.mainDocumentURL absoluteString]; - - // anchor target="_blank" - load in Mobile Safari - if ((navigationType == UIWebViewNavigationTypeOther) && (mainDocument != nil)) { - [[UIApplication sharedApplication] openURL:url]; - return NO; - } - // other anchor target - load in Cordova webView - else { - return YES; - } - } - - return NO; } /* @@ -577,16 +622,19 @@ - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest* } /* - * We don't have a Cordova or web/local request, load it in the main Safari browser. - * pass this to the application to handle. Could be a mailto:dude@duderanch.com or a tel:55555555 or sms:55555555 facetime:55555555 + * Handle all other types of urls (tel:, sms:), and requests to load a url in the main webview. */ else { - NSLog(@"AppDelegate::shouldStartLoadWithRequest: Received Unhandled URL %@", url); + // BOOL isIFrame = ([theWebView.request.mainDocumentURL absoluteString] == nil); - if ([[UIApplication sharedApplication] canOpenURL:url]) { - [[UIApplication sharedApplication] openURL:url]; - } else { // handle any custom schemes to plugins - [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]]; + if ([self.whitelist schemeIsAllowed:[url scheme]]) { + return [self.whitelist URLIsAllowed:url]; + } else { + if ([[UIApplication sharedApplication] canOpenURL:url]) { + [[UIApplication sharedApplication] openURL:url]; + } else { // handle any custom schemes to plugins + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]]; + } } return NO; @@ -705,7 +753,7 @@ - (void)showSplashScreen self.imageView.tag = 1; self.imageView.center = center; - self.imageView.autoresizingMask = (UIViewAutoresizingFlexibleWidth & UIViewAutoresizingFlexibleHeight & UIViewAutoresizingFlexibleLeftMargin & UIViewAutoresizingFlexibleRightMargin); + self.imageView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin); [self.imageView setTransform:startupImageTransform]; [self.view.superview addSubview:self.imageView]; @@ -908,6 +956,11 @@ - (void)onAppDidEnterBackground:(NSNotification*)notification [self.commandDelegate evalJs:@"cordova.fireDocumentEvent('pause', null, true);" scheduledOnRunLoop:NO]; } +- (void)onAppLocaleDidChange:(NSNotification*)notification +{ + gOriginalUserAgent = nil; +} + // /////////////////////// - (void)dealloc @@ -918,6 +971,7 @@ - (void)dealloc [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:NSCurrentLocaleDidChangeNotification object:nil]; self.webView.delegate = nil; self.webView = nil; diff --git a/CordovaLib/Classes/CDVWhitelist.h b/CordovaLib/Classes/CDVWhitelist.h index 0eb28f9..3741e94 100755 --- a/CordovaLib/Classes/CDVWhitelist.h +++ b/CordovaLib/Classes/CDVWhitelist.h @@ -19,11 +19,14 @@ #import +extern NSString* const kCDVDefaultWhitelistRejectionString; + @interface CDVWhitelist : NSObject @property (nonatomic, readonly, strong) NSArray* whitelist; @property (nonatomic, readonly, strong) NSArray* expandedWhitelist; @property (nonatomic, readonly, assign) BOOL allowAll; +@property (nonatomic, copy) NSString* whitelistRejectionFormatString; - (id)initWithArray:(NSArray*)array; - (BOOL)URLIsAllowed:(NSURL*)url; diff --git a/CordovaLib/Classes/CDVWhitelist.m b/CordovaLib/Classes/CDVWhitelist.m index ad2a0c6..77e20ac 100755 --- a/CordovaLib/Classes/CDVWhitelist.m +++ b/CordovaLib/Classes/CDVWhitelist.m @@ -19,6 +19,8 @@ Licensed to the Apache Software Foundation (ASF) under one #import "CDVWhitelist.h" +NSString* const kCDVDefaultWhitelistRejectionString = @"ERROR whitelist rejection: url='%@'"; + @interface CDVWhitelist () @property (nonatomic, readwrite, strong) NSArray* whitelist; @@ -31,7 +33,7 @@ - (void)processWhitelist; @implementation CDVWhitelist -@synthesize whitelist, expandedWhitelist, allowAll; +@synthesize whitelist, expandedWhitelist, allowAll, whitelistRejectionFormatString; - (id)initWithArray:(NSArray*)array { @@ -40,6 +42,7 @@ - (id)initWithArray:(NSArray*)array self.whitelist = array; self.expandedWhitelist = nil; self.allowAll = NO; + self.whitelistRejectionFormatString = kCDVDefaultWhitelistRejectionString; [self processWhitelist]; } @@ -183,7 +186,7 @@ - (BOOL)URLIsAllowed:(NSURL*)url - (NSString*)errorStringForURL:(NSURL*)url { - return [NSString stringWithFormat:@"ERROR whitelist rejection: url='%@'", [url absoluteString]]; + return [NSString stringWithFormat:self.whitelistRejectionFormatString, [url absoluteString]]; } @end diff --git a/CordovaLib/CordovaLib.xcodeproj/project.pbxproj b/CordovaLib/CordovaLib.xcodeproj/project.pbxproj index 06dc0c8..1bb7fa7 100755 --- a/CordovaLib/CordovaLib.xcodeproj/project.pbxproj +++ b/CordovaLib/CordovaLib.xcodeproj/project.pbxproj @@ -22,6 +22,9 @@ 30392E4E14F4FCAB00B9E0B8 /* CDVAvailability.h in Headers */ = {isa = PBXBuildFile; fileRef = 30392E4D14F4FCAB00B9E0B8 /* CDVAvailability.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3062D120151D0EDB000D9128 /* UIDevice+Extensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 3062D11E151D0EDB000D9128 /* UIDevice+Extensions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3062D122151D0EDB000D9128 /* UIDevice+Extensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 3062D11F151D0EDB000D9128 /* UIDevice+Extensions.m */; }; + 3073E9E91656D37700957977 /* CDVInAppBrowser.h in Headers */ = {isa = PBXBuildFile; fileRef = 3073E9E71656D37700957977 /* CDVInAppBrowser.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3073E9EA1656D37700957977 /* CDVInAppBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = 3073E9E81656D37700957977 /* CDVInAppBrowser.m */; }; + 3073E9ED1656D51200957977 /* CDVScreenOrientationDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 3073E9EC1656D51200957977 /* CDVScreenOrientationDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 307A8F9E1385A2EC00E43782 /* CDVConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 307A8F9C1385A2EC00E43782 /* CDVConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; 307A8F9F1385A2EC00E43782 /* CDVConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 307A8F9D1385A2EC00E43782 /* CDVConnection.m */; }; 30A90B9114588697006178D3 /* JSONKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 30A90B8F14588697006178D3 /* JSONKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -69,18 +72,20 @@ 8887FDA01090FBE7009987E8 /* CDVSound.m in Sources */ = {isa = PBXBuildFile; fileRef = 8887FD611090FBE7009987E8 /* CDVSound.m */; }; 88BA573D109BB46F00FB5E78 /* CDVAccelerometer.h in Headers */ = {isa = PBXBuildFile; fileRef = 88BA573B109BB46F00FB5E78 /* CDVAccelerometer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 88BA573E109BB46F00FB5E78 /* CDVAccelerometer.m in Sources */ = {isa = PBXBuildFile; fileRef = 88BA573C109BB46F00FB5E78 /* CDVAccelerometer.m */; }; - 9D76CF3C1625A4C50008A0F6 /* CDVGlobalization.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D76CF3A1625A4C50008A0F6 /* CDVGlobalization.h */; }; + 9D76CF3C1625A4C50008A0F6 /* CDVGlobalization.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D76CF3A1625A4C50008A0F6 /* CDVGlobalization.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9D76CF3D1625A4C50008A0F6 /* CDVGlobalization.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D76CF3B1625A4C50008A0F6 /* CDVGlobalization.m */; }; C937A4561337599E002C4C79 /* CDVFileTransfer.h in Headers */ = {isa = PBXBuildFile; fileRef = C937A4541337599E002C4C79 /* CDVFileTransfer.h */; settings = {ATTRIBUTES = (Public, ); }; }; C937A4571337599E002C4C79 /* CDVFileTransfer.m in Sources */ = {isa = PBXBuildFile; fileRef = C937A4551337599E002C4C79 /* CDVFileTransfer.m */; }; - EB3B3547161CB44D003DBE7D /* CDVCommandQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = EB3B3545161CB44D003DBE7D /* CDVCommandQueue.h */; }; + EB3B3547161CB44D003DBE7D /* CDVCommandQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = EB3B3545161CB44D003DBE7D /* CDVCommandQueue.h */; settings = {ATTRIBUTES = (Public, ); }; }; EB3B3548161CB44D003DBE7D /* CDVCommandQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = EB3B3546161CB44D003DBE7D /* CDVCommandQueue.m */; }; - EB3B357C161F2A45003DBE7D /* CDVCommandDelegateImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = EB3B357A161F2A44003DBE7D /* CDVCommandDelegateImpl.h */; }; + EB3B357C161F2A45003DBE7D /* CDVCommandDelegateImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = EB3B357A161F2A44003DBE7D /* CDVCommandDelegateImpl.h */; settings = {ATTRIBUTES = (Public, ); }; }; EB3B357D161F2A45003DBE7D /* CDVCommandDelegateImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = EB3B357B161F2A45003DBE7D /* CDVCommandDelegateImpl.m */; }; - EB80C2AC15DEA63D004D9E7B /* CDVEcho.h in Headers */ = {isa = PBXBuildFile; fileRef = EB80C2AA15DEA63D004D9E7B /* CDVEcho.h */; }; + EB80C2AC15DEA63D004D9E7B /* CDVEcho.h in Headers */ = {isa = PBXBuildFile; fileRef = EB80C2AA15DEA63D004D9E7B /* CDVEcho.h */; settings = {ATTRIBUTES = (Public, ); }; }; EB80C2AD15DEA63D004D9E7B /* CDVEcho.m in Sources */ = {isa = PBXBuildFile; fileRef = EB80C2AB15DEA63D004D9E7B /* CDVEcho.m */; }; EBA3557315ABD38C00F4DE24 /* NSArray+Comparisons.h in Headers */ = {isa = PBXBuildFile; fileRef = EBA3557115ABD38C00F4DE24 /* NSArray+Comparisons.h */; settings = {ATTRIBUTES = (Public, ); }; }; EBA3557515ABD38C00F4DE24 /* NSArray+Comparisons.m in Sources */ = {isa = PBXBuildFile; fileRef = EBA3557215ABD38C00F4DE24 /* NSArray+Comparisons.m */; }; + F858FBC6166009A8007DA594 /* CDVConfigParser.h in Headers */ = {isa = PBXBuildFile; fileRef = F858FBC4166009A8007DA594 /* CDVConfigParser.h */; }; + F858FBC7166009A8007DA594 /* CDVConfigParser.m in Sources */ = {isa = PBXBuildFile; fileRef = F858FBC5166009A8007DA594 /* CDVConfigParser.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -100,6 +105,9 @@ 30392E4D14F4FCAB00B9E0B8 /* CDVAvailability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVAvailability.h; path = Classes/CDVAvailability.h; sourceTree = ""; }; 3062D11E151D0EDB000D9128 /* UIDevice+Extensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIDevice+Extensions.h"; path = "Classes/UIDevice+Extensions.h"; sourceTree = ""; }; 3062D11F151D0EDB000D9128 /* UIDevice+Extensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIDevice+Extensions.m"; path = "Classes/UIDevice+Extensions.m"; sourceTree = ""; }; + 3073E9E71656D37700957977 /* CDVInAppBrowser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVInAppBrowser.h; path = Classes/CDVInAppBrowser.h; sourceTree = ""; }; + 3073E9E81656D37700957977 /* CDVInAppBrowser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVInAppBrowser.m; path = Classes/CDVInAppBrowser.m; sourceTree = ""; }; + 3073E9EC1656D51200957977 /* CDVScreenOrientationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVScreenOrientationDelegate.h; path = Classes/CDVScreenOrientationDelegate.h; sourceTree = ""; }; 307A8F9C1385A2EC00E43782 /* CDVConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVConnection.h; path = Classes/CDVConnection.h; sourceTree = ""; }; 307A8F9D1385A2EC00E43782 /* CDVConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVConnection.m; path = Classes/CDVConnection.m; sourceTree = ""; }; 30A90B8F14588697006178D3 /* JSONKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONKit.h; sourceTree = ""; }; @@ -172,6 +180,8 @@ EB80C2AB15DEA63D004D9E7B /* CDVEcho.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVEcho.m; path = Classes/CDVEcho.m; sourceTree = ""; }; EBA3557115ABD38C00F4DE24 /* NSArray+Comparisons.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSArray+Comparisons.h"; path = "Classes/NSArray+Comparisons.h"; sourceTree = ""; }; EBA3557215ABD38C00F4DE24 /* NSArray+Comparisons.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSArray+Comparisons.m"; path = "Classes/NSArray+Comparisons.m"; sourceTree = ""; }; + F858FBC4166009A8007DA594 /* CDVConfigParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVConfigParser.h; path = Classes/CDVConfigParser.h; sourceTree = ""; }; + F858FBC5166009A8007DA594 /* CDVConfigParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVConfigParser.m; path = Classes/CDVConfigParser.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -226,6 +236,8 @@ 3054098714B77FF3009841CA /* Cleaver */ = { isa = PBXGroup; children = ( + F858FBC4166009A8007DA594 /* CDVConfigParser.h */, + F858FBC5166009A8007DA594 /* CDVConfigParser.m */, 8852C43614B65FD800F0E735 /* CDVViewController.h */, 8852C43714B65FD800F0E735 /* CDVViewController.m */, 8852C43814B65FD800F0E735 /* CDVCordovaView.h */, @@ -302,6 +314,9 @@ 3E76876C156A90EE00EB6FA3 /* CDVLogger.h */, 9D76CF3A1625A4C50008A0F6 /* CDVGlobalization.h */, 9D76CF3B1625A4C50008A0F6 /* CDVGlobalization.m */, + 3073E9E71656D37700957977 /* CDVInAppBrowser.h */, + 3073E9E81656D37700957977 /* CDVInAppBrowser.m */, + 3073E9EC1656D51200957977 /* CDVScreenOrientationDelegate.h */, ); name = Commands; sourceTree = ""; @@ -391,6 +406,9 @@ EB3B3547161CB44D003DBE7D /* CDVCommandQueue.h in Headers */, EB3B357C161F2A45003DBE7D /* CDVCommandDelegateImpl.h in Headers */, 9D76CF3C1625A4C50008A0F6 /* CDVGlobalization.h in Headers */, + 3073E9E91656D37700957977 /* CDVInAppBrowser.h in Headers */, + 3073E9ED1656D51200957977 /* CDVScreenOrientationDelegate.h in Headers */, + F858FBC6166009A8007DA594 /* CDVConfigParser.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -420,7 +438,7 @@ 0867D690FE84028FC02AAC07 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0460; + LastUpgradeCheck = 0430; }; buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "CordovaLib" */; compatibilityVersion = "Xcode 3.2"; @@ -483,6 +501,8 @@ EB3B3548161CB44D003DBE7D /* CDVCommandQueue.m in Sources */, EB3B357D161F2A45003DBE7D /* CDVCommandDelegateImpl.m in Sources */, 9D76CF3D1625A4C50008A0F6 /* CDVGlobalization.m in Sources */, + 3073E9EA1656D37700957977 /* CDVInAppBrowser.m in Sources */, + F858FBC7166009A8007DA594 /* CDVConfigParser.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -511,7 +531,7 @@ GCC_THUMB_SUPPORT = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INSTALL_PATH = /usr/local/lib; - IPHONEOS_DEPLOYMENT_TARGET = 4.3; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; PRODUCT_NAME = Cordova; PUBLIC_HEADERS_FOLDER_PATH = include/Cordova; SKIP_INSTALL = YES; @@ -537,7 +557,7 @@ GCC_THUMB_SUPPORT = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INSTALL_PATH = /usr/local/lib; - IPHONEOS_DEPLOYMENT_TARGET = 4.3; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; PRODUCT_NAME = Cordova; PUBLIC_HEADERS_FOLDER_PATH = include/Cordova; SKIP_INSTALL = YES; @@ -553,17 +573,12 @@ armv7s, ); "ARCHS[sdk=iphonesimulator*]" = i386; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; GCC_C_LANGUAGE_STANDARD = c99; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ""; GCC_THUMB_SUPPORT = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 4.3; ONLY_ACTIVE_ARCH = NO; @@ -586,16 +601,11 @@ armv7s, ); "ARCHS[sdk=iphonesimulator*]" = i386; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; GCC_C_LANGUAGE_STANDARD = c99; GCC_PREPROCESSOR_DEFINITIONS = ""; GCC_THUMB_SUPPORT = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 4.3; ONLY_ACTIVE_ARCH = NO; diff --git a/CordovaLib/VERSION b/CordovaLib/VERSION index e3a4f19..cc6612c 100755 --- a/CordovaLib/VERSION +++ b/CordovaLib/VERSION @@ -1 +1 @@ -2.2.0 \ No newline at end of file +2.3.0 \ No newline at end of file From fbe1594eb197eca95b2a988ec927c4c9a5fcdfe4 Mon Sep 17 00:00:00 2001 From: George Garside Date: Fri, 19 Apr 2013 16:44:31 +0100 Subject: [PATCH 05/32] Update Cordova.plist to config.xml --- TDA-Enrichment.xcodeproj/project.pbxproj | 8 +-- TDA-Enrichment/Cordova.plist | 83 ------------------------ TDA-Enrichment/config.xml | 45 +++++++++++++ 3 files changed, 49 insertions(+), 87 deletions(-) delete mode 100755 TDA-Enrichment/Cordova.plist create mode 100644 TDA-Enrichment/config.xml diff --git a/TDA-Enrichment.xcodeproj/project.pbxproj b/TDA-Enrichment.xcodeproj/project.pbxproj index 24ee81b..f39308f 100644 --- a/TDA-Enrichment.xcodeproj/project.pbxproj +++ b/TDA-Enrichment.xcodeproj/project.pbxproj @@ -45,7 +45,7 @@ 302D95F214D2391D003F00A1 /* MainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 302D95F014D2391D003F00A1 /* MainViewController.xib */; }; 305D5FD1115AB8F900A74A75 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 305D5FD0115AB8F900A74A75 /* MobileCoreServices.framework */; }; 3072F99713A8081B00425683 /* Capture.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 3072F99613A8081B00425683 /* Capture.bundle */; }; - 30E1352710E2C1420031B30D /* Cordova.plist in Resources */ = {isa = PBXBuildFile; fileRef = 30E1352610E2C1420031B30D /* Cordova.plist */; }; + 30E1352710E2C1420031B30D /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 30E1352610E2C1420031B30D /* config.xml */; }; 30E5649213A7FCAF007403D8 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30E5649113A7FCAF007403D8 /* CoreMedia.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; /* End PBXBuildFile section */ @@ -115,7 +115,7 @@ 3072F99613A8081B00425683 /* Capture.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Capture.bundle; sourceTree = ""; }; 30A0434414DC770100060A13 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Localizable.strings; sourceTree = ""; }; 30A0434714DC770100060A13 /* se */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = se; path = Localizable.strings; sourceTree = ""; }; - 30E1352610E2C1420031B30D /* Cordova.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Cordova.plist; path = ../Cordova.plist; sourceTree = ""; }; + 30E1352610E2C1420031B30D /* config.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = config.xml; path = ../config.xml; sourceTree = ""; }; 30E5649113A7FCAF007403D8 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; 32CA4F630368D1EE00C91783 /* TDA-Enrichment-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TDA-Enrichment-Prefix.pch"; sourceTree = ""; }; 8D1107310486CEB800E47090 /* TDA-Enrichment-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "TDA-Enrichment-Info.plist"; path = "../TDA-Enrichment-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; @@ -303,7 +303,7 @@ 1F766FDB13BBADB100FB74C0 /* en.lproj */, 1F766FDE13BBADB100FB74C0 /* es.lproj */, 3072F99613A8081B00425683 /* Capture.bundle */, - 30E1352610E2C1420031B30D /* Cordova.plist */, + 30E1352610E2C1420031B30D /* config.xml */, 8D1107310486CEB800E47090 /* TDA-Enrichment-Info.plist */, ); name = Resources; @@ -440,7 +440,7 @@ buildActionMask = 2147483647; files = ( 301BF570109A69640062928A /* www in Resources */, - 30E1352710E2C1420031B30D /* Cordova.plist in Resources */, + 30E1352710E2C1420031B30D /* config.xml in Resources */, 3072F99713A8081B00425683 /* Capture.bundle in Resources */, 1F766FE113BBADB100FB74C0 /* Localizable.strings in Resources */, 302D95F214D2391D003F00A1 /* MainViewController.xib in Resources */, diff --git a/TDA-Enrichment/Cordova.plist b/TDA-Enrichment/Cordova.plist deleted file mode 100755 index ed35b73..0000000 --- a/TDA-Enrichment/Cordova.plist +++ /dev/null @@ -1,83 +0,0 @@ - - - - - KeyboardDisplayRequiresUserAction - - SuppressesIncrementalRendering - - UIWebViewBounce - - TopActivityIndicator - gray - EnableLocation - - EnableViewportScale - - AutoHideSplashScreen - - ShowSplashScreenSpinner - - MediaPlaybackRequiresUserAction - - AllowInlineMediaPlayback - - OpenAllWhitelistURLsInWebView - - BackupWebStorage - cloud - ExternalHosts - - *.testflightapp.com - *.georgegarside.x10.bz - *.thomasdeaconacademy.com - *.thomasdeaconacademy.peterborough.sch.uk - http://www.danone.co.uk/SiteImages/Assets/0/GDA_545px.jpg - *.cloudfront.net - *.kissmetrics.com - - Plugins - - ChildBrowserCommand - ChildBrowserCommand - ChildBrowser - ChildBrowser.js - Device - CDVDevice - Logger - CDVLogger - Compass - CDVLocation - Accelerometer - CDVAccelerometer - Camera - CDVCamera - NetworkStatus - CDVConnection - Contacts - CDVContacts - Debug Console - CDVDebugConsole - Echo - CDVEcho - File - CDVFile - FileTransfer - CDVFileTransfer - Geolocation - CDVLocation - Notification - CDVNotification - Media - CDVSound - Capture - CDVCapture - SplashScreen - CDVSplashScreen - Battery - CDVBattery - Globalization - CDVGlobalization - - - diff --git a/TDA-Enrichment/config.xml b/TDA-Enrichment/config.xml new file mode 100644 index 0000000..96cdb57 --- /dev/null +++ b/TDA-Enrichment/config.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 0720df631a573946fbb4873c748bf599f4fed935 Mon Sep 17 00:00:00 2001 From: George Garside Date: Fri, 19 Apr 2013 16:45:21 +0100 Subject: [PATCH 06/32] Update Cordova JavaScript --- www/{cordova-2.2.0.js => cordova-2.3.0.js} | 714 ++++++++++----------- 1 file changed, 328 insertions(+), 386 deletions(-) rename www/{cordova-2.2.0.js => cordova-2.3.0.js} (92%) diff --git a/www/cordova-2.2.0.js b/www/cordova-2.3.0.js similarity index 92% rename from www/cordova-2.2.0.js rename to www/cordova-2.3.0.js index b63d517..a8e5f6b 100755 --- a/www/cordova-2.2.0.js +++ b/www/cordova-2.3.0.js @@ -1,6 +1,6 @@ -// commit 02b91c5313ff37d74a58f71775170afd360f4a1f +// commit 24d65ab645742e8360c3dd16d7a36411cc3383e0 -// File generated at :: Wed Oct 31 2012 14:34:26 GMT-0700 (PDT) +// File generated at :: Thu Jan 03 2013 16:57:26 GMT-0800 (PST) /* Licensed to the Apache Software Foundation (ASF) under one @@ -314,6 +314,65 @@ channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready'); module.exports = cordova; +}); + +// file: lib/common/argscheck.js +define("cordova/argscheck", function(require, exports, module) { + +var exec = require('cordova/exec'); +var moduleExports = module.exports; + +var typeMap = { + 'A': 'Array', + 'D': 'Date', + 'N': 'Number', + 'S': 'String', + 'F': 'Function', + 'O': 'Object' +}; + +function extractParamName(callee, argIndex) { + return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex]; +} + +function checkArgs(spec, functionName, args, opt_callee) { + if (!moduleExports.enableChecks) { + return; + } + var errMsg = null; + var type; + for (var i = 0; i < spec.length; ++i) { + var c = spec.charAt(i), + cUpper = c.toUpperCase(), + arg = args[i]; + // Asterix means allow anything. + if (c == '*') { + continue; + } + type = Object.prototype.toString.call(arg).slice(8, -1); + if ((arg === null || arg === undefined) && c == cUpper) { + continue; + } + if (type != typeMap[cUpper]) { + errMsg = 'Expected ' + typeMap[cUpper]; + break; + } + } + if (errMsg) { + errMsg += ', but got ' + type + '.'; + errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg; + // Don't log when running jake test. + if (typeof jasmine == 'undefined') { + console.error(errMsg); + } + throw TypeError(errMsg); + } +} + +moduleExports.checkArgs = checkArgs; +moduleExports.enableChecks = true; + + }); // file: lib/common/builder.js @@ -329,14 +388,24 @@ function each(objects, func, context) { } } +function clobber(obj, key, value) { + obj[key] = value; + // Getters can only be overridden by getters. + if (obj[key] !== value) { + utils.defineGetter(obj, key, function() { + return value; + }); + } +} + function assignOrWrapInDeprecateGetter(obj, key, value, message) { if (message) { utils.defineGetter(obj, key, function() { - window.console && console.log(message); + console.log(message); return value; }); } else { - obj[key] = value; + clobber(obj, key, value); } } @@ -395,8 +464,11 @@ function recursiveMerge(target, src) { // If the target object is a constructor override off prototype. target.prototype[prop] = src[prop]; } else { - target[prop] = typeof src[prop] === 'object' ? recursiveMerge( - target[prop], src[prop]) : src[prop]; + if (typeof src[prop] === 'object') { + target[prop] = recursiveMerge(target[prop], src[prop]); + } else { + clobber(target, prop, src[prop]); + } } } } @@ -404,18 +476,14 @@ function recursiveMerge(target, src) { } module.exports = { - build: function (objects) { - return { - intoButDoNotClobber: function (target) { - include(target, objects, false, false); - }, - intoAndClobber: function(target) { - include(target, objects, true, false); - }, - intoAndMerge: function(target) { - include(target, objects, true, true); - } - }; + buildIntoButDoNotClobber: function(objects, target) { + include(target, objects, false, false); + }, + buildIntoAndClobber: function(objects, target) { + include(target, objects, true, false); + }, + buildIntoAndMerge: function(objects, target) { + include(target, objects, true, true); } }; @@ -701,7 +769,7 @@ module.exports = { define("cordova/common", function(require, exports, module) { module.exports = { - objects: { + defaults: { cordova: { path: 'cordova', children: { @@ -720,6 +788,9 @@ module.exports = { } } }, + open : { + path: 'cordova/plugin/InAppBrowser' + }, navigator: { children: { notification: { @@ -737,9 +808,6 @@ module.exports = { compass:{ path: 'cordova/plugin/compass' }, - connection: { - path: 'cordova/plugin/network' - }, contacts: { path: 'cordova/plugin/contacts' }, @@ -907,6 +975,15 @@ module.exports = { resolveLocalFileSystemURI:{ path: 'cordova/plugin/resolveLocalFileSystemURI' } + }, + clobbers: { + navigator: { + children: { + connection: { + path: 'cordova/plugin/network' + } + } + } } }; @@ -915,12 +992,12 @@ module.exports = { // file: lib/ios/exec.js define("cordova/exec", function(require, exports, module) { - /** - * Creates a gap bridge iframe used to notify the native code about queued - * commands. - * - * @private - */ +/** + * Creates a gap bridge iframe used to notify the native code about queued + * commands. + * + * @private + */ var cordova = require('cordova'), channel = require('cordova/channel'), utils = require('cordova/utils'), @@ -930,13 +1007,11 @@ var cordova = require('cordova'), XHR_WITH_PAYLOAD: 2, XHR_OPTIONAL_PAYLOAD: 3 }, - // XHR mode does not work on iOS 4.2, so default to IFRAME_NAV for such devices. - // XHR mode's main advantage is working around a bug in -webkit-scroll, which - // doesn't exist in 4.X devices anyways. - bridgeMode = navigator.userAgent.indexOf(' 4_') == -1 ? jsToNativeModes.XHR_NO_PAYLOAD : jsToNativeModes.IFRAME_NAV, + bridgeMode, execIframe, execXhr, requestCount = 0, + vcHeaderValue = null, commandQueue = [], // Contains pending JS->Native messages. isInContextOfEvalJs = 0; @@ -963,10 +1038,11 @@ function shouldBundleCommandJson() { } function iOSExec() { - if (channel.onCordovaReady.state != 2) { - utils.alert("ERROR: Attempting to call cordova.exec()" + - " before 'deviceready'. Ignoring."); - return; + // XHR mode does not work on iOS 4.2, so default to IFRAME_NAV for such devices. + // XHR mode's main advantage is working around a bug in -webkit-scroll, which + // doesn't exist in 4.X devices anyways. + if (bridgeMode === undefined) { + bridgeMode = navigator.userAgent.indexOf(' 4_') == -1 ? jsToNativeModes.XHR_NO_PAYLOAD : jsToNativeModes.IFRAME_NAV; } var successCallback, failCallback, service, action, actionArgs, splitCommand; @@ -1007,21 +1083,26 @@ function iOSExec() { // the command is executed. commandQueue.push(JSON.stringify(command)); - if (!isInContextOfEvalJs) { + // If we're in the context of a stringByEvaluatingJavaScriptFromString call, + // then the queue will be flushed when it returns; no need for a poke. + // Also, if there is already a command in the queue, then we've already + // poked the native side, so there is no reason to do so again. + if (!isInContextOfEvalJs && commandQueue.length == 1) { if (bridgeMode != jsToNativeModes.IFRAME_NAV) { - // Re-using the XHR improves exec() performance by about 10%. - // It is possible for a native stringByEvaluatingJavascriptFromString call - // to cause us to reach this point when a request is already in progress, - // so we check the readyState to guard agains re-using an inprogress XHR. - // Refer to CB-1404. + // This prevents sending an XHR when there is already one being sent. + // This should happen only in rare circumstances (refer to unit tests). if (execXhr && execXhr.readyState != 4) { execXhr = null; } + // Re-using the XHR improves exec() performance by about 10%. execXhr = execXhr || new XMLHttpRequest(); // Changing this to a GET will make the XHR reach the URIProtocol on 4.2. // For some reason it still doesn't work though... execXhr.open('HEAD', "/!gap_exec", true); - execXhr.setRequestHeader('vc', cordova.iOSVCAddr); + if (!vcHeaderValue) { + vcHeaderValue = /.*\((.*)\)/.exec(navigator.userAgent)[1]; + } + execXhr.setRequestHeader('vc', vcHeaderValue); execXhr.setRequestHeader('rc', ++requestCount); if (shouldBundleCommandJson()) { execXhr.setRequestHeader('cmds', iOSExec.nativeFetchMessages()); @@ -1059,7 +1140,7 @@ iOSExec.nativeFetchMessages = function() { iOSExec.nativeCallback = function(callbackId, status, payload, keepCallback) { return iOSExec.nativeEvalAndFetch(function() { - var success = status == 0 || status == 1; + var success = status === 0 || status === 1; cordova.callbackFromNative(callbackId, success, status, payload, keepCallback); }); }; @@ -1085,15 +1166,8 @@ define("cordova/platform", function(require, exports, module) { module.exports = { id: "ios", initialize:function() { - // iOS doesn't allow reassigning / overriding navigator.geolocation object. - // So clobber its methods here instead :) - var geo = require('cordova/plugin/geolocation'); - - navigator.geolocation.getCurrentPosition = geo.getCurrentPosition; - navigator.geolocation.watchPosition = geo.watchPosition; - navigator.geolocation.clearWatch = geo.clearWatch; }, - objects: { + clobbers: { File: { // exists natively, override path: "cordova/plugin/File" }, @@ -1105,6 +1179,9 @@ module.exports = { }, console: { path: 'cordova/plugin/ios/console' + }, + open : { + path: 'cordova/plugin/InAppBrowser' } }, merges:{ @@ -1124,6 +1201,9 @@ module.exports = { }, contacts:{ path:"cordova/plugin/ios/contacts" + }, + geolocation: { + path: 'cordova/plugin/geolocation' } } } @@ -3135,6 +3215,62 @@ GlobalizationError.PATTERN_ERROR = 3; module.exports = GlobalizationError; +}); + +// file: lib/common/plugin/InAppBrowser.js +define("cordova/plugin/InAppBrowser", function(require, exports, module) { + +var exec = require('cordova/exec'); + +function InAppBrowser() +{ + var _channel = require('cordova/channel'); + this.channels = { + 'loadstart': _channel.create('loadstart'), + 'loadstop' : _channel.create('loadstop'), + 'exit' : _channel.create('exit') + }; +} + +InAppBrowser.prototype._eventHandler = function(event) +{ + if (event.type in this.channels) { + this.channels[event.type].fire(event); + } +} + +InAppBrowser.open = function(strUrl, strWindowName, strWindowFeatures) +{ + var iab = new InAppBrowser(); + var cb = function(eventname) { + iab._eventHandler(eventname); + } + exec(cb, null, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]); + return iab; +} + +InAppBrowser.prototype.close = function(eventname, f) +{ + exec(null, null, "InAppBrowser", "close", []); +} + +InAppBrowser.prototype.addEventListener = function(eventname, f) +{ + if (eventname in this.channels) { + this.channels[eventname].subscribe(f); + } +} + +InAppBrowser.prototype.removeEventListener = function(eventname, f) +{ + if (eventname in this.channels) { + this.channels[eventname].unsubscribe(f); + } +} + +module.exports = InAppBrowser.open; + + }); // file: lib/common/plugin/LocalFileSystem.js @@ -3573,7 +3709,8 @@ define("cordova/plugin/accelerometer", function(require, exports, module) { * This class provides access to device accelerometer data. * @constructor */ -var utils = require("cordova/utils"), +var argscheck = require('cordova/argscheck'), + utils = require("cordova/utils"), exec = require("cordova/exec"), Acceleration = require('cordova/plugin/Acceleration'); @@ -3637,10 +3774,7 @@ var accelerometer = { * @param {AccelerationOptions} options The options for getting the accelerometer data such as timeout. (OPTIONAL) */ getCurrentAcceleration: function(successCallback, errorCallback, options) { - // successCallback required - if (typeof successCallback !== "function") { - throw "getCurrentAcceleration must be called with at least a success callback function as first parameter."; - } + argscheck.checkArgs('fFO', 'accelerometer.getCurrentAcceleration', arguments); var p; var win = function(a) { @@ -3649,7 +3783,7 @@ var accelerometer = { }; var fail = function(e) { removeListeners(p); - errorCallback(e); + errorCallback && errorCallback(e); }; p = createCallbackPair(win, fail); @@ -3669,20 +3803,16 @@ var accelerometer = { * @return String The watch id that must be passed to #clearWatch to stop watching. */ watchAcceleration: function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'accelerometer.watchAcceleration', arguments); // Default interval (10 sec) var frequency = (options && options.frequency && typeof options.frequency == 'number') ? options.frequency : 10000; - // successCallback required - if (typeof successCallback !== "function") { - throw "watchAcceleration must be called with at least a success callback function as first parameter."; - } - // Keep reference to watch id, and report accel readings as often as defined in frequency var id = utils.createUUID(); var p = createCallbackPair(function(){}, function(e) { removeListeners(p); - errorCallback(e); + errorCallback && errorCallback(e); }); listeners.push(p); @@ -3698,7 +3828,7 @@ var accelerometer = { if (running) { // If we're already running then immediately invoke the success callback // but only if we have retrieved a value, sample code does not check for null ... - if(accel) { + if (accel) { successCallback(accel); } } else { @@ -3892,7 +4022,8 @@ module.exports = new Capture(); // file: lib/common/plugin/compass.js define("cordova/plugin/compass", function(require, exports, module) { -var exec = require('cordova/exec'), +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), utils = require('cordova/utils'), CompassHeading = require('cordova/plugin/CompassHeading'), CompassError = require('cordova/plugin/CompassError'), @@ -3907,23 +4038,13 @@ var exec = require('cordova/exec'), * @param {CompassOptions} options The options for getting the heading data (not used). */ getCurrentHeading:function(successCallback, errorCallback, options) { - // successCallback required - if (typeof successCallback !== "function") { - console.log("Compass Error: successCallback is not a function"); - return; - } - - // errorCallback optional - if (errorCallback && (typeof errorCallback !== "function")) { - console.log("Compass Error: errorCallback is not a function"); - return; - } + argscheck.checkArgs('fFO', 'compass.getCurrentHeading', arguments); var win = function(result) { var ch = new CompassHeading(result.magneticHeading, result.trueHeading, result.headingAccuracy, result.timestamp); successCallback(ch); }; - var fail = function(code) { + var fail = errorCallback && function(code) { var ce = new CompassError(code); errorCallback(ce); }; @@ -3943,22 +4064,11 @@ var exec = require('cordova/exec'), * specifies to watch via a distance filter rather than time. */ watchHeading:function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'compass.watchHeading', arguments); // Default interval (100 msec) var frequency = (options !== undefined && options.frequency !== undefined) ? options.frequency : 100; var filter = (options !== undefined && options.filter !== undefined) ? options.filter : 0; - // successCallback required - if (typeof successCallback !== "function") { - console.log("Compass Error: successCallback is not a function"); - return; - } - - // errorCallback optional - if (errorCallback && (typeof errorCallback !== "function")) { - console.log("Compass Error: errorCallback is not a function"); - return; - } - var id = utils.createUUID(); if (filter > 0) { // is an iOS request for watch by filter, no timer needed @@ -3982,8 +4092,8 @@ var exec = require('cordova/exec'), // Stop javascript timer & remove from timer list if (id && timers[id]) { if (timers[id] != "iOS") { - clearInterval(timers[id]); - } else { + clearInterval(timers[id]); + } else { // is iOS watch by filter so call into device to stop exec(null, null, "Compass", "stopHeading", []); } @@ -4171,7 +4281,8 @@ for (var key in console) { // file: lib/common/plugin/contacts.js define("cordova/plugin/contacts", function(require, exports, module) { -var exec = require('cordova/exec'), +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), ContactError = require('cordova/plugin/ContactError'), utils = require('cordova/utils'), Contact = require('cordova/plugin/Contact'); @@ -4190,13 +4301,9 @@ var contacts = { * @return array of Contacts matching search criteria */ find:function(fields, successCB, errorCB, options) { - if (!successCB) { - throw new TypeError("You must specify a success callback for the find command."); - } - if (!fields || (utils.isArray(fields) && fields.length === 0)) { - if (typeof errorCB === "function") { - errorCB(new ContactError(ContactError.INVALID_ARGUMENT_ERROR)); - } + argscheck.checkArgs('afFO', 'contacts.find', arguments); + if (!fields.length) { + errorCB && errorCB(new ContactError(ContactError.INVALID_ARGUMENT_ERROR)); } else { var win = function(result) { var cs = []; @@ -4217,9 +4324,9 @@ var contacts = { * @returns new Contact object */ create:function(properties) { - var i; + argscheck.checkArgs('O', 'contacts.create', arguments); var contact = new Contact(); - for (i in properties) { + for (var i in properties) { if (typeof contact[i] !== 'undefined' && properties.hasOwnProperty(i)) { contact[i] = properties[i]; } @@ -4235,7 +4342,8 @@ module.exports = contacts; // file: lib/common/plugin/device.js define("cordova/plugin/device", function(require, exports, module) { -var channel = require('cordova/channel'), +var argscheck = require('cordova/argscheck'), + channel = require('cordova/channel'), utils = require('cordova/utils'), exec = require('cordova/exec'); @@ -4254,6 +4362,7 @@ function Device() { this.name = null; this.uuid = null; this.cordova = null; + this.model = null; var me = this; @@ -4265,6 +4374,7 @@ function Device() { me.name = info.name; me.uuid = info.uuid; me.cordova = info.cordova; + me.model = info.model; channel.onCordovaInfoReady.fire(); },function(e) { me.available = false; @@ -4280,20 +4390,7 @@ function Device() { * @param {Function} errorCallback The function to call when there is an error getting the heading data. (OPTIONAL) */ Device.prototype.getInfo = function(successCallback, errorCallback) { - - // successCallback required - if (typeof successCallback !== "function") { - console.log("Device Error: successCallback is not a function"); - return; - } - - // errorCallback optional - if (errorCallback && (typeof errorCallback !== "function")) { - console.log("Device Error: errorCallback is not a function"); - return; - } - - // Get info + argscheck.checkArgs('fF', 'Device.getInfo', arguments); exec(successCallback, errorCallback, "Device", "getDeviceInfo", []); }; @@ -4324,7 +4421,8 @@ module.exports = function(successCallback, errorCallback, message, forceAsync) { // file: lib/common/plugin/geolocation.js define("cordova/plugin/geolocation", function(require, exports, module) { -var utils = require('cordova/utils'), +var argscheck = require('cordova/argscheck'), + utils = require('cordova/utils'), exec = require('cordova/exec'), PositionError = require('cordova/plugin/PositionError'), Position = require('cordova/plugin/Position'); @@ -4381,9 +4479,7 @@ var geolocation = { * @param {PositionOptions} options The options for getting the position data. (OPTIONAL) */ getCurrentPosition:function(successCallback, errorCallback, options) { - if (arguments.length === 0) { - throw new Error("getCurrentPosition must be called with at least one argument."); - } + argscheck.checkArgs('fFO', 'geolocation.getCurrentPosition', arguments); options = parseParameters(options); // Timer var that will fire an error callback if no position is retrieved from native @@ -4459,9 +4555,7 @@ var geolocation = { * @return String The watch id that must be passed to #clearWatch to stop watching. */ watchPosition:function(successCallback, errorCallback, options) { - if (arguments.length === 0) { - throw new Error("watchPosition must be called with at least one argument."); - } + argscheck.checkArgs('fFO', 'geolocation.getCurrentPosition', arguments); options = parseParameters(options); var id = utils.createUUID(); @@ -4523,7 +4617,8 @@ module.exports = geolocation; // file: lib/common/plugin/globalization.js define("cordova/plugin/globalization", function(require, exports, module) { -var exec = require('cordova/exec'), +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), GlobalizationError = require('cordova/plugin/GlobalizationError'); var globalization = { @@ -4546,18 +4641,7 @@ var globalization = { * function () {}); */ getPreferredLanguage:function(successCB, failureCB) { - // successCallback required - if (typeof successCB != "function") { - console.log("Globalization.getPreferredLanguage Error: successCB is not a function"); - return; - } - - // errorCallback required - if (typeof failureCB != "function") { - console.log("Globalization.getPreferredLanguage Error: failureCB is not a function"); - return; - } - + argscheck.checkArgs('fF', 'Globalization.getPreferredLanguage', arguments); exec(successCB, failureCB, "Globalization","getPreferredLanguage", []); }, @@ -4579,17 +4663,7 @@ getPreferredLanguage:function(successCB, failureCB) { * function () {}); */ getLocaleName:function(successCB, failureCB) { - // successCallback required - if (typeof successCB != "function") { - console.log("Globalization.getLocaleName Error: successCB is not a function"); - return; - } - - // errorCallback required - if (typeof failureCB != "function") { - console.log("Globalization.getLocaleName Error: failureCB is not a function"); - return; - } + argscheck.checkArgs('fF', 'Globalization.getLocaleName', arguments); exec(successCB, failureCB, "Globalization","getLocaleName", []); }, @@ -4620,27 +4694,9 @@ getLocaleName:function(successCB, failureCB) { * {formatLength:'short'}); */ dateToString:function(date, successCB, failureCB, options) { - // successCallback required - if (typeof successCB != "function") { - console.log("Globalization.dateToString Error: successCB is not a function"); - return; - } - - // errorCallback required - if (typeof failureCB != "function") { - console.log("Globalization.dateToString Error: failureCB is not a function"); - return; - } - - - if (date instanceof Date){ - var dateValue; - dateValue = date.valueOf(); - exec(successCB, failureCB, "Globalization", "dateToString", [{"date": dateValue, "options": options}]); - } - else { - console.log("Globalization.dateToString Error: date is not a Date object"); - } + argscheck.checkArgs('dfFO', 'Globalization.dateToString', arguments); + var dateValue = date.valueOf(); + exec(successCB, failureCB, "Globalization", "dateToString", [{"date": dateValue, "options": options}]); }, @@ -4680,23 +4736,8 @@ dateToString:function(date, successCB, failureCB, options) { * {selector:'date'}); */ stringToDate:function(dateString, successCB, failureCB, options) { - // successCallback required - if (typeof successCB != "function") { - console.log("Globalization.stringToDate Error: successCB is not a function"); - return; - } - - // errorCallback required - if (typeof failureCB != "function") { - console.log("Globalization.stringToDate Error: failureCB is not a function"); - return; - } - if (typeof dateString == "string"){ - exec(successCB, failureCB, "Globalization", "stringToDate", [{"dateString": dateString, "options": options}]); - } - else { - console.log("Globalization.stringToDate Error: dateString is not a string"); - } + argscheck.checkArgs('sfFO', 'Globalization.stringToDate', arguments); + exec(successCB, failureCB, "Globalization", "stringToDate", [{"dateString": dateString, "options": options}]); }, @@ -4733,18 +4774,7 @@ stringToDate:function(dateString, successCB, failureCB, options) { * {formatLength:'short'}); */ getDatePattern:function(successCB, failureCB, options) { - // successCallback required - if (typeof successCB != "function") { - console.log("Globalization.getDatePattern Error: successCB is not a function"); - return; - } - - // errorCallback required - if (typeof failureCB != "function") { - console.log("Globalization.getDatePattern Error: failureCB is not a function"); - return; - } - + argscheck.checkArgs('fFO', 'Globalization.getDatePattern', arguments); exec(successCB, failureCB, "Globalization", "getDatePattern", [{"options": options}]); }, @@ -4775,17 +4805,7 @@ getDatePattern:function(successCB, failureCB, options) { * function () {}); */ getDateNames:function(successCB, failureCB, options) { - // successCallback required - if (typeof successCB != "function") { - console.log("Globalization.getDateNames Error: successCB is not a function"); - return; - } - - // errorCallback required - if (typeof failureCB != "function") { - console.log("Globalization.getDateNames Error: failureCB is not a function"); - return; - } + argscheck.checkArgs('fFO', 'Globalization.getDateNames', arguments); exec(successCB, failureCB, "Globalization", "getDateNames", [{"options": options}]); }, @@ -4810,28 +4830,9 @@ getDateNames:function(successCB, failureCB, options) { * function () {}); */ isDayLightSavingsTime:function(date, successCB, failureCB) { - // successCallback required - if (typeof successCB != "function") { - console.log("Globalization.isDayLightSavingsTime Error: successCB is not a function"); - return; - } - - // errorCallback required - if (typeof failureCB != "function") { - console.log("Globalization.isDayLightSavingsTime Error: failureCB is not a function"); - return; - } - - - if (date instanceof Date){ - var dateValue; - dateValue = date.valueOf(); - exec(successCB, failureCB, "Globalization", "isDayLightSavingsTime", [{"date": dateValue}]); - } - else { - console.log("Globalization.isDayLightSavingsTime Error: date is not a Date object"); - } - + argscheck.checkArgs('dfF', 'Globalization.isDayLightSavingsTime', arguments); + var dateValue = date.valueOf(); + exec(successCB, failureCB, "Globalization", "isDayLightSavingsTime", [{"date": dateValue}]); }, /** @@ -4853,18 +4854,7 @@ isDayLightSavingsTime:function(date, successCB, failureCB) { * function () {}); */ getFirstDayOfWeek:function(successCB, failureCB) { - // successCallback required - if (typeof successCB != "function") { - console.log("Globalization.getFirstDayOfWeek Error: successCB is not a function"); - return; - } - - // errorCallback required - if (typeof failureCB != "function") { - console.log("Globalization.getFirstDayOfWeek Error: failureCB is not a function"); - return; - } - + argscheck.checkArgs('fF', 'Globalization.getFirstDayOfWeek', arguments); exec(successCB, failureCB, "Globalization", "getFirstDayOfWeek", []); }, @@ -4893,24 +4883,8 @@ getFirstDayOfWeek:function(successCB, failureCB) { * {type:'decimal'}); */ numberToString:function(number, successCB, failureCB, options) { - // successCallback required - if (typeof successCB != "function") { - console.log("Globalization.numberToString Error: successCB is not a function"); - return; - } - - // errorCallback required - if (typeof failureCB != "function") { - console.log("Globalization.numberToString Error: failureCB is not a function"); - return; - } - - if(typeof number == "number") { - exec(successCB, failureCB, "Globalization", "numberToString", [{"number": number, "options": options}]); - } - else { - console.log("Globalization.numberToString Error: number is not a number"); - } + argscheck.checkArgs('nfFO', 'Globalization.numberToString', arguments); + exec(successCB, failureCB, "Globalization", "numberToString", [{"number": number, "options": options}]); }, /** @@ -4937,24 +4911,8 @@ numberToString:function(number, successCB, failureCB, options) { * function () { alert('Error parsing number');}); */ stringToNumber:function(numberString, successCB, failureCB, options) { - // successCallback required - if (typeof successCB != "function") { - console.log("Globalization.stringToNumber Error: successCB is not a function"); - return; - } - - // errorCallback required - if (typeof failureCB != "function") { - console.log("Globalization.stringToNumber Error: failureCB is not a function"); - return; - } - - if(typeof numberString == "string") { - exec(successCB, failureCB, "Globalization", "stringToNumber", [{"numberString": numberString, "options": options}]); - } - else { - console.log("Globalization.stringToNumber Error: numberString is not a string"); - } + argscheck.checkArgs('sfFO', 'Globalization.stringToNumber', arguments); + exec(successCB, failureCB, "Globalization", "stringToNumber", [{"numberString": numberString, "options": options}]); }, /** @@ -4990,18 +4948,7 @@ stringToNumber:function(numberString, successCB, failureCB, options) { * function () {}); */ getNumberPattern:function(successCB, failureCB, options) { - // successCallback required - if (typeof successCB != "function") { - console.log("Globalization.getNumberPattern Error: successCB is not a function"); - return; - } - - // errorCallback required - if (typeof failureCB != "function") { - console.log("Globalization.getNumberPattern Error: failureCB is not a function"); - return; - } - + argscheck.checkArgs('fFO', 'Globalization.getNumberPattern', arguments); exec(successCB, failureCB, "Globalization", "getNumberPattern", [{"options": options}]); }, @@ -5033,24 +4980,8 @@ getNumberPattern:function(successCB, failureCB, options) { * function () {}); */ getCurrencyPattern:function(currencyCode, successCB, failureCB) { - // successCallback required - if (typeof successCB != "function") { - console.log("Globalization.getCurrencyPattern Error: successCB is not a function"); - return; - } - - // errorCallback required - if (typeof failureCB != "function") { - console.log("Globalization.getCurrencyPattern Error: failureCB is not a function"); - return; - } - - if(typeof currencyCode == "string") { - exec(successCB, failureCB, "Globalization", "getCurrencyPattern", [{"currencyCode": currencyCode}]); - } - else { - console.log("Globalization.getCurrencyPattern Error: currencyCode is not a currency code"); - } + argscheck.checkArgs('sfF', 'Globalization.getCurrencyPattern', arguments); + exec(successCB, failureCB, "Globalization", "getCurrencyPattern", [{"currencyCode": currencyCode}]); } }; @@ -5578,49 +5509,9 @@ if (typeof navigator != 'undefined') { }); } -var NetworkConnection = function () { - this.type = null; - this._firstRun = true; - this._timer = null; - this.timeout = 500; - - var me = this; - - channel.onCordovaReady.subscribe(function() { - me.getInfo(function (info) { - me.type = info; - if (info === "none") { - // set a timer if still offline at the end of timer send the offline event - me._timer = setTimeout(function(){ - cordova.fireDocumentEvent("offline"); - me._timer = null; - }, me.timeout); - } else { - // If there is a current offline event pending clear it - if (me._timer !== null) { - clearTimeout(me._timer); - me._timer = null; - } - cordova.fireDocumentEvent("online"); - } - - // should only fire this once - if (me._firstRun) { - me._firstRun = false; - channel.onCordovaConnectionReady.fire(); - } - }, - function (e) { - // If we can't get the network info we should still tell Cordova - // to fire the deviceready event. - if (me._firstRun) { - me._firstRun = false; - channel.onCordovaConnectionReady.fire(); - } - console.log("Error initializing Network Connection: " + e); - }); - }); -}; +function NetworkConnection() { + this.type = 'unknown'; +} /** * Get connection info @@ -5628,12 +5519,48 @@ var NetworkConnection = function () { * @param {Function} successCallback The function to call when the Connection data is available * @param {Function} errorCallback The function to call when there is an error getting the Connection data. (OPTIONAL) */ -NetworkConnection.prototype.getInfo = function (successCallback, errorCallback) { - // Get info +NetworkConnection.prototype.getInfo = function(successCallback, errorCallback) { exec(successCallback, errorCallback, "NetworkStatus", "getConnectionInfo", []); }; -module.exports = new NetworkConnection(); +var me = new NetworkConnection(); +var timerId = null; +var timeout = 500; + +channel.onCordovaReady.subscribe(function() { + me.getInfo(function(info) { + me.type = info; + if (info === "none") { + // set a timer if still offline at the end of timer send the offline event + timerId = setTimeout(function(){ + cordova.fireDocumentEvent("offline"); + timerId = null; + }, timeout); + } else { + // If there is a current offline event pending clear it + if (timerId !== null) { + clearTimeout(timerId); + timerId = null; + } + cordova.fireDocumentEvent("online"); + } + + // should only fire this once + if (channel.onCordovaConnectionReady.state !== 2) { + channel.onCordovaConnectionReady.fire(); + } + }, + function (e) { + // If we can't get the network info we should still tell Cordova + // to fire the deviceready event. + if (channel.onCordovaConnectionReady.state !== 2) { + channel.onCordovaConnectionReady.fire(); + } + console.log("Error initializing Network Connection: " + e); + }); +}); + +module.exports = me; }); @@ -5702,7 +5629,8 @@ module.exports = { // file: lib/common/plugin/requestFileSystem.js define("cordova/plugin/requestFileSystem", function(require, exports, module) { -var FileError = require('cordova/plugin/FileError'), +var argscheck = require('cordova/argscheck'), + FileError = require('cordova/plugin/FileError'), FileSystem = require('cordova/plugin/FileSystem'), exec = require('cordova/exec'); @@ -5714,10 +5642,9 @@ var FileError = require('cordova/plugin/FileError'), * @param errorCallback invoked if error occurs retrieving file system */ var requestFileSystem = function(type, size, successCallback, errorCallback) { + argscheck.checkArgs('nnFF', 'requestFileSystem', arguments); var fail = function(code) { - if (typeof errorCallback === 'function') { - errorCallback(new FileError(code)); - } + errorCallback && errorCallback(new FileError(code)); }; if (type < 0 || type > 3) { @@ -5726,7 +5653,7 @@ var requestFileSystem = function(type, size, successCallback, errorCallback) { // if successful, return a FileSystem object var success = function(file_system) { if (file_system) { - if (typeof successCallback === 'function') { + if (successCallback) { // grab the name and root from the file system object var result = new FileSystem(file_system.name, file_system.root); successCallback(result); @@ -5748,7 +5675,8 @@ module.exports = requestFileSystem; // file: lib/common/plugin/resolveLocalFileSystemURI.js define("cordova/plugin/resolveLocalFileSystemURI", function(require, exports, module) { -var DirectoryEntry = require('cordova/plugin/DirectoryEntry'), +var argscheck = require('cordova/argscheck'), + DirectoryEntry = require('cordova/plugin/DirectoryEntry'), FileEntry = require('cordova/plugin/FileEntry'), FileError = require('cordova/plugin/FileError'), exec = require('cordova/exec'); @@ -5760,11 +5688,10 @@ var DirectoryEntry = require('cordova/plugin/DirectoryEntry'), * @param errorCallback invoked if error occurs retrieving file system entry */ module.exports = function(uri, successCallback, errorCallback) { + argscheck.checkArgs('sFF', 'resolveLocalFileSystemURI', arguments); // error callback var fail = function(error) { - if (typeof errorCallback === 'function') { - errorCallback(new FileError(error)); - } + errorCallback && errorCallback(new FileError(error)); }; // sanity check for 'not:valid:filename' if(!uri || uri.split(":").length > 2) { @@ -5777,15 +5704,10 @@ module.exports = function(uri, successCallback, errorCallback) { var success = function(entry) { var result; if (entry) { - if (typeof successCallback === 'function') { + if (successCallback) { // create appropriate Entry object result = (entry.isDirectory) ? new DirectoryEntry(entry.name, entry.fullPath) : new FileEntry(entry.name, entry.fullPath); - try { - successCallback(result); - } - catch (e) { - console.log('Error invoking callback: ' + e); - } + successCallback(result); } } else { @@ -5833,6 +5755,30 @@ utils.defineGetter = function(obj, key, func) { } }; +utils.arrayIndexOf = function(a, item) { + if (a.indexOf) { + return a.indexOf(item); + } + var len = a.length; + for (var i = 0; i < len; ++i) { + if (a[i] == item) { + return i; + } + } + return -1; +}; + +/** + * Returns whether the item was found in the array. + */ +utils.arrayRemove = function(a, item) { + var index = utils.arrayIndexOf(a, item); + if (index != -1) { + a.splice(index, 1); + } + return index != -1; +}; + /** * Returns an indication of whether the argument is an array or not */ @@ -6028,10 +5974,10 @@ window.cordova = require('cordova'); (function (context) { // Replace navigator before any modules are required(), to ensure it happens as soon as possible. // We replace it so that properties that can't be clobbered can instead be overridden. - if (typeof navigator != 'undefined') { - var CordovaNavigator = function () {}; - CordovaNavigator.prototype = navigator; - navigator = new CordovaNavigator(); + if (context.navigator) { + function CordovaNavigator() {} + CordovaNavigator.prototype = context.navigator; + context.navigator = new CordovaNavigator(); } var channel = require("cordova/channel"), @@ -6046,17 +5992,13 @@ window.cordova = require('cordova'); platform = require('cordova/platform'); // Drop the common globals into the window object, but be nice and don't overwrite anything. - builder.build(base.objects).intoButDoNotClobber(window); + builder.buildIntoButDoNotClobber(base.defaults, context); + builder.buildIntoAndClobber(base.clobbers, context); + builder.buildIntoAndMerge(base.merges, context); - // Drop the platform-specific globals into the window object - // and clobber any existing object. - builder.build(platform.objects).intoAndClobber(window); - - // Merge the platform-specific overrides/enhancements into - // the window object. - if (typeof platform.merges !== 'undefined') { - builder.build(platform.merges).intoAndMerge(window); - } + builder.buildIntoButDoNotClobber(platform.defaults, context); + builder.buildIntoAndClobber(platform.clobbers, context); + builder.buildIntoAndMerge(platform.merges, context); // Call the platform-specific initialization platform.initialize(); @@ -6087,4 +6029,4 @@ window.cordova = require('cordova'); }(window)); -})();var PhoneGap = cordova; +})(); \ No newline at end of file From 508e7633282427581a7b6d09487c1e3d09755d25 Mon Sep 17 00:00:00 2001 From: George Garside Date: Fri, 19 Apr 2013 16:46:02 +0100 Subject: [PATCH 07/32] Update Cordova scripts --- cordova/emulate | 28 +++++++++--------- cordova/log | 2 +- cordova/{debug => release} | 18 ++++++++---- cordova/run | 58 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 20 deletions(-) rename cordova/{debug => release} (66%) create mode 100755 cordova/run diff --git a/cordova/emulate b/cordova/emulate index 10551fb..7f7072a 100755 --- a/cordova/emulate +++ b/cordova/emulate @@ -20,31 +20,33 @@ set -e -CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd ) -PROJECT_PATH=$CORDOVA_PATH/.. +XCODE_VER=$(xcodebuild -version | head -n 1 | sed -e 's/Xcode //') +XCODE_MIN_VERSION="4.5" -function getAppPath() { - for file in "$( find "$PROJECT_PATH" -type d -name '*.xcodeproj' | sort )"; do - PROJECT_NAME=$(basename "$file" .xcodeproj) - done; - APP=build/$PROJECT_NAME.app - APP_PATH="$PROJECT_PATH/$APP" -} +if [[ "$XCODE_VER" < "$XCODE_MIN_VERSION" ]]; then + echo "Cordova can only run in Xcode version $XCODE_MIN_VERSION or greater." + exit 1 +fi + +CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd -P) +PROJECT_PATH="$(dirname "$CORDOVA_PATH")" +XCODEPROJ=$( ls "$PROJECT_PATH" | grep .xcodeproj ) +PROJECT_NAME=$(basename "$XCODEPROJ" .xcodeproj) APP_PATH=$1 if [ $# -lt 1 ]; then - getAppPath + APP_PATH="$PROJECT_PATH/build/$PROJECT_NAME.app" fi if [ ! -d "$APP_PATH" ]; then echo "Project '$APP_PATH' is not built. Building." - $CORDOVA_PATH/debug || exit $? + $CORDOVA_PATH/debug || exit $? fi if [ ! -d "$APP_PATH" ]; then - echo "$APP_PATH not found to emulate." - exit 1 + echo "$APP_PATH not found to emulate." + exit 1 fi # launch using ios-sim diff --git a/cordova/log b/cordova/log index 787a4c8..b235b09 100755 --- a/cordova/log +++ b/cordova/log @@ -18,6 +18,6 @@ # under the License. # -CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd ) +CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd -P) tail -f "$CORDOVA_PATH/console.log" diff --git a/cordova/debug b/cordova/release similarity index 66% rename from cordova/debug rename to cordova/release index a326217..7263934 100755 --- a/cordova/debug +++ b/cordova/release @@ -25,19 +25,25 @@ set -e -CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd ) -PROJECT_PATH=$CORDOVA_PATH/.. +XCODE_VER=$(xcodebuild -version | head -n 1 | sed -e 's/Xcode //') +XCODE_MIN_VERSION="4.5" -for file in $PROJECT_PATH/*.xcodeproj; do - PROJECT_NAME=$(basename "$file" .xcodeproj) -done; +if [[ "$XCODE_VER" < "$XCODE_MIN_VERSION" ]]; then + echo "Cordova can only run in Xcode version $XCODE_MIN_VERSION or greater." + exit 1 +fi + +CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd -P) +PROJECT_PATH="$(dirname "$CORDOVA_PATH")" +XCODEPROJ=$( ls "$PROJECT_PATH" | grep .xcodeproj ) +PROJECT_NAME=$(basename "$XCODEPROJ" .xcodeproj) cd "$PROJECT_PATH" APP=build/$PROJECT_NAME.app SDK=`xcodebuild -showsdks | grep Sim | tail -1 | awk '{print $6}'` -xcodebuild -project $PROJECT_NAME.xcodeproj -arch i386 -target $PROJECT_NAME -configuration Debug -sdk $SDK clean build VALID_ARCHS="i386" CONFIGURATION_BUILD_DIR="$PROJECT_PATH/build" +xcodebuild -project $PROJECT_NAME.xcodeproj -arch i386 -target $PROJECT_NAME -configuration Release -sdk $SDK clean build VALID_ARCHS="i386" CONFIGURATION_BUILD_DIR="$PROJECT_PATH/build" diff --git a/cordova/run b/cordova/run new file mode 100755 index 0000000..7f7072a --- /dev/null +++ b/cordova/run @@ -0,0 +1,58 @@ +#! /bin/sh +# +# 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. +# + +set -e + +XCODE_VER=$(xcodebuild -version | head -n 1 | sed -e 's/Xcode //') +XCODE_MIN_VERSION="4.5" + +if [[ "$XCODE_VER" < "$XCODE_MIN_VERSION" ]]; then + echo "Cordova can only run in Xcode version $XCODE_MIN_VERSION or greater." + exit 1 +fi + +CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd -P) +PROJECT_PATH="$(dirname "$CORDOVA_PATH")" +XCODEPROJ=$( ls "$PROJECT_PATH" | grep .xcodeproj ) +PROJECT_NAME=$(basename "$XCODEPROJ" .xcodeproj) + +APP_PATH=$1 + +if [ $# -lt 1 ]; then + APP_PATH="$PROJECT_PATH/build/$PROJECT_NAME.app" +fi + +if [ ! -d "$APP_PATH" ]; then + echo "Project '$APP_PATH' is not built. Building." + $CORDOVA_PATH/debug || exit $? +fi + +if [ ! -d "$APP_PATH" ]; then + echo "$APP_PATH not found to emulate." + exit 1 +fi + +# launch using ios-sim +if which ios-sim >/dev/null; then + ios-sim launch "$APP_PATH" --stderr "$CORDOVA_PATH/console.log" --stdout "$CORDOVA_PATH/console.log" & +else + echo -e '\033[31mError: ios-sim was not found. Please download, build and install version 1.4 or greater from https://github.com/phonegap/ios-sim into your path. Or "brew install ios-sim" using homebrew: http://mxcl.github.com/homebrew/\033[m'; exit 1; +fi + From 781648c495c4a66e450692fa056bf86ad7874d60 Mon Sep 17 00:00:00 2001 From: George Garside Date: Fri, 19 Apr 2013 16:47:58 +0100 Subject: [PATCH 08/32] Update MainViewController --- TDA-Enrichment/Classes/MainViewController.m | 32 +++++++++++++-------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/TDA-Enrichment/Classes/MainViewController.m b/TDA-Enrichment/Classes/MainViewController.m index c210179..7d7d360 100644 --- a/TDA-Enrichment/Classes/MainViewController.m +++ b/TDA-Enrichment/Classes/MainViewController.m @@ -19,7 +19,7 @@ Licensed to the Apache Software Foundation (ASF) under one // // MainViewController.h -// TDA-Enrichment +// cordova-2.3.0 // // Created by George Garside on 11/01/2013. // Copyright George Garside 2012-2013. All rights reserved. @@ -33,7 +33,22 @@ - (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { - // Custom initialization + // Uncomment to override the CDVCommandDelegateImpl used + // _commandDelegate = [[MainCommandDelegate alloc] initWithViewController:self]; + // Uncomment to override the CDVCommandQueue used + // _commandQueue = [[MainCommandQueue alloc] initWithViewController:self]; + } + return self; +} + +- (id)init +{ + self = [super init]; + if (self) { + // Uncomment to override the CDVCommandDelegateImpl used + // _commandDelegate = [[MainCommandDelegate alloc] initWithViewController:self]; + // Uncomment to override the CDVCommandQueue used + // _commandQueue = [[MainCommandQueue alloc] initWithViewController:self]; } return self; } @@ -46,19 +61,12 @@ - (void)didReceiveMemoryWarning // Release any cached data, images, etc that aren't in use. } -#pragma mark - View lifecycle +#pragma mark View lifecycle - (void)viewWillAppear:(BOOL)animated { - // Set the main view to utilize the entire application frame space of the device. - // Change this to suit your view's UI footprint needs in your application. - - UIView* rootView = [[[[UIApplication sharedApplication] keyWindow] rootViewController] view]; - CGRect webViewFrame = [[[rootView subviews] objectAtIndex:0] frame]; // first subview is the UIWebView - - if (CGRectEqualToRect(webViewFrame, CGRectZero)) { // UIWebView is sized according to its parent, here it hasn't been sized yet - self.view.frame = [[UIScreen mainScreen] applicationFrame]; // size UIWebView's parent according to application frame, which will in turn resize the UIWebView - } + // View defaults to full size. If you want to customize the view's size, or its subviews (e.g. webView), + // you can do so here. [super viewWillAppear:animated]; } From 7eb5fecf9a4fec2a384bdf5ccc56c9080368a3fd Mon Sep 17 00:00:00 2001 From: George Garside Date: Fri, 19 Apr 2013 16:48:17 +0100 Subject: [PATCH 09/32] Reference new Cordova JavaScript --- www/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/index.html b/www/index.html index f4d94b5..c213f0f 100644 --- a/www/index.html +++ b/www/index.html @@ -9,7 +9,7 @@ - +
-

TDA Enrichment

Info +

TDA Enrichment

Info
@@ -61,19 +61,19 @@

Welcome

  • Big Friday
  • Dodgeball
  • After School
  • -
  • Monday 10 activities
  • -
  • Tuesday 10 activities
  • -
  • Wednesday 14 activities
  • -
  • Thursday 6 activities
  • -
  • Friday 8 activities
  • +
  • Monday 10 activities
  • +
  • Tuesday 10 activities
  • +
  • Wednesday 14 activities
  • +
  • Thursday 6 activities
  • +
  • Friday 8 activities
  • Health & Fitness
  • -
  • HOFF's 5 Wheels
  • -
  • Warm-ups and Cool-downs
  • -
  • Resistance Training
  • -
  • Aerobic Training
  • -
  • Nutrition
  • -
  • Core Conditioning
  • -
  • How do I? NEW!
  • +
  • HOFF's 5 Wheels
  • +
  • Warm-ups and Cool-downs
  • +
  • Resistance Training
  • +
  • Aerobic Training
  • +
  • Nutrition
  • +
  • Core Conditioning
  • +
  • How do I? NEW!
  • From 8b23308c6a9673ddc1196b6cc375c139b8611be3 Mon Sep 17 00:00:00 2001 From: George Garside Date: Fri, 19 Apr 2013 19:14:08 +0100 Subject: [PATCH 25/32] Remove all `role="heading"` --- www/index.html | 72 +++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/www/index.html b/www/index.html index 7849832..05e3360 100644 --- a/www/index.html +++ b/www/index.html @@ -102,7 +102,7 @@

    © George Garside