diff --git a/.cordova/config.json b/.cordova/config.json new file mode 100644 index 0000000..d7ce45f --- /dev/null +++ b/.cordova/config.json @@ -0,0 +1 @@ +{"id":"com.georgegarside.tda-enrichment","name":"TDA-Enrichment"} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 086fa36..c9e4de1 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ build .DS_Store xcuserdata/ *.diff +Other Resources diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..5b10ebb --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +TDA-Enrichment \ No newline at end of file diff --git a/.idea/TDA-Enrichment.iml b/.idea/TDA-Enrichment.iml new file mode 100644 index 0000000..967832e --- /dev/null +++ b/.idea/TDA-Enrichment.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..d821048 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..c66df00 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..3b31283 --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 0000000..b6029b6 --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jsLinters/jslint.xml b/.idea/jsLinters/jslint.xml new file mode 100644 index 0000000..2ea776a --- /dev/null +++ b/.idea/jsLinters/jslint.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..8662aa9 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..a66d183 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..6564d52 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..99e63db --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,743 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + GeneralJavaScript + + + JavaScript + + + Potentially confusing code constructsJavaScript + + + Probable bugsJavaScript + + + Spelling + + + XPath + + + + + SpellCheckingInspection + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + 1419803886434 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CordovaLib/Classes/CDVAccelerometer.h b/CordovaLib/Classes/CDVAccelerometer.h deleted file mode 100755 index 044ca53..0000000 --- a/CordovaLib/Classes/CDVAccelerometer.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - 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 -#import "CDVPlugin.h" - -@interface CDVAccelerometer : CDVPlugin -{ - double x; - double y; - double z; - NSTimeInterval timestamp; -} - -@property (readonly, assign) BOOL isRunning; -@property (nonatomic, strong) NSString* callbackId; - -- (CDVAccelerometer*)init; - -- (void)start:(CDVInvokedUrlCommand*)command; -- (void)stop:(CDVInvokedUrlCommand*)command; - -@end diff --git a/CordovaLib/Classes/CDVAccelerometer.m b/CordovaLib/Classes/CDVAccelerometer.m deleted file mode 100755 index 33093d0..0000000 --- a/CordovaLib/Classes/CDVAccelerometer.m +++ /dev/null @@ -1,128 +0,0 @@ -/* - 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 "CDVAccelerometer.h" - -@interface CDVAccelerometer () {} -@property (readwrite, assign) BOOL isRunning; -@end - -@implementation CDVAccelerometer - -@synthesize callbackId, isRunning; - -// defaults to 10 msec -#define kAccelerometerInterval 40 -// g constant: -9.81 m/s^2 -#define kGravitationalConstant -9.81 - -- (CDVAccelerometer*)init -{ - self = [super init]; - if (self) { - x = 0; - y = 0; - z = 0; - timestamp = 0; - self.callbackId = nil; - self.isRunning = NO; - } - return self; -} - -- (void)dealloc -{ - [self stop:nil]; -} - -- (void)start:(CDVInvokedUrlCommand*)command -{ - NSString* cbId = command.callbackId; - NSTimeInterval desiredFrequency_num = kAccelerometerInterval; - UIAccelerometer* pAccel = [UIAccelerometer sharedAccelerometer]; - - // accelerometer expects fractional seconds, but we have msecs - pAccel.updateInterval = desiredFrequency_num / 1000; - self.callbackId = cbId; - if (!self.isRunning) { - pAccel.delegate = self; - self.isRunning = YES; - } -} - -- (void)onReset -{ - [self stop:nil]; -} - -- (void)stop:(CDVInvokedUrlCommand*)command -{ - UIAccelerometer* theAccelerometer = [UIAccelerometer sharedAccelerometer]; - - theAccelerometer.delegate = nil; - self.isRunning = NO; -} - -/** - * Picks up accel updates from device and stores them in this class - */ -- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration -{ - if (self.isRunning) { - x = acceleration.x; - y = acceleration.y; - z = acceleration.z; - timestamp = ([[NSDate date] timeIntervalSince1970] * 1000); - [self returnAccelInfo]; - } -} - -- (void)returnAccelInfo -{ - // Create an acceleration object - NSMutableDictionary* accelProps = [NSMutableDictionary dictionaryWithCapacity:4]; - - [accelProps setValue:[NSNumber numberWithDouble:x * kGravitationalConstant] forKey:@"x"]; - [accelProps setValue:[NSNumber numberWithDouble:y * kGravitationalConstant] forKey:@"y"]; - [accelProps setValue:[NSNumber numberWithDouble:z * kGravitationalConstant] forKey:@"z"]; - [accelProps setValue:[NSNumber numberWithDouble:timestamp] forKey:@"timestamp"]; - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:accelProps]; - [result setKeepCallback:[NSNumber numberWithBool:YES]]; - [self.commandDelegate sendPluginResult:result callbackId:self.callbackId]; -} - -// TODO: Consider using filtering to isolate instantaneous data vs. gravity data -jm - -/* - #define kFilteringFactor 0.1 - - // Use a basic low-pass filter to keep only the gravity component of each axis. - grav_accelX = (acceleration.x * kFilteringFactor) + ( grav_accelX * (1.0 - kFilteringFactor)); - grav_accelY = (acceleration.y * kFilteringFactor) + ( grav_accelY * (1.0 - kFilteringFactor)); - grav_accelZ = (acceleration.z * kFilteringFactor) + ( grav_accelZ * (1.0 - kFilteringFactor)); - - // Subtract the low-pass value from the current value to get a simplified high-pass filter - instant_accelX = acceleration.x - ( (acceleration.x * kFilteringFactor) + (instant_accelX * (1.0 - kFilteringFactor)) ); - instant_accelY = acceleration.y - ( (acceleration.y * kFilteringFactor) + (instant_accelY * (1.0 - kFilteringFactor)) ); - instant_accelZ = acceleration.z - ( (acceleration.z * kFilteringFactor) + (instant_accelZ * (1.0 - kFilteringFactor)) ); - - - */ -@end diff --git a/CordovaLib/Classes/CDVBattery.h b/CordovaLib/Classes/CDVBattery.h deleted file mode 100755 index ba26c3a..0000000 --- a/CordovaLib/Classes/CDVBattery.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - 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 -#import "CDVPlugin.h" - -@interface CDVBattery : CDVPlugin { - UIDeviceBatteryState state; - float level; - bool isPlugged; - NSString* callbackId; -} - -@property (nonatomic) UIDeviceBatteryState state; -@property (nonatomic) float level; -@property (nonatomic) bool isPlugged; -@property (strong) NSString* callbackId; - -- (void)updateBatteryStatus:(NSNotification*)notification; -- (NSDictionary*)getBatteryStatus; -- (void)start:(CDVInvokedUrlCommand*)command; -- (void)stop:(CDVInvokedUrlCommand*)command; -- (void)dealloc; -@end diff --git a/CordovaLib/Classes/CDVBattery.m b/CordovaLib/Classes/CDVBattery.m deleted file mode 100755 index 681511c..0000000 --- a/CordovaLib/Classes/CDVBattery.m +++ /dev/null @@ -1,152 +0,0 @@ -/* - 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 "CDVBattery.h" - -@interface CDVBattery (PrivateMethods) -- (void)updateOnlineStatus; -@end - -@implementation CDVBattery - -@synthesize state, level, callbackId, isPlugged; - -/* determining type of event occurs on JavaScript side -- (void) updateBatteryLevel:(NSNotification*)notification -{ - // send batterylow event for less than 25% battery - // send batterycritical event for less than 10% battery - // W3c says to send batteryStatus event when batterylevel changes by more than 1% (iOS seems to notify each 5%) - // always update the navigator.device.battery info - float currentLevel = [[UIDevice currentDevice] batteryLevel]; - NSString* type = @""; - // no check for level == -1 since this api is only called when monitoring is enabled so level should be valid - if (currentLevel < 0.10){ - type = @"batterycritical"; - } else if (currentLevel < 0.25) { - type = @"batterylow"; - } else { - float onePercent = 0.1; - if (self.level >= 0 ){ - onePercent = self.level * 0.01; - } - if (fabsf(currentLevel - self.level) > onePercent){ - // issue batteryStatus event - type = @"batterystatus"; - } - } - // update the battery info and fire event - NSString* jsString = [NSString stringWithFormat:@"navigator.device.battery._status(\"%@\", %@)", type,[[self getBatteryStatus] JSONRepresentation]]; - [super writeJavascript:jsString]; -} - */ - -- (void)updateBatteryStatus:(NSNotification*)notification -{ - NSDictionary* batteryData = [self getBatteryStatus]; - - if (self.callbackId) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:batteryData]; - [result setKeepCallbackAsBool:YES]; - [self.commandDelegate sendPluginResult:result callbackId:self.callbackId]; - } -} - -/* Get the current battery status and level. Status will be unknown and level will be -1.0 if - * monitoring is turned off. - */ -- (NSDictionary*)getBatteryStatus -{ - UIDevice* currentDevice = [UIDevice currentDevice]; - UIDeviceBatteryState currentState = [currentDevice batteryState]; - - isPlugged = FALSE; // UIDeviceBatteryStateUnknown or UIDeviceBatteryStateUnplugged - if ((currentState == UIDeviceBatteryStateCharging) || (currentState == UIDeviceBatteryStateFull)) { - isPlugged = TRUE; - } - float currentLevel = [currentDevice batteryLevel]; - - if ((currentLevel != self.level) || (currentState != self.state)) { - self.level = currentLevel; - self.state = currentState; - } - - // W3C spec says level must be null if it is unknown - NSObject* w3cLevel = nil; - if ((currentState == UIDeviceBatteryStateUnknown) || (currentLevel == -1.0)) { - w3cLevel = [NSNull null]; - } else { - w3cLevel = [NSNumber numberWithFloat:(currentLevel * 100)]; - } - NSMutableDictionary* batteryData = [NSMutableDictionary dictionaryWithCapacity:2]; - [batteryData setObject:[NSNumber numberWithBool:isPlugged] forKey:@"isPlugged"]; - [batteryData setObject:w3cLevel forKey:@"level"]; - return batteryData; -} - -/* turn on battery monitoring*/ -- (void)start:(CDVInvokedUrlCommand*)command -{ - self.callbackId = command.callbackId; - - if ([UIDevice currentDevice].batteryMonitoringEnabled == NO) { - [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateBatteryStatus:) - name:UIDeviceBatteryStateDidChangeNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateBatteryStatus:) - name:UIDeviceBatteryLevelDidChangeNotification object:nil]; - } -} - -/* turn off battery monitoring */ -- (void)stop:(CDVInvokedUrlCommand*)command -{ - // callback one last time to clear the callback function on JS side - if (self.callbackId) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getBatteryStatus]]; - [result setKeepCallbackAsBool:NO]; - [self.commandDelegate sendPluginResult:result callbackId:self.callbackId]; - } - self.callbackId = nil; - [[UIDevice currentDevice] setBatteryMonitoringEnabled:NO]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceBatteryStateDidChangeNotification object:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceBatteryLevelDidChangeNotification object:nil]; -} - -- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView -{ - self = (CDVBattery*)[super initWithWebView:theWebView]; - if (self) { - self.state = UIDeviceBatteryStateUnknown; - self.level = -1.0; - } - return self; -} - -- (void)dealloc -{ - [self stop:nil]; -} - -- (void)onReset -{ - [self stop:nil]; -} - -@end diff --git a/CordovaLib/Classes/CDVCamera.h b/CordovaLib/Classes/CDVCamera.h deleted file mode 100755 index 65eac77..0000000 --- a/CordovaLib/Classes/CDVCamera.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - 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 -#import "CDVPlugin.h" - -enum CDVDestinationType { - DestinationTypeDataUrl = 0, - DestinationTypeFileUri, - DestinationTypeNativeUri -}; -typedef NSUInteger CDVDestinationType; - -enum CDVEncodingType { - EncodingTypeJPEG = 0, - EncodingTypePNG -}; -typedef NSUInteger CDVEncodingType; - -enum CDVMediaType { - MediaTypePicture = 0, - MediaTypeVideo, - MediaTypeAll -}; -typedef NSUInteger CDVMediaType; - -@interface CDVCameraPicker : UIImagePickerController -{} - -@property (assign) NSInteger quality; -@property (copy) NSString* callbackId; -@property (copy) NSString* postUrl; -@property (nonatomic) enum CDVDestinationType returnType; -@property (nonatomic) enum CDVEncodingType encodingType; -@property (strong) UIPopoverController* popoverController; -@property (assign) CGSize targetSize; -@property (assign) bool correctOrientation; -@property (assign) bool saveToPhotoAlbum; -@property (assign) bool cropToSize; -@property (strong) UIWebView* webView; -@property (assign) BOOL popoverSupported; - -@end - -// ======================================================================= // - -@interface CDVCamera : CDVPlugin -{} - -@property (strong) CDVCameraPicker* pickerController; - -/* - * getPicture - * - * arguments: - * 1: this is the javascript function that will be called with the results, the first parameter passed to the - * javascript function is the picture as a Base64 encoded string - * 2: this is the javascript function to be called if there was an error - * options: - * quality: integer between 1 and 100 - */ -- (void)takePicture:(CDVInvokedUrlCommand*)command; -- (void)postImage:(UIImage*)anImage withFilename:(NSString*)filename toUrl:(NSURL*)url; -- (void)cleanup:(CDVInvokedUrlCommand*)command; -- (void)repositionPopover:(CDVInvokedUrlCommand*)command; - -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info; -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo; -- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker; -- (UIImage*)imageByScalingAndCroppingForSize:(UIImage*)anImage toSize:(CGSize)targetSize; -- (UIImage*)imageByScalingNotCroppingForSize:(UIImage*)anImage toSize:(CGSize)frameSize; -- (UIImage*)imageCorrectedForCaptureOrientation:(UIImage*)anImage; - -@end diff --git a/CordovaLib/Classes/CDVCamera.m b/CordovaLib/Classes/CDVCamera.m deleted file mode 100755 index 823fde9..0000000 --- a/CordovaLib/Classes/CDVCamera.m +++ /dev/null @@ -1,570 +0,0 @@ -/* - 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 "CDVCamera.h" -#import "CDVJpegHeaderWriter.h" -#import "NSArray+Comparisons.h" -#import "NSData+Base64.h" -#import "NSDictionary+Extensions.h" -#import - -#define CDV_PHOTO_PREFIX @"cdv_photo_" - -static NSSet* org_apache_cordova_validArrowDirections; - -@interface CDVCamera () - -@property (readwrite, assign) BOOL hasPendingOperation; - -@end - -@implementation CDVCamera - -+ (void)initialize -{ - org_apache_cordova_validArrowDirections = [[NSSet alloc] initWithObjects:[NSNumber numberWithInt:UIPopoverArrowDirectionUp], [NSNumber numberWithInt:UIPopoverArrowDirectionDown], [NSNumber numberWithInt:UIPopoverArrowDirectionLeft], [NSNumber numberWithInt:UIPopoverArrowDirectionRight], [NSNumber numberWithInt:UIPopoverArrowDirectionAny], nil]; -} - -@synthesize hasPendingOperation, pickerController; - -- (BOOL)popoverSupported -{ - return (NSClassFromString(@"UIPopoverController") != nil) && - (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad); -} - -/* takePicture arguments: - * INDEX ARGUMENT - * 0 quality - * 1 destination type - * 2 source type - * 3 targetWidth - * 4 targetHeight - * 5 encodingType - * 6 mediaType - * 7 allowsEdit - * 8 correctOrientation - * 9 saveToPhotoAlbum - * 10 popoverOptions - * 11 cameraDirection - */ -- (void)takePicture:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSArray* arguments = command.arguments; - - self.hasPendingOperation = NO; - - NSString* sourceTypeString = [arguments objectAtIndex:2]; - UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera; // default - if (sourceTypeString != nil) { - sourceType = (UIImagePickerControllerSourceType)[sourceTypeString intValue]; - } - - bool hasCamera = [UIImagePickerController isSourceTypeAvailable:sourceType]; - if (!hasCamera) { - NSLog(@"Camera.getPicture: source type %d not available.", sourceType); - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no camera available"]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - return; - } - - bool allowEdit = [[arguments objectAtIndex:7] boolValue]; - NSNumber* targetWidth = [arguments objectAtIndex:3]; - NSNumber* targetHeight = [arguments objectAtIndex:4]; - NSNumber* mediaValue = [arguments objectAtIndex:6]; - CDVMediaType mediaType = (mediaValue) ? [mediaValue intValue] : MediaTypePicture; - - CGSize targetSize = CGSizeMake(0, 0); - if ((targetWidth != nil) && (targetHeight != nil)) { - targetSize = CGSizeMake([targetWidth floatValue], [targetHeight floatValue]); - } - - // If a popover is already open, close it; we only want one at a time. - if (([[self pickerController] popoverController] != nil) && [[[self pickerController] popoverController] isPopoverVisible]) { - [[[self pickerController] popoverController] dismissPopoverAnimated:YES]; - [[[self pickerController] popoverController] setDelegate:nil]; - [[self pickerController] setPopoverController:nil]; - } - - CDVCameraPicker* cameraPicker = [[CDVCameraPicker alloc] init]; - self.pickerController = cameraPicker; - - cameraPicker.delegate = self; - cameraPicker.sourceType = sourceType; - cameraPicker.allowsEditing = allowEdit; // THIS IS ALL IT TAKES FOR CROPPING - jm - cameraPicker.callbackId = callbackId; - cameraPicker.targetSize = targetSize; - cameraPicker.cropToSize = NO; - // we need to capture this state for memory warnings that dealloc this object - cameraPicker.webView = self.webView; - cameraPicker.popoverSupported = [self popoverSupported]; - - cameraPicker.correctOrientation = [[arguments objectAtIndex:8] boolValue]; - cameraPicker.saveToPhotoAlbum = [[arguments objectAtIndex:9] boolValue]; - - cameraPicker.encodingType = ([arguments objectAtIndex:5]) ? [[arguments objectAtIndex:5] intValue] : EncodingTypeJPEG; - - cameraPicker.quality = ([arguments objectAtIndex:0]) ? [[arguments objectAtIndex:0] intValue] : 50; - cameraPicker.returnType = ([arguments objectAtIndex:1]) ? [[arguments objectAtIndex:1] intValue] : DestinationTypeFileUri; - - if (sourceType == UIImagePickerControllerSourceTypeCamera) { - // We only allow taking pictures (no video) in this API. - cameraPicker.mediaTypes = [NSArray arrayWithObjects:(NSString*)kUTTypeImage, nil]; - - // We can only set the camera device if we're actually using the camera. - NSNumber* cameraDirection = [command argumentAtIndex:11 withDefault:[NSNumber numberWithInteger:UIImagePickerControllerCameraDeviceRear]]; - cameraPicker.cameraDevice = (UIImagePickerControllerCameraDevice)[cameraDirection intValue]; - } else if (mediaType == MediaTypeAll) { - cameraPicker.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:sourceType]; - } else { - NSArray* mediaArray = [NSArray arrayWithObjects:(NSString*)(mediaType == MediaTypeVideo ? kUTTypeMovie : kUTTypeImage), nil]; - cameraPicker.mediaTypes = mediaArray; - } - - if ([self popoverSupported] && (sourceType != UIImagePickerControllerSourceTypeCamera)) { - if (cameraPicker.popoverController == nil) { - cameraPicker.popoverController = [[NSClassFromString(@"UIPopoverController")alloc] initWithContentViewController:cameraPicker]; - } - NSDictionary* options = [command.arguments objectAtIndex:10 withDefault:nil]; - [self displayPopover:options]; - } else { - if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) { - [self.viewController presentViewController:cameraPicker animated:YES completion:nil]; - } else { - [self.viewController presentModalViewController:cameraPicker animated:YES]; - } - } - self.hasPendingOperation = YES; -} - -- (void)repositionPopover:(CDVInvokedUrlCommand*)command -{ - NSDictionary* options = [command.arguments objectAtIndex:0 withDefault:nil]; - - [self displayPopover:options]; -} - -- (void)displayPopover:(NSDictionary*)options -{ - int x = 0; - int y = 32; - int width = 320; - int height = 480; - UIPopoverArrowDirection arrowDirection = UIPopoverArrowDirectionAny; - - if (options) { - x = [options integerValueForKey:@"x" defaultValue:0]; - y = [options integerValueForKey:@"y" defaultValue:32]; - width = [options integerValueForKey:@"width" defaultValue:320]; - height = [options integerValueForKey:@"height" defaultValue:480]; - arrowDirection = [options integerValueForKey:@"arrowDir" defaultValue:UIPopoverArrowDirectionAny]; - if (![org_apache_cordova_validArrowDirections containsObject:[NSNumber numberWithInt:arrowDirection]]) { - arrowDirection = UIPopoverArrowDirectionAny; - } - } - - [[[self pickerController] popoverController] setDelegate:self]; - [[[self pickerController] popoverController] presentPopoverFromRect:CGRectMake(x, y, width, height) - inView:[self.webView superview] - permittedArrowDirections:arrowDirection - animated:YES]; -} - -- (void)cleanup:(CDVInvokedUrlCommand*)command -{ - // empty the tmp directory - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - NSError* err = nil; - BOOL hasErrors = NO; - - // clear contents of NSTemporaryDirectory - NSString* tempDirectoryPath = NSTemporaryDirectory(); - NSDirectoryEnumerator* directoryEnumerator = [fileMgr enumeratorAtPath:tempDirectoryPath]; - NSString* fileName = nil; - BOOL result; - - while ((fileName = [directoryEnumerator nextObject])) { - // only delete the files we created - if (![fileName hasPrefix:CDV_PHOTO_PREFIX]) { - continue; - } - NSString* filePath = [tempDirectoryPath stringByAppendingPathComponent:fileName]; - result = [fileMgr removeItemAtPath:filePath error:&err]; - if (!result && err) { - NSLog(@"Failed to delete: %@ (error: %@)", filePath, err); - hasErrors = YES; - } - } - - CDVPluginResult* pluginResult; - if (hasErrors) { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:@"One or more files failed to be deleted."]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -- (void)popoverControllerDidDismissPopover:(id)popoverController -{ - // [ self imagePickerControllerDidCancel:self.pickerController ]; ' - UIPopoverController* pc = (UIPopoverController*)popoverController; - - [pc dismissPopoverAnimated:YES]; - pc.delegate = nil; - if (self.pickerController && self.pickerController.callbackId && self.pickerController.popoverController) { - self.pickerController.popoverController = nil; - NSString* callbackId = self.pickerController.callbackId; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no image selected"]; // error callback expects string ATM - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - self.hasPendingOperation = NO; -} - -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info -{ - CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker; - - if (cameraPicker.popoverSupported && (cameraPicker.popoverController != nil)) { - [cameraPicker.popoverController dismissPopoverAnimated:YES]; - cameraPicker.popoverController.delegate = nil; - cameraPicker.popoverController = nil; - } else { - if ([cameraPicker respondsToSelector:@selector(presentingViewController)]) { - [[cameraPicker presentingViewController] dismissModalViewControllerAnimated:YES]; - } else { - [[cameraPicker parentViewController] dismissModalViewControllerAnimated:YES]; - } - } - - CDVPluginResult* result = nil; - - NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType]; - // IMAGE TYPE - if ([mediaType isEqualToString:(NSString*)kUTTypeImage]) { - if (cameraPicker.returnType == DestinationTypeNativeUri) { - NSString* nativeUri = [(NSURL*)[info objectForKey:UIImagePickerControllerReferenceURL] absoluteString]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:nativeUri]; - } else { - // get the image - UIImage* image = nil; - if (cameraPicker.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage]) { - image = [info objectForKey:UIImagePickerControllerEditedImage]; - } else { - image = [info objectForKey:UIImagePickerControllerOriginalImage]; - } - - if (cameraPicker.saveToPhotoAlbum) { - UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil); - } - - if (cameraPicker.correctOrientation) { - image = [self imageCorrectedForCaptureOrientation:image]; - } - - UIImage* scaledImage = nil; - - if ((cameraPicker.targetSize.width > 0) && (cameraPicker.targetSize.height > 0)) { - // if cropToSize, resize image and crop to target size, otherwise resize to fit target without cropping - if (cameraPicker.cropToSize) { - scaledImage = [self imageByScalingAndCroppingForSize:image toSize:cameraPicker.targetSize]; - } else { - scaledImage = [self imageByScalingNotCroppingForSize:image toSize:cameraPicker.targetSize]; - } - } - - NSData* data = nil; - - if (cameraPicker.encodingType == EncodingTypePNG) { - data = UIImagePNGRepresentation(scaledImage == nil ? image : scaledImage); - } else { - data = UIImageJPEGRepresentation(scaledImage == nil ? image : scaledImage, cameraPicker.quality / 100.0f); - - /* splice loc */ - CDVJpegHeaderWriter* exifWriter = [[CDVJpegHeaderWriter alloc] init]; - NSString* headerstring = [exifWriter createExifAPP1:[info objectForKey:@"UIImagePickerControllerMediaMetadata"]]; - data = [exifWriter spliceExifBlockIntoJpeg:data withExifBlock:headerstring]; - } - - if (cameraPicker.returnType == DestinationTypeFileUri) { - // write to temp directory and return URI - // get the temp directory path - NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath]; - NSError* err = nil; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; // recommended by apple (vs [NSFileManager defaultManager]) to be threadsafe - // generate unique file name - NSString* filePath; - - int i = 1; - do { - filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, i++, cameraPicker.encodingType == EncodingTypePNG ? @"png":@"jpg"]; - } while ([fileMgr fileExistsAtPath:filePath]); - - // save file - if (![data writeToFile:filePath options:NSAtomicWrite error:&err]) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[[NSURL fileURLWithPath:filePath] absoluteString]]; - } - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[data base64EncodedString]]; - } - } - } - // NOT IMAGE TYPE (MOVIE) - else { - NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] absoluteString]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:moviePath]; - } - - if (result) { - [self.commandDelegate sendPluginResult:result callbackId:cameraPicker.callbackId]; - } - - self.hasPendingOperation = NO; - self.pickerController = nil; -} - -// older api calls newer didFinishPickingMediaWithInfo -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo -{ - NSDictionary* imageInfo = [NSDictionary dictionaryWithObject:image forKey:UIImagePickerControllerOriginalImage]; - - [self imagePickerController:picker didFinishPickingMediaWithInfo:imageInfo]; -} - -- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker -{ - CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker; - - if ([cameraPicker respondsToSelector:@selector(presentingViewController)]) { - [[cameraPicker presentingViewController] dismissModalViewControllerAnimated:YES]; - } else { - [[cameraPicker parentViewController] dismissModalViewControllerAnimated:YES]; - } - // popoverControllerDidDismissPopover:(id)popoverController is called if popover is cancelled - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no image selected"]; // error callback expects string ATM - [self.commandDelegate sendPluginResult:result callbackId:cameraPicker.callbackId]; - - self.hasPendingOperation = NO; - self.pickerController = nil; -} - -- (UIImage*)imageByScalingAndCroppingForSize:(UIImage*)anImage toSize:(CGSize)targetSize -{ - UIImage* sourceImage = anImage; - UIImage* newImage = nil; - CGSize imageSize = sourceImage.size; - CGFloat width = imageSize.width; - CGFloat height = imageSize.height; - CGFloat targetWidth = targetSize.width; - CGFloat targetHeight = targetSize.height; - CGFloat scaleFactor = 0.0; - CGFloat scaledWidth = targetWidth; - CGFloat scaledHeight = targetHeight; - CGPoint thumbnailPoint = CGPointMake(0.0, 0.0); - - if (CGSizeEqualToSize(imageSize, targetSize) == NO) { - CGFloat widthFactor = targetWidth / width; - CGFloat heightFactor = targetHeight / height; - - if (widthFactor > heightFactor) { - scaleFactor = widthFactor; // scale to fit height - } else { - scaleFactor = heightFactor; // scale to fit width - } - scaledWidth = width * scaleFactor; - scaledHeight = height * scaleFactor; - - // center the image - if (widthFactor > heightFactor) { - thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; - } else if (widthFactor < heightFactor) { - thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5; - } - } - - UIGraphicsBeginImageContext(targetSize); // this will crop - - CGRect thumbnailRect = CGRectZero; - thumbnailRect.origin = thumbnailPoint; - thumbnailRect.size.width = scaledWidth; - thumbnailRect.size.height = scaledHeight; - - [sourceImage drawInRect:thumbnailRect]; - - newImage = UIGraphicsGetImageFromCurrentImageContext(); - if (newImage == nil) { - NSLog(@"could not scale image"); - } - - // pop the context to get back to the default - UIGraphicsEndImageContext(); - return newImage; -} - -- (UIImage*)imageCorrectedForCaptureOrientation:(UIImage*)anImage -{ - float rotation_radians = 0; - bool perpendicular = false; - - switch ([anImage imageOrientation]) { - case UIImageOrientationUp : - rotation_radians = 0.0; - break; - - case UIImageOrientationDown: - rotation_radians = M_PI; // don't be scared of radians, if you're reading this, you're good at math - break; - - case UIImageOrientationRight: - rotation_radians = M_PI_2; - perpendicular = true; - break; - - case UIImageOrientationLeft: - rotation_radians = -M_PI_2; - perpendicular = true; - break; - - default: - break; - } - - UIGraphicsBeginImageContext(CGSizeMake(anImage.size.width, anImage.size.height)); - CGContextRef context = UIGraphicsGetCurrentContext(); - - // Rotate around the center point - CGContextTranslateCTM(context, anImage.size.width / 2, anImage.size.height / 2); - CGContextRotateCTM(context, rotation_radians); - - CGContextScaleCTM(context, 1.0, -1.0); - float width = perpendicular ? anImage.size.height : anImage.size.width; - float height = perpendicular ? anImage.size.width : anImage.size.height; - CGContextDrawImage(context, CGRectMake(-width / 2, -height / 2, width, height), [anImage CGImage]); - - // Move the origin back since the rotation might've change it (if its 90 degrees) - if (perpendicular) { - CGContextTranslateCTM(context, -anImage.size.height / 2, -anImage.size.width / 2); - } - - UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - return newImage; -} - -- (UIImage*)imageByScalingNotCroppingForSize:(UIImage*)anImage toSize:(CGSize)frameSize -{ - UIImage* sourceImage = anImage; - UIImage* newImage = nil; - CGSize imageSize = sourceImage.size; - CGFloat width = imageSize.width; - CGFloat height = imageSize.height; - CGFloat targetWidth = frameSize.width; - CGFloat targetHeight = frameSize.height; - CGFloat scaleFactor = 0.0; - CGSize scaledSize = frameSize; - - if (CGSizeEqualToSize(imageSize, frameSize) == NO) { - CGFloat widthFactor = targetWidth / width; - CGFloat heightFactor = targetHeight / height; - - // opposite comparison to imageByScalingAndCroppingForSize in order to contain the image within the given bounds - if (widthFactor > heightFactor) { - scaleFactor = heightFactor; // scale to fit height - } else { - scaleFactor = widthFactor; // scale to fit width - } - scaledSize = CGSizeMake(MIN(width * scaleFactor, targetWidth), MIN(height * scaleFactor, targetHeight)); - } - - UIGraphicsBeginImageContext(scaledSize); // this will resize - - [sourceImage drawInRect:CGRectMake(0, 0, scaledSize.width, scaledSize.height)]; - - newImage = UIGraphicsGetImageFromCurrentImageContext(); - if (newImage == nil) { - NSLog(@"could not scale image"); - } - - // pop the context to get back to the default - UIGraphicsEndImageContext(); - return newImage; -} - -- (void)postImage:(UIImage*)anImage withFilename:(NSString*)filename toUrl:(NSURL*)url -{ - self.hasPendingOperation = YES; - - NSString* boundary = @"----BOUNDARY_IS_I"; - - NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url]; - [req setHTTPMethod:@"POST"]; - - NSString* contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; - [req setValue:contentType forHTTPHeaderField:@"Content-type"]; - - NSData* imageData = UIImagePNGRepresentation(anImage); - - // adding the body - NSMutableData* postBody = [NSMutableData data]; - - // first parameter an image - [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; - [postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"upload\"; filename=\"%@\"\r\n", filename] dataUsingEncoding:NSUTF8StringEncoding]]; - [postBody appendData:[@"Content-Type: image/png\r\n\r\n" dataUsingEncoding : NSUTF8StringEncoding]]; - [postBody appendData:imageData]; - - // // second parameter information - // [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; - // [postBody appendData:[@"Content-Disposition: form-data; name=\"some_other_name\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; - // [postBody appendData:[@"some_other_value" dataUsingEncoding:NSUTF8StringEncoding]]; - // [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r \n",boundary] dataUsingEncoding:NSUTF8StringEncoding]]; - - [req setHTTPBody:postBody]; - - NSURLResponse* response; - NSError* error; - [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&error]; - - // NSData* result = [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&error]; - // NSString * resultStr = [[[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding] autorelease]; - - self.hasPendingOperation = NO; -} - -@end - -@implementation CDVCameraPicker - -@synthesize quality, postUrl; -@synthesize returnType; -@synthesize callbackId; -@synthesize popoverController; -@synthesize targetSize; -@synthesize correctOrientation; -@synthesize saveToPhotoAlbum; -@synthesize encodingType; -@synthesize cropToSize; -@synthesize webView; -@synthesize popoverSupported; - -@end diff --git a/CordovaLib/Classes/CDVCapture.h b/CordovaLib/Classes/CDVCapture.h deleted file mode 100755 index afb82b4..0000000 --- a/CordovaLib/Classes/CDVCapture.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - 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 -#import -#import -#import "CDVPlugin.h" -#import "CDVFile.h" - -enum CDVCaptureError { - CAPTURE_INTERNAL_ERR = 0, - CAPTURE_APPLICATION_BUSY = 1, - CAPTURE_INVALID_ARGUMENT = 2, - CAPTURE_NO_MEDIA_FILES = 3, - CAPTURE_NOT_SUPPORTED = 20 -}; -typedef NSUInteger CDVCaptureError; - -@interface CDVImagePicker : UIImagePickerController -{ - NSString* callbackid; - NSInteger quality; - NSString* mimeType; -} -@property (assign) NSInteger quality; -@property (copy) NSString* callbackId; -@property (copy) NSString* mimeType; - -@end - -@interface CDVCapture : CDVPlugin -{ - CDVImagePicker* pickerController; - BOOL inUse; -} -@property BOOL inUse; -- (void)captureAudio:(CDVInvokedUrlCommand*)command; -- (void)captureImage:(CDVInvokedUrlCommand*)command; -- (CDVPluginResult*)processImage:(UIImage*)image type:(NSString*)mimeType forCallbackId:(NSString*)callbackId; -- (void)captureVideo:(CDVInvokedUrlCommand*)command; -- (CDVPluginResult*)processVideo:(NSString*)moviePath forCallbackId:(NSString*)callbackId; -- (void)getMediaModes:(CDVInvokedUrlCommand*)command; -- (void)getFormatData:(CDVInvokedUrlCommand*)command; -- (NSDictionary*)getMediaDictionaryFromPath:(NSString*)fullPath ofType:(NSString*)type; -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info; -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo; -- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker; - -@end - -@interface CDVAudioNavigationController : UINavigationController - -@end - -/* AudioRecorderViewController is used to create a simple view for audio recording. - * It is created from [Capture captureAudio]. It creates a very simple interface for - * recording by presenting just a record/stop button and a Done button to close the view. - * The recording time is displayed and recording for a specified duration is supported. When duration - * is specified there is no UI to the user - recording just stops when the specified - * duration is reached. The UI has been minimized to avoid localization. - */ -@interface CDVAudioRecorderViewController : UIViewController -{ - CDVCaptureError errorCode; - NSString* callbackId; - NSNumber* duration; - CDVCapture* captureCommand; - UIBarButtonItem* doneButton; - UIView* recordingView; - UIButton* recordButton; - UIImage* recordImage; - UIImage* stopRecordImage; - UILabel* timerLabel; - AVAudioRecorder* avRecorder; - AVAudioSession* avSession; - CDVPluginResult* pluginResult; - NSTimer* timer; - BOOL isTimed; -} -@property (nonatomic) CDVCaptureError errorCode; -@property (nonatomic, copy) NSString* callbackId; -@property (nonatomic, copy) NSNumber* duration; -@property (nonatomic, strong) CDVCapture* captureCommand; -@property (nonatomic, strong) UIBarButtonItem* doneButton; -@property (nonatomic, strong) UIView* recordingView; -@property (nonatomic, strong) UIButton* recordButton; -@property (nonatomic, strong) UIImage* recordImage; -@property (nonatomic, strong) UIImage* stopRecordImage; -@property (nonatomic, strong) UILabel* timerLabel; -@property (nonatomic, strong) AVAudioRecorder* avRecorder; -@property (nonatomic, strong) AVAudioSession* avSession; -@property (nonatomic, strong) CDVPluginResult* pluginResult; -@property (nonatomic, strong) NSTimer* timer; -@property (nonatomic) BOOL isTimed; - -- (id)initWithCommand:(CDVPlugin*)theCommand duration:(NSNumber*)theDuration callbackId:(NSString*)theCallbackId; -- (void)processButton:(id)sender; -- (void)stopRecordingCleanup; -- (void)dismissAudioView:(id)sender; -- (NSString*)formatTime:(int)interval; -- (void)updateTime; -@end diff --git a/CordovaLib/Classes/CDVCapture.m b/CordovaLib/Classes/CDVCapture.m deleted file mode 100755 index d89e3d3..0000000 --- a/CordovaLib/Classes/CDVCapture.m +++ /dev/null @@ -1,847 +0,0 @@ -/* - 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 "CDVCapture.h" -#import "CDVJSON.h" -#import "CDVAvailability.h" - -#define kW3CMediaFormatHeight @"height" -#define kW3CMediaFormatWidth @"width" -#define kW3CMediaFormatCodecs @"codecs" -#define kW3CMediaFormatBitrate @"bitrate" -#define kW3CMediaFormatDuration @"duration" -#define kW3CMediaModeType @"type" - -@implementation CDVImagePicker - -@synthesize quality; -@synthesize callbackId; -@synthesize mimeType; - -- (uint64_t)accessibilityTraits -{ - NSString* systemVersion = [[UIDevice currentDevice] systemVersion]; - - if (([systemVersion compare:@"4.0" options:NSNumericSearch] != NSOrderedAscending)) { // this means system version is not less than 4.0 - return UIAccessibilityTraitStartsMediaSession; - } - - return UIAccessibilityTraitNone; -} - -@end - -@implementation CDVCapture -@synthesize inUse; - -- (id)initWithWebView:(UIWebView*)theWebView -{ - self = (CDVCapture*)[super initWithWebView:theWebView]; - if (self) { - self.inUse = NO; - } - return self; -} - -- (void)captureAudio:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* options = [command.arguments objectAtIndex:0]; - - if ([options isKindOfClass:[NSNull class]]) { - options = [NSDictionary dictionary]; - } - - NSNumber* duration = [options objectForKey:@"duration"]; - // the default value of duration is 0 so use nil (no duration) if default value - if (duration) { - duration = [duration doubleValue] == 0 ? nil : duration; - } - CDVPluginResult* result = nil; - - if (NSClassFromString(@"AVAudioRecorder") == nil) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_NOT_SUPPORTED]; - } else if (self.inUse == YES) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_APPLICATION_BUSY]; - } else { - // all the work occurs here - CDVAudioRecorderViewController* audioViewController = [[CDVAudioRecorderViewController alloc] initWithCommand:self duration:duration callbackId:callbackId]; - - // Now create a nav controller and display the view... - CDVAudioNavigationController* navController = [[CDVAudioNavigationController alloc] initWithRootViewController:audioViewController]; - - self.inUse = YES; - - if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) { - [self.viewController presentViewController:navController animated:YES completion:nil]; - } else { - [self.viewController presentModalViewController:navController animated:YES]; - } - } - - if (result) { - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } -} - -- (void)captureImage:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* options = [command.arguments objectAtIndex:0]; - - if ([options isKindOfClass:[NSNull class]]) { - options = [NSDictionary dictionary]; - } - NSString* mode = [options objectForKey:@"mode"]; - - // options could contain limit and mode neither of which are supported at this time - // taking more than one picture (limit) is only supported if provide own controls via cameraOverlayView property - // can support mode in OS - - if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { - NSLog(@"Capture.imageCapture: camera not available."); - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_NOT_SUPPORTED]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } else { - if (pickerController == nil) { - pickerController = [[CDVImagePicker alloc] init]; - } - - pickerController.delegate = self; - pickerController.sourceType = UIImagePickerControllerSourceTypeCamera; - pickerController.allowsEditing = NO; - if ([pickerController respondsToSelector:@selector(mediaTypes)]) { - // iOS 3.0 - pickerController.mediaTypes = [NSArray arrayWithObjects:(NSString*)kUTTypeImage, nil]; - } - - /*if ([pickerController respondsToSelector:@selector(cameraCaptureMode)]){ - // iOS 4.0 - pickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto; - pickerController.cameraDevice = UIImagePickerControllerCameraDeviceRear; - pickerController.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto; - }*/ - // CDVImagePicker specific property - pickerController.callbackId = callbackId; - pickerController.mimeType = mode; - - if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) { - [self.viewController presentViewController:pickerController animated:YES completion:nil]; - } else { - [self.viewController presentModalViewController:pickerController animated:YES]; - } - } -} - -/* Process a still image from the camera. - * IN: - * UIImage* image - the UIImage data returned from the camera - * NSString* callbackId - */ -- (CDVPluginResult*)processImage:(UIImage*)image type:(NSString*)mimeType forCallbackId:(NSString*)callbackId -{ - CDVPluginResult* result = nil; - - // save the image to photo album - UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil); - - NSData* data = nil; - if (mimeType && [mimeType isEqualToString:@"image/png"]) { - data = UIImagePNGRepresentation(image); - } else { - data = UIImageJPEGRepresentation(image, 0.5); - } - - // write to temp directory and return URI - NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath]; // use file system temporary directory - NSError* err = nil; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - - // generate unique file name - NSString* filePath; - int i = 1; - do { - filePath = [NSString stringWithFormat:@"%@/photo_%03d.jpg", docsPath, i++]; - } while ([fileMgr fileExistsAtPath:filePath]); - - if (![data writeToFile:filePath options:NSAtomicWrite error:&err]) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageToErrorObject:CAPTURE_INTERNAL_ERR]; - if (err) { - NSLog(@"Error saving image: %@", [err localizedDescription]); - } - } else { - // create MediaFile object - - NSDictionary* fileDict = [self getMediaDictionaryFromPath:filePath ofType:mimeType]; - NSArray* fileArray = [NSArray arrayWithObject:fileDict]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:fileArray]; - } - - return result; -} - -- (void)captureVideo:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* options = [command.arguments objectAtIndex:0]; - - if ([options isKindOfClass:[NSNull class]]) { - options = [NSDictionary dictionary]; - } - - // options could contain limit, duration and mode, only duration is supported (but is not due to apple bug) - // taking more than one video (limit) is only supported if provide own controls via cameraOverlayView property - // NSNumber* duration = [options objectForKey:@"duration"]; - NSString* mediaType = nil; - - if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { - // there is a camera, it is available, make sure it can do movies - pickerController = [[CDVImagePicker alloc] init]; - - NSArray* types = nil; - if ([UIImagePickerController respondsToSelector:@selector(availableMediaTypesForSourceType:)]) { - types = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera]; - // NSLog(@"MediaTypes: %@", [types description]); - - if ([types containsObject:(NSString*)kUTTypeMovie]) { - mediaType = (NSString*)kUTTypeMovie; - } else if ([types containsObject:(NSString*)kUTTypeVideo]) { - mediaType = (NSString*)kUTTypeVideo; - } - } - } - if (!mediaType) { - // don't have video camera return error - NSLog(@"Capture.captureVideo: video mode not available."); - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_NOT_SUPPORTED]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - pickerController = nil; - } else { - pickerController.delegate = self; - pickerController.sourceType = UIImagePickerControllerSourceTypeCamera; - pickerController.allowsEditing = NO; - // iOS 3.0 - pickerController.mediaTypes = [NSArray arrayWithObjects:mediaType, nil]; - - /*if ([mediaType isEqualToString:(NSString*)kUTTypeMovie]){ - if (duration) { - pickerController.videoMaximumDuration = [duration doubleValue]; - } - //NSLog(@"pickerController.videoMaximumDuration = %f", pickerController.videoMaximumDuration); - }*/ - - // iOS 4.0 - if ([pickerController respondsToSelector:@selector(cameraCaptureMode)]) { - pickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo; - // pickerController.videoQuality = UIImagePickerControllerQualityTypeHigh; - // pickerController.cameraDevice = UIImagePickerControllerCameraDeviceRear; - // pickerController.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto; - } - // CDVImagePicker specific property - pickerController.callbackId = callbackId; - - if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) { - [self.viewController presentViewController:pickerController animated:YES completion:nil]; - } else { - [self.viewController presentModalViewController:pickerController animated:YES]; - } - } -} - -- (CDVPluginResult*)processVideo:(NSString*)moviePath forCallbackId:(NSString*)callbackId -{ - // save the movie to photo album (only avail as of iOS 3.1) - - /* don't need, it should automatically get saved - NSLog(@"can save %@: %d ?", moviePath, UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(moviePath)); - if (&UIVideoAtPathIsCompatibleWithSavedPhotosAlbum != NULL && UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(moviePath) == YES) { - NSLog(@"try to save movie"); - UISaveVideoAtPathToSavedPhotosAlbum(moviePath, nil, nil, nil); - NSLog(@"finished saving movie"); - }*/ - // create MediaFile object - NSDictionary* fileDict = [self getMediaDictionaryFromPath:moviePath ofType:nil]; - NSArray* fileArray = [NSArray arrayWithObject:fileDict]; - - return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:fileArray]; -} - -- (void)getMediaModes:(CDVInvokedUrlCommand*)command -{ - // NSString* callbackId = [arguments objectAtIndex:0]; - // NSMutableDictionary* imageModes = nil; - NSArray* imageArray = nil; - NSArray* movieArray = nil; - NSArray* audioArray = nil; - - if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { - // there is a camera, find the modes - // can get image/jpeg or image/png from camera - - /* can't find a way to get the default height and width and other info - * for images/movies taken with UIImagePickerController - */ - NSDictionary* jpg = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt:0], kW3CMediaFormatHeight, - [NSNumber numberWithInt:0], kW3CMediaFormatWidth, - @"image/jpeg", kW3CMediaModeType, - nil]; - NSDictionary* png = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt:0], kW3CMediaFormatHeight, - [NSNumber numberWithInt:0], kW3CMediaFormatWidth, - @"image/png", kW3CMediaModeType, - nil]; - imageArray = [NSArray arrayWithObjects:jpg, png, nil]; - - if ([UIImagePickerController respondsToSelector:@selector(availableMediaTypesForSourceType:)]) { - NSArray* types = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera]; - - if ([types containsObject:(NSString*)kUTTypeMovie]) { - NSDictionary* mov = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt:0], kW3CMediaFormatHeight, - [NSNumber numberWithInt:0], kW3CMediaFormatWidth, - @"video/quicktime", kW3CMediaModeType, - nil]; - movieArray = [NSArray arrayWithObject:mov]; - } - } - } - NSDictionary* modes = [NSDictionary dictionaryWithObjectsAndKeys: - imageArray ? (NSObject*) imageArray:[NSNull null], @"image", - movieArray ? (NSObject*) movieArray:[NSNull null], @"video", - audioArray ? (NSObject*) audioArray:[NSNull null], @"audio", - nil]; - NSString* jsString = [NSString stringWithFormat:@"navigator.device.capture.setSupportedModes(%@);", [modes JSONString]]; - [self.commandDelegate evalJs:jsString]; -} - -- (void)getFormatData:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - // existence of fullPath checked on JS side - NSString* fullPath = [command.arguments objectAtIndex:0]; - // mimeType could be null - NSString* mimeType = nil; - - if ([command.arguments count] > 1) { - mimeType = [command.arguments objectAtIndex:1]; - } - BOOL bError = NO; - CDVCaptureError errorCode = CAPTURE_INTERNAL_ERR; - CDVPluginResult* result = nil; - - if (!mimeType || [mimeType isKindOfClass:[NSNull class]]) { - // try to determine mime type if not provided - id command = [self.commandDelegate getCommandInstance:@"File"]; - bError = !([command isKindOfClass:[CDVFile class]]); - if (!bError) { - CDVFile* cdvFile = (CDVFile*)command; - mimeType = [cdvFile getMimeTypeFromPath:fullPath]; - if (!mimeType) { - // can't do much without mimeType, return error - bError = YES; - errorCode = CAPTURE_INVALID_ARGUMENT; - } - } - } - if (!bError) { - // create and initialize return dictionary - NSMutableDictionary* formatData = [NSMutableDictionary dictionaryWithCapacity:5]; - [formatData setObject:[NSNull null] forKey:kW3CMediaFormatCodecs]; - [formatData setObject:[NSNumber numberWithInt:0] forKey:kW3CMediaFormatBitrate]; - [formatData setObject:[NSNumber numberWithInt:0] forKey:kW3CMediaFormatHeight]; - [formatData setObject:[NSNumber numberWithInt:0] forKey:kW3CMediaFormatWidth]; - [formatData setObject:[NSNumber numberWithInt:0] forKey:kW3CMediaFormatDuration]; - - if ([mimeType rangeOfString:@"image/"].location != NSNotFound) { - UIImage* image = [UIImage imageWithContentsOfFile:fullPath]; - if (image) { - CGSize imgSize = [image size]; - [formatData setObject:[NSNumber numberWithInteger:imgSize.width] forKey:kW3CMediaFormatWidth]; - [formatData setObject:[NSNumber numberWithInteger:imgSize.height] forKey:kW3CMediaFormatHeight]; - } - } else if (([mimeType rangeOfString:@"video/"].location != NSNotFound) && (NSClassFromString(@"AVURLAsset") != nil)) { - NSURL* movieURL = [NSURL fileURLWithPath:fullPath]; - AVURLAsset* movieAsset = [[AVURLAsset alloc] initWithURL:movieURL options:nil]; - CMTime duration = [movieAsset duration]; - [formatData setObject:[NSNumber numberWithFloat:CMTimeGetSeconds(duration)] forKey:kW3CMediaFormatDuration]; - - 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]; - NSError* err = nil; - - AVAudioPlayer* avPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&err]; - if (!err) { - // get the data - [formatData setObject:[NSNumber numberWithDouble:[avPlayer duration]] forKey:kW3CMediaFormatDuration]; - if ([avPlayer respondsToSelector:@selector(settings)]) { - NSDictionary* info = [avPlayer settings]; - NSNumber* bitRate = [info objectForKey:AVEncoderBitRateKey]; - if (bitRate) { - [formatData setObject:bitRate forKey:kW3CMediaFormatBitrate]; - } - } - } // else leave data init'ed to 0 - } - } - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:formatData]; - // NSLog(@"getFormatData: %@", [formatData description]); - } - if (bError) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errorCode]; - } - if (result) { - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } -} - -- (NSDictionary*)getMediaDictionaryFromPath:(NSString*)fullPath ofType:(NSString*)type -{ - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - NSMutableDictionary* fileDict = [NSMutableDictionary dictionaryWithCapacity:5]; - - [fileDict setObject:[fullPath lastPathComponent] forKey:@"name"]; - [fileDict setObject:fullPath forKey:@"fullPath"]; - // determine type - if (!type) { - id command = [self.commandDelegate getCommandInstance:@"File"]; - if ([command isKindOfClass:[CDVFile class]]) { - CDVFile* cdvFile = (CDVFile*)command; - NSString* mimeType = [cdvFile getMimeTypeFromPath:fullPath]; - [fileDict setObject:(mimeType != nil ? (NSObject*)mimeType : [NSNull null]) forKey:@"type"]; - } - } - NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:fullPath error:nil]; - [fileDict setObject:[NSNumber numberWithUnsignedLongLong:[fileAttrs fileSize]] forKey:@"size"]; - NSDate* modDate = [fileAttrs fileModificationDate]; - NSNumber* msDate = [NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000]; - [fileDict setObject:msDate forKey:@"lastModifiedDate"]; - - return fileDict; -} - -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo -{ - // older api calls new one - [self imagePickerController:picker didFinishPickingMediaWithInfo:editingInfo]; -} - -/* Called when image/movie is finished recording. - * Calls success or error code as appropriate - * if successful, result contains an array (with just one entry since can only get one image unless build own camera UI) of MediaFile object representing the image - * name - * fullPath - * type - * lastModifiedDate - * size - */ -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info -{ - CDVImagePicker* cameraPicker = (CDVImagePicker*)picker; - NSString* callbackId = cameraPicker.callbackId; - - if ([picker respondsToSelector:@selector(presentingViewController)]) { - [[picker presentingViewController] dismissModalViewControllerAnimated:YES]; - } else { - [[picker parentViewController] dismissModalViewControllerAnimated:YES]; - } - - CDVPluginResult* result = nil; - - UIImage* image = nil; - NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType]; - if (!mediaType || [mediaType isEqualToString:(NSString*)kUTTypeImage]) { - // mediaType is nil then only option is UIImagePickerControllerOriginalImage - if ([UIImagePickerController respondsToSelector:@selector(allowsEditing)] && - (cameraPicker.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage])) { - image = [info objectForKey:UIImagePickerControllerEditedImage]; - } else { - image = [info objectForKey:UIImagePickerControllerOriginalImage]; - } - } - if (image != nil) { - // mediaType was image - result = [self processImage:image type:cameraPicker.mimeType forCallbackId:callbackId]; - } else if ([mediaType isEqualToString:(NSString*)kUTTypeMovie]) { - // process video - NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path]; - if (moviePath) { - result = [self processVideo:moviePath forCallbackId:callbackId]; - } - } - if (!result) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_INTERNAL_ERR]; - } - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - pickerController = nil; -} - -- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker -{ - CDVImagePicker* cameraPicker = (CDVImagePicker*)picker; - NSString* callbackId = cameraPicker.callbackId; - - if ([picker respondsToSelector:@selector(presentingViewController)]) { - [[picker presentingViewController] dismissModalViewControllerAnimated:YES]; - } else { - [[picker parentViewController] dismissModalViewControllerAnimated:YES]; - } - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:CAPTURE_NO_MEDIA_FILES]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - pickerController = nil; -} - -@end - -@implementation CDVAudioNavigationController - -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000 - - (NSUInteger)supportedInterfaceOrientations - { - // delegate to CVDAudioRecorderViewController - return [self.topViewController supportedInterfaceOrientations]; - } -#endif - -@end - -@implementation CDVAudioRecorderViewController -@synthesize errorCode, callbackId, duration, captureCommand, doneButton, recordingView, recordButton, recordImage, stopRecordImage, timerLabel, avRecorder, avSession, pluginResult, timer, isTimed; - -- (NSString*)resolveImageResource:(NSString*)resource -{ - NSString* systemVersion = [[UIDevice currentDevice] systemVersion]; - BOOL isLessThaniOS4 = ([systemVersion compare:@"4.0" options:NSNumericSearch] == NSOrderedAscending); - - // the iPad image (nor retina) differentiation code was not in 3.x, and we have to explicitly set the path - // if user wants iPhone only app to run on iPad they must remove *~ipad.* images from capture.bundle - if (isLessThaniOS4) { - NSString* iPadResource = [NSString stringWithFormat:@"%@~ipad.png", resource]; - if (CDV_IsIPad() && [UIImage imageNamed:iPadResource]) { - return iPadResource; - } else { - return [NSString stringWithFormat:@"%@.png", resource]; - } - } - - return resource; -} - -- (id)initWithCommand:(CDVCapture*)theCommand duration:(NSNumber*)theDuration callbackId:(NSString*)theCallbackId -{ - if ((self = [super init])) { - self.captureCommand = theCommand; - self.duration = theDuration; - self.callbackId = theCallbackId; - self.errorCode = CAPTURE_NO_MEDIA_FILES; - self.isTimed = self.duration != nil; - - return self; - } - - return nil; -} - -- (void)loadView -{ - // create view and display - CGRect viewRect = [[UIScreen mainScreen] applicationFrame]; - UIView* tmp = [[UIView alloc] initWithFrame:viewRect]; - - // make backgrounds - NSString* microphoneResource = @"Capture.bundle/microphone"; - - if (CDV_IsIPhone5()) { - microphoneResource = @"Capture.bundle/microphone-568h"; - } - - UIImage* microphone = [UIImage imageNamed:[self resolveImageResource:microphoneResource]]; - UIView* microphoneView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, viewRect.size.width, microphone.size.height)]; - [microphoneView setBackgroundColor:[UIColor colorWithPatternImage:microphone]]; - [microphoneView setUserInteractionEnabled:NO]; - [microphoneView setIsAccessibilityElement:NO]; - [tmp addSubview:microphoneView]; - - // add bottom bar view - UIImage* grayBkg = [UIImage imageNamed:[self resolveImageResource:@"Capture.bundle/controls_bg"]]; - UIView* controls = [[UIView alloc] initWithFrame:CGRectMake(0, microphone.size.height, viewRect.size.width, grayBkg.size.height)]; - [controls setBackgroundColor:[UIColor colorWithPatternImage:grayBkg]]; - [controls setUserInteractionEnabled:NO]; - [controls setIsAccessibilityElement:NO]; - [tmp addSubview:controls]; - - // make red recording background view - UIImage* recordingBkg = [UIImage imageNamed:[self resolveImageResource:@"Capture.bundle/recording_bg"]]; - UIColor* background = [UIColor colorWithPatternImage:recordingBkg]; - self.recordingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, viewRect.size.width, recordingBkg.size.height)]; - [self.recordingView setBackgroundColor:background]; - [self.recordingView setHidden:YES]; - [self.recordingView setUserInteractionEnabled:NO]; - [self.recordingView setIsAccessibilityElement:NO]; - [tmp addSubview:self.recordingView]; - - // add label - self.timerLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, viewRect.size.width, recordingBkg.size.height)]; - // timerLabel.autoresizingMask = reSizeMask; - [self.timerLabel setBackgroundColor:[UIColor clearColor]]; - [self.timerLabel setTextColor:[UIColor whiteColor]]; - [self.timerLabel setTextAlignment:UITextAlignmentCenter]; - [self.timerLabel setText:@"0:00"]; - [self.timerLabel setAccessibilityHint:NSLocalizedString(@"recorded time in minutes and seconds", nil)]; - self.timerLabel.accessibilityTraits |= UIAccessibilityTraitUpdatesFrequently; - self.timerLabel.accessibilityTraits &= ~UIAccessibilityTraitStaticText; - [tmp addSubview:self.timerLabel]; - - // Add record button - - self.recordImage = [UIImage imageNamed:[self resolveImageResource:@"Capture.bundle/record_button"]]; - self.stopRecordImage = [UIImage imageNamed:[self resolveImageResource:@"Capture.bundle/stop_button"]]; - self.recordButton.accessibilityTraits |= [self accessibilityTraits]; - self.recordButton = [[UIButton alloc] initWithFrame:CGRectMake((viewRect.size.width - recordImage.size.width) / 2, (microphone.size.height + (grayBkg.size.height - recordImage.size.height) / 2), recordImage.size.width, recordImage.size.height)]; - [self.recordButton setAccessibilityLabel:NSLocalizedString(@"toggle audio recording", nil)]; - [self.recordButton setImage:recordImage forState:UIControlStateNormal]; - [self.recordButton addTarget:self action:@selector(processButton:) forControlEvents:UIControlEventTouchUpInside]; - [tmp addSubview:recordButton]; - - // make and add done button to navigation bar - self.doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismissAudioView:)]; - [self.doneButton setStyle:UIBarButtonItemStyleDone]; - self.navigationItem.rightBarButtonItem = self.doneButton; - - [self setView:tmp]; -} - -- (void)viewDidLoad -{ - [super viewDidLoad]; - UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); - NSError* error = nil; - - if (self.avSession == nil) { - // create audio session - self.avSession = [AVAudioSession sharedInstance]; - if (error) { - // return error if can't create recording audio session - NSLog(@"error creating audio session: %@", [[error userInfo] description]); - self.errorCode = CAPTURE_INTERNAL_ERR; - [self dismissAudioView:nil]; - } - } - - // create file to record to in temporary dir - - NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath]; // use file system temporary directory - NSError* err = nil; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - - // generate unique file name - NSString* filePath; - int i = 1; - do { - filePath = [NSString stringWithFormat:@"%@/audio_%03d.wav", docsPath, i++]; - } while ([fileMgr fileExistsAtPath:filePath]); - - NSURL* fileURL = [NSURL fileURLWithPath:filePath isDirectory:NO]; - - // create AVAudioPlayer - self.avRecorder = [[AVAudioRecorder alloc] initWithURL:fileURL settings:nil error:&err]; - if (err) { - NSLog(@"Failed to initialize AVAudioRecorder: %@\n", [err localizedDescription]); - self.avRecorder = nil; - // return error - self.errorCode = CAPTURE_INTERNAL_ERR; - [self dismissAudioView:nil]; - } else { - self.avRecorder.delegate = self; - [self.avRecorder prepareToRecord]; - self.recordButton.enabled = YES; - self.doneButton.enabled = YES; - } -} - -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000 - - (NSUInteger)supportedInterfaceOrientations - { - NSUInteger orientation = UIInterfaceOrientationMaskPortrait; // must support portrait - NSUInteger supported = [captureCommand.viewController supportedInterfaceOrientations]; - - orientation = orientation | (supported & UIInterfaceOrientationMaskPortraitUpsideDown); - return orientation; - } -#endif - -- (void)viewDidUnload -{ - [self setView:nil]; - [self.captureCommand setInUse:NO]; -} - -- (void)processButton:(id)sender -{ - if (self.avRecorder.recording) { - // stop recording - [self.avRecorder stop]; - self.isTimed = NO; // recording was stopped via button so reset isTimed - // view cleanup will occur in audioRecordingDidFinishRecording - } else { - // begin recording - [self.recordButton setImage:stopRecordImage forState:UIControlStateNormal]; - self.recordButton.accessibilityTraits &= ~[self accessibilityTraits]; - [self.recordingView setHidden:NO]; - NSError* error = nil; - [self.avSession setCategory:AVAudioSessionCategoryRecord error:&error]; - [self.avSession setActive:YES error:&error]; - if (error) { - // can't continue without active audio session - self.errorCode = CAPTURE_INTERNAL_ERR; - [self dismissAudioView:nil]; - } else { - if (self.duration) { - self.isTimed = true; - [self.avRecorder recordForDuration:[duration doubleValue]]; - } else { - [self.avRecorder record]; - } - [self.timerLabel setText:@"0.00"]; - self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:@selector(updateTime) userInfo:nil repeats:YES]; - self.doneButton.enabled = NO; - } - UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil); - } -} - -/* - * helper method to clean up when stop recording - */ -- (void)stopRecordingCleanup -{ - if (self.avRecorder.recording) { - [self.avRecorder stop]; - } - [self.recordButton setImage:recordImage forState:UIControlStateNormal]; - self.recordButton.accessibilityTraits |= [self accessibilityTraits]; - [self.recordingView setHidden:YES]; - self.doneButton.enabled = YES; - if (self.avSession) { - // deactivate session so sounds can come through - [self.avSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; - [self.avSession setActive:NO error:nil]; - } - if (self.duration && self.isTimed) { - // VoiceOver announcement so user knows timed recording has finished - BOOL isUIAccessibilityAnnouncementNotification = (&UIAccessibilityAnnouncementNotification != NULL); - if (isUIAccessibilityAnnouncementNotification) { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 500ull * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{ - UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, NSLocalizedString(@"timed recording complete", nil)); - }); - } - } else { - // issue a layout notification change so that VO will reannounce the button label when recording completes - UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil); - } -} - -- (void)dismissAudioView:(id)sender -{ - // called when done button pressed or when error condition to do cleanup and remove view - if ([self.captureCommand.viewController.modalViewController respondsToSelector:@selector(presentingViewController)]) { - [[self.captureCommand.viewController.modalViewController presentingViewController] dismissModalViewControllerAnimated:YES]; - } else { - [[self.captureCommand.viewController.modalViewController parentViewController] dismissModalViewControllerAnimated:YES]; - } - - if (!self.pluginResult) { - // return error - self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:self.errorCode]; - } - - self.avRecorder = nil; - [self.avSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; - [self.avSession setActive:NO error:nil]; - [self.captureCommand setInUse:NO]; - UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); - // return result - [self.captureCommand.commandDelegate sendPluginResult:pluginResult callbackId:callbackId]; -} - -- (void)updateTime -{ - // update the label with the elapsed time - [self.timerLabel setText:[self formatTime:self.avRecorder.currentTime]]; -} - -- (NSString*)formatTime:(int)interval -{ - // is this format universal? - int secs = interval % 60; - int min = interval / 60; - - if (interval < 60) { - return [NSString stringWithFormat:@"0:%02d", interval]; - } else { - return [NSString stringWithFormat:@"%d:%02d", min, secs]; - } -} - -- (void)audioRecorderDidFinishRecording:(AVAudioRecorder*)recorder successfully:(BOOL)flag -{ - // may be called when timed audio finishes - need to stop time and reset buttons - [self.timer invalidate]; - [self stopRecordingCleanup]; - - // generate success result - if (flag) { - NSString* filePath = [avRecorder.url path]; - // NSLog(@"filePath: %@", filePath); - NSDictionary* fileDict = [captureCommand getMediaDictionaryFromPath:filePath ofType:@"audio/wav"]; - NSArray* fileArray = [NSArray arrayWithObject:fileDict]; - - self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:fileArray]; - } else { - self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageToErrorObject:CAPTURE_INTERNAL_ERR]; - } -} - -- (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder*)recorder error:(NSError*)error -{ - [self.timer invalidate]; - [self stopRecordingCleanup]; - - NSLog(@"error recording audio"); - self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageToErrorObject:CAPTURE_INTERNAL_ERR]; - [self dismissAudioView:nil]; -} - -@end diff --git a/CordovaLib/Classes/CDVCommandQueue.m b/CordovaLib/Classes/CDVCommandQueue.m deleted file mode 100755 index 1a0dfa0..0000000 --- a/CordovaLib/Classes/CDVCommandQueue.m +++ /dev/null @@ -1,169 +0,0 @@ -/* - 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. - */ - -#include -#import "CDV.h" -#import "CDVCommandQueue.h" -#import "CDVViewController.h" -#import "CDVCommandDelegateImpl.h" - -@interface CDVCommandQueue () { - NSInteger _lastCommandQueueFlushRequestId; - __weak CDVViewController* _viewController; - NSMutableArray* _queue; - BOOL _currentlyExecuting; -} -@end - -@implementation CDVCommandQueue - -@synthesize currentlyExecuting = _currentlyExecuting; - -- (id)initWithViewController:(CDVViewController*)viewController -{ - self = [super init]; - if (self != nil) { - _viewController = viewController; - _queue = [[NSMutableArray alloc] init]; - } - return self; -} - -- (void)dispose -{ - // TODO(agrieve): Make this a zeroing weak ref once we drop support for 4.3. - _viewController = nil; -} - -- (void)resetRequestId -{ - _lastCommandQueueFlushRequestId = 0; -} - -- (void)enqueCommandBatch:(NSString*)batchJSON -{ - if ([batchJSON length] > 0) { - [_queue addObject:batchJSON]; - [self executePending]; - } -} - -- (void)maybeFetchCommandsFromJs:(NSNumber*)requestId -{ - // Use the request ID to determine if we've already flushed for this request. - // This is required only because the NSURLProtocol enqueues the same request - // multiple times. - if ([requestId integerValue] > _lastCommandQueueFlushRequestId) { - _lastCommandQueueFlushRequestId = [requestId integerValue]; - [self fetchCommandsFromJs]; - } -} - -- (void)fetchCommandsFromJs -{ - // Grab all the queued commands from the JS side. - NSString* queuedCommandsJSON = [_viewController.webView stringByEvaluatingJavaScriptFromString: - @"cordova.require('cordova/exec').nativeFetchMessages()"]; - - [self enqueCommandBatch:queuedCommandsJSON]; - if ([queuedCommandsJSON length] > 0) { - CDV_EXEC_LOG(@"Exec: Retrieved new exec messages by request."); - } -} - -- (void)executePending -{ - // Make us re-entrant-safe. - if (_currentlyExecuting) { - return; - } - @try { - _currentlyExecuting = YES; - - for (NSUInteger i = 0; i < [_queue count]; ++i) { - // Parse the returned JSON array. - NSArray* commandBatch = [[_queue objectAtIndex:i] JSONObject]; - - // Iterate over and execute all of the commands. - for (NSArray* jsonEntry in commandBatch) { - CDVInvokedUrlCommand* command = [CDVInvokedUrlCommand commandFromJson:jsonEntry]; - CDV_EXEC_LOG(@"Exec(%@): Calling %@.%@", command.callbackId, command.className, command.methodName); - - if (![self execute:command]) { -#ifdef DEBUG - NSString* commandJson = [jsonEntry JSONString]; - static NSUInteger maxLogLength = 1024; - NSString* commandString = ([commandJson length] > maxLogLength) ? - [NSString stringWithFormat:@"%@[...]", [commandJson substringToIndex:maxLogLength]] : - commandJson; - - DLog(@"FAILED pluginJSON = %@", commandString); -#endif - } - } - } - - [_queue removeAllObjects]; - } @finally - { - _currentlyExecuting = NO; - } -} - -- (BOOL)execute:(CDVInvokedUrlCommand*)command -{ - if ((command.className == nil) || (command.methodName == nil)) { - NSLog(@"ERROR: Classname and/or methodName not found for command."); - return NO; - } - - // Fetch an instance of this class - 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 config.xml.", command.className); - return NO; - } - BOOL retVal = YES; - - // Find the proper selector to call. - NSString* methodName = [NSString stringWithFormat:@"%@:", command.methodName]; - NSString* methodNameWithDict = [NSString stringWithFormat:@"%@:withDict:", command.methodName]; - SEL normalSelector = NSSelectorFromString(methodName); - SEL legacySelector = NSSelectorFromString(methodNameWithDict); - // Test for the legacy selector first in case they both exist. - if ([obj respondsToSelector:legacySelector]) { - NSMutableArray* arguments = nil; - NSMutableDictionary* dict = nil; - [command legacyArguments:&arguments andDict:&dict]; - // [obj performSelector:legacySelector withObject:arguments withObject:dict]; - objc_msgSend(obj, legacySelector, arguments, dict); - } else if ([obj respondsToSelector:normalSelector]) { - // [obj performSelector:normalSelector withObject:command]; - objc_msgSend(obj, normalSelector, command); - } else { - // There's no method to call, so throw an error. - NSLog(@"ERROR: Method '%@' not defined in Plugin '%@'", methodName, command.className); - retVal = NO; - } - - return retVal; -} - -@end diff --git a/CordovaLib/Classes/CDVConnection.h b/CordovaLib/Classes/CDVConnection.h deleted file mode 100755 index d3e8c5d..0000000 --- a/CordovaLib/Classes/CDVConnection.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - 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 -#import "CDVPlugin.h" -#import "CDVReachability.h" - -@interface CDVConnection : CDVPlugin { - NSString* type; - NSString* _callbackId; - - CDVReachability* internetReach; -} - -@property (copy) NSString* connectionType; -@property (strong) CDVReachability* internetReach; - -@end diff --git a/CordovaLib/Classes/CDVConnection.m b/CordovaLib/Classes/CDVConnection.m deleted file mode 100755 index b3f5cab..0000000 --- a/CordovaLib/Classes/CDVConnection.m +++ /dev/null @@ -1,132 +0,0 @@ -/* - 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 "CDVConnection.h" -#import "CDVReachability.h" - -@interface CDVConnection (PrivateMethods) -- (void)updateOnlineStatus; -- (void)sendPluginResult; -@end - -@implementation CDVConnection - -@synthesize connectionType, internetReach; - -- (void)getConnectionInfo:(CDVInvokedUrlCommand*)command -{ - _callbackId = command.callbackId; - [self sendPluginResult]; -} - -- (void)sendPluginResult -{ - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:self.connectionType]; - - [result setKeepCallbackAsBool:YES]; - [self.commandDelegate sendPluginResult:result callbackId:_callbackId]; -} - -- (NSString*)w3cConnectionTypeFor:(CDVReachability*)reachability -{ - NetworkStatus networkStatus = [reachability currentReachabilityStatus]; - - switch (networkStatus) { - case NotReachable: - return @"none"; - - case ReachableViaWWAN: - // Return value of '2g' is deprecated as of 2.6.0 and will be replaced with 'cellular' in 3.0.0 - return @"2g"; - - case ReachableViaWiFi: - return @"wifi"; - - default: - return @"unknown"; - } -} - -- (BOOL)isCellularConnection:(NSString*)theConnectionType -{ - return [theConnectionType isEqualToString:@"2g"] || - [theConnectionType isEqualToString:@"3g"] || - [theConnectionType isEqualToString:@"4g"] || - [theConnectionType isEqualToString:@"cellular"]; -} - -- (void)updateReachability:(CDVReachability*)reachability -{ - if (reachability) { - // check whether the connection type has changed - NSString* newConnectionType = [self w3cConnectionTypeFor:reachability]; - if ([newConnectionType isEqualToString:self.connectionType]) { // the same as before, remove dupes - return; - } else { - self.connectionType = [self w3cConnectionTypeFor:reachability]; - } - } - [self sendPluginResult]; -} - -- (void)updateConnectionType:(NSNotification*)note -{ - CDVReachability* curReach = [note object]; - - if ((curReach != nil) && [curReach isKindOfClass:[CDVReachability class]]) { - [self updateReachability:curReach]; - } -} - -- (void)onPause -{ - [self.internetReach stopNotifier]; -} - -- (void)onResume -{ - [self.internetReach startNotifier]; - [self updateReachability:self.internetReach]; -} - -- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView -{ - self = [super initWithWebView:theWebView]; - if (self) { - self.connectionType = @"none"; - self.internetReach = [CDVReachability reachabilityForInternetConnection]; - self.connectionType = [self w3cConnectionTypeFor:self.internetReach]; - [self.internetReach startNotifier]; - [self printDeprecationNotice]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateConnectionType:) - name:kReachabilityChangedNotification object:nil]; - if (&UIApplicationDidEnterBackgroundNotification && &UIApplicationWillEnterForegroundNotification) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onPause) name:UIApplicationDidEnterBackgroundNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResume) name:UIApplicationWillEnterForegroundNotification object:nil]; - } - } - return self; -} - -- (void)printDeprecationNotice -{ - NSLog(@"DEPRECATION NOTICE: The Connection ReachableViaWWAN return value of '2g' is deprecated as of Cordova version 2.6.0 and will be changed to 'cellular' in a future release. "); -} - -@end diff --git a/CordovaLib/Classes/CDVContact.h b/CordovaLib/Classes/CDVContact.h deleted file mode 100755 index 5187efc..0000000 --- a/CordovaLib/Classes/CDVContact.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - 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 -#import -#import - -enum CDVContactError { - UNKNOWN_ERROR = 0, - INVALID_ARGUMENT_ERROR = 1, - TIMEOUT_ERROR = 2, - PENDING_OPERATION_ERROR = 3, - IO_ERROR = 4, - NOT_SUPPORTED_ERROR = 5, - PERMISSION_DENIED_ERROR = 20 -}; -typedef NSUInteger CDVContactError; - -@interface CDVContact : NSObject { - ABRecordRef record; // the ABRecord associated with this contact - NSDictionary* returnFields; // dictionary of fields to return when performing search -} - -@property (nonatomic, assign) ABRecordRef record; -@property (nonatomic, strong) NSDictionary* returnFields; - -+ (NSDictionary*)defaultABtoW3C; -+ (NSDictionary*)defaultW3CtoAB; -+ (NSSet*)defaultW3CtoNull; -+ (NSDictionary*)defaultObjectAndProperties; -+ (NSDictionary*)defaultFields; - -+ (NSDictionary*)calcReturnFields:(NSArray*)fields; -- (id)init; -- (id)initFromABRecord:(ABRecordRef)aRecord; -- (bool)setFromContactDict:(NSDictionary*)aContact asUpdate:(BOOL)bUpdate; - -+ (BOOL)needsConversion:(NSString*)W3Label; -+ (CFStringRef)convertContactTypeToPropertyLabel:(NSString*)label; -+ (NSString*)convertPropertyLabelToContactType:(NSString*)label; -+ (BOOL)isValidW3ContactType:(NSString*)label; -- (bool)setValue:(id)aValue forProperty:(ABPropertyID)aProperty inRecord:(ABRecordRef)aRecord asUpdate:(BOOL)bUpdate; - -- (NSDictionary*)toDictionary:(NSDictionary*)withFields; -- (NSNumber*)getDateAsNumber:(ABPropertyID)datePropId; -- (NSObject*)extractName; -- (NSObject*)extractMultiValue:(NSString*)propertyId; -- (NSObject*)extractAddresses; -- (NSObject*)extractIms; -- (NSObject*)extractOrganizations; -- (NSObject*)extractPhotos; - -- (NSMutableDictionary*)translateW3Dict:(NSDictionary*)dict forProperty:(ABPropertyID)prop; -- (bool)setMultiValueStrings:(NSArray*)fieldArray forProperty:(ABPropertyID)prop inRecord:(ABRecordRef)person asUpdate:(BOOL)bUpdate; -- (bool)setMultiValueDictionary:(NSArray*)array forProperty:(ABPropertyID)prop inRecord:(ABRecordRef)person asUpdate:(BOOL)bUpdate; -- (ABMultiValueRef)allocStringMultiValueFromArray:array; -- (ABMultiValueRef)allocDictMultiValueFromArray:array forProperty:(ABPropertyID)prop; -- (BOOL)foundValue:(NSString*)testValue inFields:(NSDictionary*)searchFields; -- (BOOL)testStringValue:(NSString*)testValue forW3CProperty:(NSString*)property; -- (BOOL)testDateValue:(NSString*)testValue forW3CProperty:(NSString*)property; -- (BOOL)searchContactFields:(NSArray*)fields forMVStringProperty:(ABPropertyID)propId withValue:testValue; -- (BOOL)testMultiValueStrings:(NSString*)testValue forProperty:(ABPropertyID)propId ofType:(NSString*)type; -- (NSArray*)valuesForProperty:(ABPropertyID)propId inRecord:(ABRecordRef)aRecord; -- (NSArray*)labelsForProperty:(ABPropertyID)propId inRecord:(ABRecordRef)aRecord; -- (BOOL)searchContactFields:(NSArray*)fields forMVDictionaryProperty:(ABPropertyID)propId withValue:(NSString*)testValue; - -@end - -// generic ContactField types -#define kW3ContactFieldType @"type" -#define kW3ContactFieldValue @"value" -#define kW3ContactFieldPrimary @"pref" -// Various labels for ContactField types -#define kW3ContactWorkLabel @"work" -#define kW3ContactHomeLabel @"home" -#define kW3ContactOtherLabel @"other" -#define kW3ContactPhoneFaxLabel @"fax" -#define kW3ContactPhoneMobileLabel @"mobile" -#define kW3ContactPhonePagerLabel @"pager" -#define kW3ContactUrlBlog @"blog" -#define kW3ContactUrlProfile @"profile" -#define kW3ContactImAIMLabel @"aim" -#define kW3ContactImICQLabel @"icq" -#define kW3ContactImMSNLabel @"msn" -#define kW3ContactImYahooLabel @"yahoo" -#define kW3ContactFieldId @"id" -// special translation for IM field value and type -#define kW3ContactImType @"type" -#define kW3ContactImValue @"value" - -// Contact object -#define kW3ContactId @"id" -#define kW3ContactName @"name" -#define kW3ContactFormattedName @"formatted" -#define kW3ContactGivenName @"givenName" -#define kW3ContactFamilyName @"familyName" -#define kW3ContactMiddleName @"middleName" -#define kW3ContactHonorificPrefix @"honorificPrefix" -#define kW3ContactHonorificSuffix @"honorificSuffix" -#define kW3ContactDisplayName @"displayName" -#define kW3ContactNickname @"nickname" -#define kW3ContactPhoneNumbers @"phoneNumbers" -#define kW3ContactAddresses @"addresses" -#define kW3ContactAddressFormatted @"formatted" -#define kW3ContactStreetAddress @"streetAddress" -#define kW3ContactLocality @"locality" -#define kW3ContactRegion @"region" -#define kW3ContactPostalCode @"postalCode" -#define kW3ContactCountry @"country" -#define kW3ContactEmails @"emails" -#define kW3ContactIms @"ims" -#define kW3ContactOrganizations @"organizations" -#define kW3ContactOrganizationName @"name" -#define kW3ContactTitle @"title" -#define kW3ContactDepartment @"department" -#define kW3ContactBirthday @"birthday" -#define kW3ContactNote @"note" -#define kW3ContactPhotos @"photos" -#define kW3ContactCategories @"categories" -#define kW3ContactUrls @"urls" diff --git a/CordovaLib/Classes/CDVContact.m b/CordovaLib/Classes/CDVContact.m deleted file mode 100755 index 3844525..0000000 --- a/CordovaLib/Classes/CDVContact.m +++ /dev/null @@ -1,1752 +0,0 @@ -/* - 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 "CDVContact.h" -#import "NSDictionary+Extensions.h" - -#define DATE_OR_NULL(dateObj) ((aDate != nil) ? (id)([aDate descriptionWithLocale:[NSLocale currentLocale]]) : (id)([NSNull null])) -#define IS_VALID_VALUE(value) ((value != nil) && (![value isKindOfClass:[NSNull class]])) - -static NSDictionary* org_apache_cordova_contacts_W3CtoAB = nil; -static NSDictionary* org_apache_cordova_contacts_ABtoW3C = nil; -static NSSet* org_apache_cordova_contacts_W3CtoNull = nil; -static NSDictionary* org_apache_cordova_contacts_objectAndProperties = nil; -static NSDictionary* org_apache_cordova_contacts_defaultFields = nil; - -@implementation CDVContact : NSObject - - @synthesize returnFields; - -- (id)init -{ - if ((self = [super init]) != nil) { - ABRecordRef rec = ABPersonCreate(); - self.record = rec; - if (rec) { - CFRelease(rec); - } - } - return self; -} - -- (id)initFromABRecord:(ABRecordRef)aRecord -{ - if ((self = [super init]) != nil) { - self.record = aRecord; - } - return self; -} - -/* synthesize 'record' ourselves to have retain properties for CF types */ - -- (void)setRecord:(ABRecordRef)aRecord -{ - if (record != NULL) { - CFRelease(record); - } - if (aRecord != NULL) { - record = CFRetain(aRecord); - } -} - -- (ABRecordRef)record -{ - return record; -} - -/* Rather than creating getters and setters for each AddressBook (AB) Property, generic methods are used to deal with - * simple properties, MultiValue properties( phone numbers and emails) and MultiValueDictionary properties (Ims and addresses). - * The dictionaries below are used to translate between the W3C identifiers and the AB properties. Using the dictionaries, - * allows looping through sets of properties to extract from or set into the W3C dictionary to/from the ABRecord. - */ - -/* The two following dictionaries translate between W3C properties and AB properties. It currently mixes both - * Properties (kABPersonAddressProperty for example) and Strings (kABPersonAddressStreetKey) so users should be aware of - * what types of values are expected. - * a bit. -*/ -+ (NSDictionary*)defaultABtoW3C -{ - if (org_apache_cordova_contacts_ABtoW3C == nil) { - org_apache_cordova_contacts_ABtoW3C = [NSDictionary dictionaryWithObjectsAndKeys: - kW3ContactNickname, [NSNumber numberWithInt:kABPersonNicknameProperty], - kW3ContactGivenName, [NSNumber numberWithInt:kABPersonFirstNameProperty], - kW3ContactFamilyName, [NSNumber numberWithInt:kABPersonLastNameProperty], - kW3ContactMiddleName, [NSNumber numberWithInt:kABPersonMiddleNameProperty], - kW3ContactHonorificPrefix, [NSNumber numberWithInt:kABPersonPrefixProperty], - kW3ContactHonorificSuffix, [NSNumber numberWithInt:kABPersonSuffixProperty], - kW3ContactPhoneNumbers, [NSNumber numberWithInt:kABPersonPhoneProperty], - kW3ContactAddresses, [NSNumber numberWithInt:kABPersonAddressProperty], - kW3ContactStreetAddress, kABPersonAddressStreetKey, - kW3ContactLocality, kABPersonAddressCityKey, - kW3ContactRegion, kABPersonAddressStateKey, - kW3ContactPostalCode, kABPersonAddressZIPKey, - kW3ContactCountry, kABPersonAddressCountryKey, - kW3ContactEmails, [NSNumber numberWithInt:kABPersonEmailProperty], - kW3ContactIms, [NSNumber numberWithInt:kABPersonInstantMessageProperty], - kW3ContactOrganizations, [NSNumber numberWithInt:kABPersonOrganizationProperty], - kW3ContactOrganizationName, [NSNumber numberWithInt:kABPersonOrganizationProperty], - kW3ContactTitle, [NSNumber numberWithInt:kABPersonJobTitleProperty], - kW3ContactDepartment, [NSNumber numberWithInt:kABPersonDepartmentProperty], - kW3ContactBirthday, [NSNumber numberWithInt:kABPersonBirthdayProperty], - kW3ContactUrls, [NSNumber numberWithInt:kABPersonURLProperty], - kW3ContactNote, [NSNumber numberWithInt:kABPersonNoteProperty], - nil]; - } - - return org_apache_cordova_contacts_ABtoW3C; -} - -+ (NSDictionary*)defaultW3CtoAB -{ - if (org_apache_cordova_contacts_W3CtoAB == nil) { - org_apache_cordova_contacts_W3CtoAB = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt:kABPersonNicknameProperty], kW3ContactNickname, - [NSNumber numberWithInt:kABPersonFirstNameProperty], kW3ContactGivenName, - [NSNumber numberWithInt:kABPersonLastNameProperty], kW3ContactFamilyName, - [NSNumber numberWithInt:kABPersonMiddleNameProperty], kW3ContactMiddleName, - [NSNumber numberWithInt:kABPersonPrefixProperty], kW3ContactHonorificPrefix, - [NSNumber numberWithInt:kABPersonSuffixProperty], kW3ContactHonorificSuffix, - [NSNumber numberWithInt:kABPersonPhoneProperty], kW3ContactPhoneNumbers, - [NSNumber numberWithInt:kABPersonAddressProperty], kW3ContactAddresses, - kABPersonAddressStreetKey, kW3ContactStreetAddress, - kABPersonAddressCityKey, kW3ContactLocality, - kABPersonAddressStateKey, kW3ContactRegion, - kABPersonAddressZIPKey, kW3ContactPostalCode, - kABPersonAddressCountryKey, kW3ContactCountry, - [NSNumber numberWithInt:kABPersonEmailProperty], kW3ContactEmails, - [NSNumber numberWithInt:kABPersonInstantMessageProperty], kW3ContactIms, - [NSNumber numberWithInt:kABPersonOrganizationProperty], kW3ContactOrganizations, - [NSNumber numberWithInt:kABPersonJobTitleProperty], kW3ContactTitle, - [NSNumber numberWithInt:kABPersonDepartmentProperty], kW3ContactDepartment, - [NSNumber numberWithInt:kABPersonBirthdayProperty], kW3ContactBirthday, - [NSNumber numberWithInt:kABPersonNoteProperty], kW3ContactNote, - [NSNumber numberWithInt:kABPersonURLProperty], kW3ContactUrls, - kABPersonInstantMessageUsernameKey, kW3ContactImValue, - kABPersonInstantMessageServiceKey, kW3ContactImType, - [NSNull null], kW3ContactFieldType, /* include entries in dictionary to indicate ContactField properties */ - [NSNull null], kW3ContactFieldValue, - [NSNull null], kW3ContactFieldPrimary, - [NSNull null], kW3ContactFieldId, - [NSNumber numberWithInt:kABPersonOrganizationProperty], kW3ContactOrganizationName, /* careful, name is used multiple times*/ - nil]; - } - return org_apache_cordova_contacts_W3CtoAB; -} - -+ (NSSet*)defaultW3CtoNull -{ - // these are values that have no AddressBook Equivalent OR have not been implemented yet - if (org_apache_cordova_contacts_W3CtoNull == nil) { - org_apache_cordova_contacts_W3CtoNull = [NSSet setWithObjects:kW3ContactDisplayName, - kW3ContactCategories, kW3ContactFormattedName, nil]; - } - return org_apache_cordova_contacts_W3CtoNull; -} - -/* - * The objectAndProperties dictionary contains the all of the properties of the W3C Contact Objects specified by the key - * Used in calcReturnFields, and various extract methods - */ -+ (NSDictionary*)defaultObjectAndProperties -{ - if (org_apache_cordova_contacts_objectAndProperties == nil) { - org_apache_cordova_contacts_objectAndProperties = [NSDictionary dictionaryWithObjectsAndKeys: - [NSArray arrayWithObjects:kW3ContactGivenName, kW3ContactFamilyName, - kW3ContactMiddleName, kW3ContactHonorificPrefix, kW3ContactHonorificSuffix, kW3ContactFormattedName, nil], kW3ContactName, - [NSArray arrayWithObjects:kW3ContactStreetAddress, kW3ContactLocality, kW3ContactRegion, - kW3ContactPostalCode, kW3ContactCountry, /*kW3ContactAddressFormatted,*/ nil], kW3ContactAddresses, - [NSArray arrayWithObjects:kW3ContactOrganizationName, kW3ContactTitle, kW3ContactDepartment, nil], kW3ContactOrganizations, - [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary, nil], kW3ContactPhoneNumbers, - [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary, nil], kW3ContactEmails, - [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary, nil], kW3ContactPhotos, - [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary, nil], kW3ContactUrls, - [NSArray arrayWithObjects:kW3ContactImValue, kW3ContactImType, nil], kW3ContactIms, - nil]; - } - return org_apache_cordova_contacts_objectAndProperties; -} - -+ (NSDictionary*)defaultFields -{ - if (org_apache_cordova_contacts_defaultFields == nil) { - org_apache_cordova_contacts_defaultFields = [NSDictionary dictionaryWithObjectsAndKeys: - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactName], kW3ContactName, - [NSNull null], kW3ContactNickname, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactAddresses], kW3ContactAddresses, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactOrganizations], kW3ContactOrganizations, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactPhoneNumbers], kW3ContactPhoneNumbers, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactEmails], kW3ContactEmails, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactIms], kW3ContactIms, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactPhotos], kW3ContactPhotos, - [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactUrls], kW3ContactUrls, - [NSNull null], kW3ContactBirthday, - [NSNull null], kW3ContactNote, - nil]; - } - return org_apache_cordova_contacts_defaultFields; -} - -/* Translate W3C Contact data into ABRecordRef - * - * New contact information comes in as a NSMutableDictionary. All Null entries in Contact object are set - * as [NSNull null] in the dictionary when translating from the JSON input string of Contact data. However, if - * user did not set a value within a Contact object or sub-object (by not using the object constructor) some data - * may not exist. - * bUpdate = YES indicates this is a save of an existing record - */ -- (bool)setFromContactDict:(NSDictionary*)aContact asUpdate:(BOOL)bUpdate -{ - if (![aContact isKindOfClass:[NSDictionary class]]) { - return FALSE; // can't do anything if no dictionary! - } - - ABRecordRef person = self.record; - bool bSuccess = TRUE; - CFErrorRef error; - - // set name info - // iOS doesn't have displayName - might have to pull parts from it to create name - bool bName = false; - NSDictionary* dict = [aContact valueForKey:kW3ContactName]; - if ([dict isKindOfClass:[NSDictionary class]]) { - bName = true; - NSArray* propArray = [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactName]; - - for (id i in propArray) { - if (![(NSString*)i isEqualToString : kW3ContactFormattedName]) { // kW3ContactFormattedName is generated from ABRecordCopyCompositeName() and can't be set - [self setValue:[dict valueForKey:i] forProperty:(ABPropertyID)[(NSNumber*)[[CDVContact defaultW3CtoAB] objectForKey:i] intValue] - inRecord:person asUpdate:bUpdate]; - } - } - } - - id nn = [aContact valueForKey:kW3ContactNickname]; - if (![nn isKindOfClass:[NSNull class]]) { - bName = true; - [self setValue:nn forProperty:kABPersonNicknameProperty inRecord:person asUpdate:bUpdate]; - } - if (!bName) { - // if no name or nickname - try and use displayName as W3Contact must have displayName or ContactName - [self setValue:[aContact valueForKey:kW3ContactDisplayName] forProperty:kABPersonNicknameProperty - inRecord:person asUpdate:bUpdate]; - } - - // set phoneNumbers - // NSLog(@"setting phoneNumbers"); - NSArray* array = [aContact valueForKey:kW3ContactPhoneNumbers]; - if ([array isKindOfClass:[NSArray class]]) { - [self setMultiValueStrings:array forProperty:kABPersonPhoneProperty inRecord:person asUpdate:bUpdate]; - } - // set Emails - // NSLog(@"setting emails"); - array = [aContact valueForKey:kW3ContactEmails]; - if ([array isKindOfClass:[NSArray class]]) { - [self setMultiValueStrings:array forProperty:kABPersonEmailProperty inRecord:person asUpdate:bUpdate]; - } - // set Urls - // NSLog(@"setting urls"); - array = [aContact valueForKey:kW3ContactUrls]; - if ([array isKindOfClass:[NSArray class]]) { - [self setMultiValueStrings:array forProperty:kABPersonURLProperty inRecord:person asUpdate:bUpdate]; - } - - // set multivalue dictionary properties - // set addresses: streetAddress, locality, region, postalCode, country - // set ims: value = username, type = servicetype - // iOS addresses and im are a MultiValue Properties with label, value=dictionary of info, and id - // NSLog(@"setting addresses"); - error = nil; - array = [aContact valueForKey:kW3ContactAddresses]; - if ([array isKindOfClass:[NSArray class]]) { - [self setMultiValueDictionary:array forProperty:kABPersonAddressProperty inRecord:person asUpdate:bUpdate]; - } - // ims - // NSLog(@"setting ims"); - array = [aContact valueForKey:kW3ContactIms]; - if ([array isKindOfClass:[NSArray class]]) { - [self setMultiValueDictionary:array forProperty:kABPersonInstantMessageProperty inRecord:person asUpdate:bUpdate]; - } - - // organizations - // W3C ContactOrganization has pref, type, name, title, department - // iOS only supports name, title, department - // NSLog(@"setting organizations"); - // TODO this may need work - should Organization information be removed when array is empty?? - array = [aContact valueForKey:kW3ContactOrganizations]; // iOS only supports one organization - use first one - if ([array isKindOfClass:[NSArray class]]) { - BOOL bRemove = NO; - NSDictionary* dict = nil; - if ([array count] > 0) { - dict = [array objectAtIndex:0]; - } else { - // remove the organization info entirely - bRemove = YES; - } - if ([dict isKindOfClass:[NSDictionary class]] || (bRemove == YES)) { - [self setValue:(bRemove ? @"" : [dict valueForKey:@"name"]) forProperty:kABPersonOrganizationProperty inRecord:person asUpdate:bUpdate]; - [self setValue:(bRemove ? @"" : [dict valueForKey:kW3ContactTitle]) forProperty:kABPersonJobTitleProperty inRecord:person asUpdate:bUpdate]; - [self setValue:(bRemove ? @"" : [dict valueForKey:kW3ContactDepartment]) forProperty:kABPersonDepartmentProperty inRecord:person asUpdate:bUpdate]; - } - } - // add dates - // Dates come in as milliseconds in NSNumber Object - id ms = [aContact valueForKey:kW3ContactBirthday]; - NSDate* aDate = nil; - if (ms && [ms isKindOfClass:[NSNumber class]]) { - double msValue = [ms doubleValue]; - msValue = msValue / 1000; - aDate = [NSDate dateWithTimeIntervalSince1970:msValue]; - } - if ((aDate != nil) || [ms isKindOfClass:[NSString class]]) { - [self setValue:aDate != nil ? aDate:ms forProperty:kABPersonBirthdayProperty inRecord:person asUpdate:bUpdate]; - } - // don't update creation date - // modification date will get updated when save - // anniversary is removed from W3C Contact api Dec 9, 2010 spec - don't waste time on it yet - - // kABPersonDateProperty - - // kABPersonAnniversaryLabel - - // iOS doesn't have gender - ignore - // note - [self setValue:[aContact valueForKey:kW3ContactNote] forProperty:kABPersonNoteProperty inRecord:person asUpdate:bUpdate]; - - // iOS doesn't have preferredName- ignore - - // photo - array = [aContact valueForKey:kW3ContactPhotos]; - if ([array isKindOfClass:[NSArray class]]) { - if (bUpdate && ([array count] == 0)) { - // remove photo - bSuccess = ABPersonRemoveImageData(person, &error); - } else if ([array count] > 0) { - NSDictionary* dict = [array objectAtIndex:0]; // currently only support one photo - if ([dict isKindOfClass:[NSDictionary class]]) { - id value = [dict objectForKey:kW3ContactFieldValue]; - if ([value isKindOfClass:[NSString class]]) { - if (bUpdate && ([value length] == 0)) { - // remove the current image - bSuccess = ABPersonRemoveImageData(person, &error); - } else { - // use this image - // don't know if string is encoded or not so first unencode it then encode it again - NSString* cleanPath = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - NSURL* photoUrl = [NSURL URLWithString:[cleanPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; - // caller is responsible for checking for a connection, if no connection this will fail - NSError* err = nil; - NSData* data = nil; - if (photoUrl) { - data = [NSData dataWithContentsOfURL:photoUrl options:NSDataReadingUncached error:&err]; - } - if (data && ([data length] > 0)) { - bSuccess = ABPersonSetImageData(person, (__bridge CFDataRef)data, &error); - } - if (!data || !bSuccess) { - NSLog(@"error setting contact image: %@", (err != nil ? [err localizedDescription] : @"")); - } - } - } - } - } - } - - // TODO WebURLs - - // TODO timezone - - return bSuccess; -} - -/* Set item into an AddressBook Record for the specified property. - * aValue - the value to set into the address book (code checks for null or [NSNull null] - * aProperty - AddressBook property ID - * aRecord - the record to update - * bUpdate - whether this is a possible update vs a new entry - * RETURN - * true - property was set (or input value as null) - * false - property was not set - */ -- (bool)setValue:(id)aValue forProperty:(ABPropertyID)aProperty inRecord:(ABRecordRef)aRecord asUpdate:(BOOL)bUpdate -{ - bool bSuccess = true; // if property was null, just ignore and return success - CFErrorRef error; - - if (aValue && ![aValue isKindOfClass:[NSNull class]]) { - if (bUpdate && ([aValue isKindOfClass:[NSString class]] && ([aValue length] == 0))) { // if updating, empty string means to delete - aValue = NULL; - } // really only need to set if different - more efficient to just update value or compare and only set if necessary??? - bSuccess = ABRecordSetValue(aRecord, aProperty, (__bridge CFTypeRef)aValue, &error); - if (!bSuccess) { - NSLog(@"error setting %d property", aProperty); - } - } - - return bSuccess; -} - -- (bool)removeProperty:(ABPropertyID)aProperty inRecord:(ABRecordRef)aRecord -{ - CFErrorRef err; - bool bSuccess = ABRecordRemoveValue(aRecord, aProperty, &err); - - if (!bSuccess) { - CFStringRef errDescription = CFErrorCopyDescription(err); - NSLog(@"Unable to remove property %d: %@", aProperty, errDescription); - CFRelease(errDescription); - } - return bSuccess; -} - -- (bool)addToMultiValue:(ABMultiValueRef)multi fromDictionary:dict -{ - bool bSuccess = FALSE; - id value = [dict valueForKey:kW3ContactFieldValue]; - - if (IS_VALID_VALUE(value)) { - CFStringRef label = [CDVContact convertContactTypeToPropertyLabel:[dict valueForKey:kW3ContactFieldType]]; - bSuccess = ABMultiValueAddValueAndLabel(multi, (__bridge CFTypeRef)value, label, NULL); - if (!bSuccess) { - NSLog(@"Error setting Value: %@ and label: %@", value, label); - } - } - return bSuccess; -} - -- (ABMultiValueRef)allocStringMultiValueFromArray:array -{ - ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABMultiStringPropertyType); - - for (NSDictionary* dict in array) { - [self addToMultiValue:multi fromDictionary:dict]; - } - - return multi; // caller is responsible for releasing multi -} - -- (bool)setValue:(CFTypeRef)value forProperty:(ABPropertyID)prop inRecord:(ABRecordRef)person -{ - CFErrorRef error; - bool bSuccess = ABRecordSetValue(person, prop, value, &error); - - if (!bSuccess) { - NSLog(@"Error setting value for property: %d", prop); - } - return bSuccess; -} - -/* Set MultiValue string properties into Address Book Record. - * NSArray* fieldArray - array of dictionaries containing W3C properties to be set into record - * ABPropertyID prop - the property to be set (generally used for phones and emails) - * ABRecordRef person - the record to set values into - * BOOL bUpdate - whether or not to update date or set as new. - * When updating: - * empty array indicates to remove entire property - * empty string indicates to remove - * [NSNull null] do not modify (keep existing record value) - * RETURNS - * bool false indicates error - * - * used for phones and emails - */ -- (bool)setMultiValueStrings:(NSArray*)fieldArray forProperty:(ABPropertyID)prop inRecord:(ABRecordRef)person asUpdate:(BOOL)bUpdate -{ - bool bSuccess = TRUE; - ABMutableMultiValueRef multi = nil; - - if (!bUpdate) { - multi = [self allocStringMultiValueFromArray:fieldArray]; - bSuccess = [self setValue:multi forProperty:prop inRecord:person]; - } else if (bUpdate && ([fieldArray count] == 0)) { - // remove entire property - bSuccess = [self removeProperty:prop inRecord:person]; - } else { // check for and apply changes - ABMultiValueRef copy = ABRecordCopyValue(person, prop); - if (copy != nil) { - multi = ABMultiValueCreateMutableCopy(copy); - CFRelease(copy); - - for (NSDictionary* dict in fieldArray) { - id val; - NSString* label = nil; - val = [dict valueForKey:kW3ContactFieldValue]; - label = (__bridge NSString*)[CDVContact convertContactTypeToPropertyLabel:[dict valueForKey:kW3ContactFieldType]]; - if (IS_VALID_VALUE(val)) { - // is an update, find index of entry with matching id, if values are different, update. - id idValue = [dict valueForKey:kW3ContactFieldId]; - int identifier = [idValue isKindOfClass:[NSNumber class]] ? [idValue intValue] : -1; - CFIndex i = identifier >= 0 ? ABMultiValueGetIndexForIdentifier(multi, identifier) : kCFNotFound; - if (i != kCFNotFound) { - if ([val length] == 0) { - // remove both value and label - ABMultiValueRemoveValueAndLabelAtIndex(multi, i); - } else { - NSString* valueAB = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(multi, i); - NSString* labelAB = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(multi, i); - if ((valueAB == nil) || ![val isEqualToString:valueAB]) { - ABMultiValueReplaceValueAtIndex(multi, (__bridge CFTypeRef)val, i); - } - if ((labelAB == nil) || ![label isEqualToString:labelAB]) { - ABMultiValueReplaceLabelAtIndex(multi, (__bridge CFStringRef)label, i); - } - } - } else { - // is a new value - insert - [self addToMultiValue:multi fromDictionary:dict]; - } - } // end of if value - } // end of for - } else { // adding all new value(s) - multi = [self allocStringMultiValueFromArray:fieldArray]; - } - // set the (updated) copy as the new value - bSuccess = [self setValue:multi forProperty:prop inRecord:person]; - } - - if (multi) { - CFRelease(multi); - } - - return bSuccess; -} - -// used for ims and addresses -- (ABMultiValueRef)allocDictMultiValueFromArray:array forProperty:(ABPropertyID)prop -{ - ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType); - NSMutableDictionary* newDict; - NSMutableDictionary* addDict; - - for (NSDictionary* dict in array) { - newDict = [self translateW3Dict:dict forProperty:prop]; - addDict = [NSMutableDictionary dictionaryWithCapacity:2]; - if (newDict) { // create a new dictionary with a Label and Value, value is the dictionary previously created - // June, 2011 W3C Contact spec adds type into ContactAddress book - // get the type out of the original dictionary for address - NSString* addrType = (NSString*)[dict valueForKey:kW3ContactFieldType]; - if (!addrType) { - addrType = (NSString*)kABOtherLabel; - } - NSObject* typeValue = ((prop == kABPersonInstantMessageProperty) ? (NSObject*)kABOtherLabel : addrType); - // NSLog(@"typeValue: %@", typeValue); - [addDict setObject:typeValue forKey:kW3ContactFieldType]; // im labels will be set as Other and address labels as type from dictionary - [addDict setObject:newDict forKey:kW3ContactFieldValue]; - [self addToMultiValue:multi fromDictionary:addDict]; - } - } - - return multi; // caller is responsible for releasing -} - -// used for ims and addresses to convert W3 dictionary of values to AB Dictionary -// got messier when June, 2011 W3C Contact spec added type field into ContactAddress -- (NSMutableDictionary*)translateW3Dict:(NSDictionary*)dict forProperty:(ABPropertyID)prop -{ - NSArray* propArray = [[CDVContact defaultObjectAndProperties] valueForKey:[[CDVContact defaultABtoW3C] objectForKey:[NSNumber numberWithInt:prop]]]; - - NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:1]; - id value; - - for (NSString* key in propArray) { // for each W3 Contact key get the value - if (((value = [dict valueForKey:key]) != nil) && ![value isKindOfClass:[NSNull class]]) { - // if necessary convert the W3 value to AB Property label - NSString* setValue = value; - if ([CDVContact needsConversion:key]) { // IM types must be converted - setValue = (NSString*)[CDVContact convertContactTypeToPropertyLabel:value]; - // IMs must have a valid AB value! - if ((prop == kABPersonInstantMessageProperty) && [setValue isEqualToString:(NSString*)kABOtherLabel]) { - setValue = @""; // try empty string - } - } - // set the AB value into the dictionary - [newDict setObject:setValue forKey:(NSString*)[[CDVContact defaultW3CtoAB] valueForKey:(NSString*)key]]; - } - } - - if ([newDict count] == 0) { - newDict = nil; // no items added - } - return newDict; -} - -/* set multivalue dictionary properties into an AddressBook Record - * NSArray* array - array of dictionaries containing the W3C properties to set into the record - * ABPropertyID prop - the property id for the multivalue dictionary (addresses and ims) - * ABRecordRef person - the record to set the values into - * BOOL bUpdate - YES if this is an update to an existing record - * When updating: - * empty array indicates to remove entire property - * value/label == "" indicates to remove - * value/label == [NSNull null] do not modify (keep existing record value) - * RETURN - * bool false indicates fatal error - * - * iOS addresses and im are a MultiValue Properties with label, value=dictionary of info, and id - * set addresses: streetAddress, locality, region, postalCode, country - * set ims: value = username, type = servicetype - * there are some special cases in here for ims - needs cleanup / simplification - * - */ -- (bool)setMultiValueDictionary:(NSArray*)array forProperty:(ABPropertyID)prop inRecord:(ABRecordRef)person asUpdate:(BOOL)bUpdate -{ - bool bSuccess = FALSE; - ABMutableMultiValueRef multi = nil; - - if (!bUpdate) { - multi = [self allocDictMultiValueFromArray:array forProperty:prop]; - bSuccess = [self setValue:multi forProperty:prop inRecord:person]; - } else if (bUpdate && ([array count] == 0)) { - // remove property - bSuccess = [self removeProperty:prop inRecord:person]; - } else { // check for and apply changes - ABMultiValueRef copy = ABRecordCopyValue(person, prop); - if (copy) { - multi = ABMultiValueCreateMutableCopy(copy); - CFRelease(copy); - // get the W3C values for this property - NSArray* propArray = [[CDVContact defaultObjectAndProperties] valueForKey:[[CDVContact defaultABtoW3C] objectForKey:[NSNumber numberWithInt:prop]]]; - id value; - id valueAB; - - for (NSDictionary* field in array) { - NSMutableDictionary* dict; - // find the index for the current property - id idValue = [field valueForKey:kW3ContactFieldId]; - int identifier = [idValue isKindOfClass:[NSNumber class]] ? [idValue intValue] : -1; - CFIndex idx = identifier >= 0 ? ABMultiValueGetIndexForIdentifier(multi, identifier) : kCFNotFound; - BOOL bUpdateLabel = NO; - if (idx != kCFNotFound) { - dict = [NSMutableDictionary dictionaryWithCapacity:1]; - // NSDictionary* existingDictionary = (NSDictionary*)ABMultiValueCopyValueAtIndex(multi, idx); - CFTypeRef existingDictionary = ABMultiValueCopyValueAtIndex(multi, idx); - NSString* existingABLabel = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(multi, idx); - NSString* testLabel = [field valueForKey:kW3ContactFieldType]; - // fixes cb-143 where setting empty label could cause address to not be removed - // (because empty label would become 'other' in convertContactTypeToPropertyLabel - // which may not have matched existing label thus resulting in an incorrect updating of the label - // and the address not getting removed at the end of the for loop) - if (testLabel && [testLabel isKindOfClass:[NSString class]] && ([testLabel length] > 0)) { - CFStringRef w3cLabel = [CDVContact convertContactTypeToPropertyLabel:testLabel]; - if (w3cLabel && ![existingABLabel isEqualToString:(__bridge NSString*)w3cLabel]) { - // replace the label - ABMultiValueReplaceLabelAtIndex(multi, w3cLabel, idx); - bUpdateLabel = YES; - } - } // else was invalid or empty label string so do not update - - for (id k in propArray) { - value = [field valueForKey:k]; - bool bSet = (value != nil && ![value isKindOfClass:[NSNull class]] && ([value isKindOfClass:[NSString class]] && [value length] > 0)); - // if there is a contact value, put it into dictionary - if (bSet) { - NSString* setValue = [CDVContact needsConversion:(NSString*)k] ? (NSString*)[CDVContact convertContactTypeToPropertyLabel:value] : value; - [dict setObject:setValue forKey:(NSString*)[[CDVContact defaultW3CtoAB] valueForKey:(NSString*)k]]; - } else if ((value == nil) || ([value isKindOfClass:[NSString class]] && ([value length] != 0))) { - // value not provided in contact dictionary - if prop exists in AB dictionary, preserve it - valueAB = [(__bridge NSDictionary*)existingDictionary valueForKey : [[CDVContact defaultW3CtoAB] valueForKey:k]]; - if (valueAB != nil) { - [dict setValue:valueAB forKey:[[CDVContact defaultW3CtoAB] valueForKey:k]]; - } - } // else if value == "" it will not be added into updated dict and thus removed - } // end of for loop (moving here fixes cb-143, need to end for loop before replacing or removing multivalue) - - if ([dict count] > 0) { - // something was added into new dict, - ABMultiValueReplaceValueAtIndex(multi, (__bridge CFTypeRef)dict, idx); - } else if (!bUpdateLabel) { - // nothing added into new dict and no label change so remove this property entry - ABMultiValueRemoveValueAndLabelAtIndex(multi, idx); - } - - CFRelease(existingDictionary); - } else { - // not found in multivalue so add it - dict = [self translateW3Dict:field forProperty:prop]; - if (dict) { - NSMutableDictionary* addDict = [NSMutableDictionary dictionaryWithCapacity:2]; - // get the type out of the original dictionary for address - NSObject* typeValue = ((prop == kABPersonInstantMessageProperty) ? (NSObject*)kABOtherLabel : (NSString*)[field valueForKey:kW3ContactFieldType]); - // NSLog(@"typeValue: %@", typeValue); - [addDict setObject:typeValue forKey:kW3ContactFieldType]; // im labels will be set as Other and address labels as type from dictionary - [addDict setObject:dict forKey:kW3ContactFieldValue]; - [self addToMultiValue:multi fromDictionary:addDict]; - } - } - } // end of looping through dictionaries - - // set the (updated) copy as the new value - bSuccess = [self setValue:multi forProperty:prop inRecord:person]; - } - } // end of copy and apply changes - if (multi) { - CFRelease(multi); - } - - return bSuccess; -} - -/* Determine which W3C labels need to be converted - */ -+ (BOOL)needsConversion:(NSString*)W3Label -{ - BOOL bConvert = NO; - - if ([W3Label isEqualToString:kW3ContactFieldType] || [W3Label isEqualToString:kW3ContactImType]) { - bConvert = YES; - } - return bConvert; -} - -/* Translation of property type labels contact API ---> iPhone - * - * phone: work, home, other, mobile, fax, pager --> - * kABWorkLabel, kABHomeLabel, kABOtherLabel, kABPersonPhoneMobileLabel, kABPersonHomeFAXLabel || kABPersonHomeFAXLabel, kABPersonPhonePagerLabel - * emails: work, home, other ---> kABWorkLabel, kABHomeLabel, kABOtherLabel - * ims: aim, gtalk, icq, xmpp, msn, skype, qq, yahoo --> kABPersonInstantMessageService + (AIM, ICG, MSN, Yahoo). No support for gtalk, xmpp, skype, qq - * addresses: work, home, other --> kABWorkLabel, kABHomeLabel, kABOtherLabel - * - * - */ -+ (CFStringRef)convertContactTypeToPropertyLabel:(NSString*)label -{ - CFStringRef type; - - if ([label isKindOfClass:[NSNull class]] || ![label isKindOfClass:[NSString class]]) { - type = NULL; // no label - } else if ([label caseInsensitiveCompare:kW3ContactWorkLabel] == NSOrderedSame) { - type = kABWorkLabel; - } else if ([label caseInsensitiveCompare:kW3ContactHomeLabel] == NSOrderedSame) { - type = kABHomeLabel; - } else if ([label caseInsensitiveCompare:kW3ContactOtherLabel] == NSOrderedSame) { - type = kABOtherLabel; - } else if ([label caseInsensitiveCompare:kW3ContactPhoneMobileLabel] == NSOrderedSame) { - type = kABPersonPhoneMobileLabel; - } else if ([label caseInsensitiveCompare:kW3ContactPhonePagerLabel] == NSOrderedSame) { - type = kABPersonPhonePagerLabel; - } else if ([label caseInsensitiveCompare:kW3ContactImAIMLabel] == NSOrderedSame) { - type = kABPersonInstantMessageServiceAIM; - } else if ([label caseInsensitiveCompare:kW3ContactImICQLabel] == NSOrderedSame) { - type = kABPersonInstantMessageServiceICQ; - } else if ([label caseInsensitiveCompare:kW3ContactImMSNLabel] == NSOrderedSame) { - type = kABPersonInstantMessageServiceMSN; - } else if ([label caseInsensitiveCompare:kW3ContactImYahooLabel] == NSOrderedSame) { - type = kABPersonInstantMessageServiceYahoo; - } else if ([label caseInsensitiveCompare:kW3ContactUrlProfile] == NSOrderedSame) { - type = kABPersonHomePageLabel; - } else { - type = kABOtherLabel; - } - - return type; -} - -+ (NSString*)convertPropertyLabelToContactType:(NSString*)label -{ - NSString* type = nil; - - if (label != nil) { // improve efficiency...... - if ([label isEqualToString:(NSString*)kABPersonPhoneMobileLabel]) { - type = kW3ContactPhoneMobileLabel; - } else if ([label isEqualToString:(NSString*)kABPersonPhoneHomeFAXLabel] || - [label isEqualToString:(NSString*)kABPersonPhoneWorkFAXLabel]) { - type = kW3ContactPhoneFaxLabel; - } else if ([label isEqualToString:(NSString*)kABPersonPhonePagerLabel]) { - type = kW3ContactPhonePagerLabel; - } else if ([label isEqualToString:(NSString*)kABHomeLabel]) { - type = kW3ContactHomeLabel; - } else if ([label isEqualToString:(NSString*)kABWorkLabel]) { - type = kW3ContactWorkLabel; - } else if ([label isEqualToString:(NSString*)kABOtherLabel]) { - type = kW3ContactOtherLabel; - } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceAIM]) { - type = kW3ContactImAIMLabel; - } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceICQ]) { - type = kW3ContactImICQLabel; - } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceJabber]) { - type = kW3ContactOtherLabel; - } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceMSN]) { - type = kW3ContactImMSNLabel; - } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceYahoo]) { - type = kW3ContactImYahooLabel; - } else if ([label isEqualToString:(NSString*)kABPersonHomePageLabel]) { - type = kW3ContactUrlProfile; - } else { - type = kW3ContactOtherLabel; - } - } - return type; -} - -/* Check if the input label is a valid W3C ContactField.type. This is used when searching, - * only search field types if the search string is a valid type. If we converted any search - * string to a ABPropertyLabel it could convert to kABOtherLabel which is probably not want - * the user wanted to search for and could skew the results. - */ -+ (BOOL)isValidW3ContactType:(NSString*)label -{ - BOOL isValid = NO; - - if ([label isKindOfClass:[NSNull class]] || ![label isKindOfClass:[NSString class]]) { - isValid = NO; // no label - } else if ([label caseInsensitiveCompare:kW3ContactWorkLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactHomeLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactOtherLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactPhoneMobileLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactPhonePagerLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactImAIMLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactImICQLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactImMSNLabel] == NSOrderedSame) { - isValid = YES; - } else if ([label caseInsensitiveCompare:kW3ContactImYahooLabel] == NSOrderedSame) { - isValid = YES; - } else { - isValid = NO; - } - - return isValid; -} - -/* Create a new Contact Dictionary object from an ABRecordRef that contains information in a format such that - * it can be returned to JavaScript callback as JSON object string. - * Uses: - * ABRecordRef set into Contact Object - * NSDictionary withFields indicates which fields to return from the AddressBook Record - * - * JavaScript Contact: - * @param {DOMString} id unique identifier - * @param {DOMString} displayName - * @param {ContactName} name - * @param {DOMString} nickname - * @param {ContactField[]} phoneNumbers array of phone numbers - * @param {ContactField[]} emails array of email addresses - * @param {ContactAddress[]} addresses array of addresses - * @param {ContactField[]} ims instant messaging user ids - * @param {ContactOrganization[]} organizations - * @param {DOMString} published date contact was first created - * @param {DOMString} updated date contact was last updated - * @param {DOMString} birthday contact's birthday - * @param (DOMString} anniversary contact's anniversary - * @param {DOMString} gender contact's gender - * @param {DOMString} note user notes about contact - * @param {DOMString} preferredUsername - * @param {ContactField[]} photos - * @param {ContactField[]} tags - * @param {ContactField[]} relationships - * @param {ContactField[]} urls contact's web sites - * @param {ContactAccounts[]} accounts contact's online accounts - * @param {DOMString} timezone UTC time zone offset - * @param {DOMString} connected - */ - -- (NSDictionary*)toDictionary:(NSDictionary*)withFields -{ - // if not a person type record bail out for now - if (ABRecordGetRecordType(self.record) != kABPersonType) { - return NULL; - } - id value = nil; - self.returnFields = withFields; - - NSMutableDictionary* nc = [NSMutableDictionary dictionaryWithCapacity:1]; // new contact dictionary to fill in from ABRecordRef - // id - [nc setObject:[NSNumber numberWithInt:ABRecordGetRecordID(self.record)] forKey:kW3ContactId]; - if (self.returnFields == nil) { - // if no returnFields specified, W3C says to return empty contact (but Cordova will at least return id) - return nc; - } - if ([self.returnFields objectForKey:kW3ContactDisplayName]) { - // displayname requested - iOS doesn't have so return null - [nc setObject:[NSNull null] forKey:kW3ContactDisplayName]; - // may overwrite below if requested ContactName and there are no values - } - // nickname - if ([self.returnFields valueForKey:kW3ContactNickname]) { - value = (__bridge_transfer NSString*)ABRecordCopyValue(self.record, kABPersonNicknameProperty); - [nc setObject:(value != nil) ? value:[NSNull null] forKey:kW3ContactNickname]; - } - - // name dictionary - // NSLog(@"getting name info"); - NSObject* data = [self extractName]; - if (data != nil) { - [nc setObject:data forKey:kW3ContactName]; - } - if ([self.returnFields objectForKey:kW3ContactDisplayName] && ((data == nil) || ([(NSDictionary*)data objectForKey : kW3ContactFormattedName] == [NSNull null]))) { - // user asked for displayName which iOS doesn't support but there is no other name data being returned - // try and use Composite Name so some name is returned - id tryName = (__bridge_transfer NSString*)ABRecordCopyCompositeName(self.record); - if (tryName != nil) { - [nc setObject:tryName forKey:kW3ContactDisplayName]; - } else { - // use nickname or empty string - value = (__bridge_transfer NSString*)ABRecordCopyValue(self.record, kABPersonNicknameProperty); - [nc setObject:(value != nil) ? value:@"" forKey:kW3ContactDisplayName]; - } - } - // phoneNumbers array - // NSLog(@"getting phoneNumbers"); - value = [self extractMultiValue:kW3ContactPhoneNumbers]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactPhoneNumbers]; - } - // emails array - // NSLog(@"getting emails"); - value = [self extractMultiValue:kW3ContactEmails]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactEmails]; - } - // urls array - value = [self extractMultiValue:kW3ContactUrls]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactUrls]; - } - // addresses array - // NSLog(@"getting addresses"); - value = [self extractAddresses]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactAddresses]; - } - // im array - // NSLog(@"getting ims"); - value = [self extractIms]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactIms]; - } - // organization array (only info for one organization in iOS) - // NSLog(@"getting organizations"); - value = [self extractOrganizations]; - if (value != nil) { - [nc setObject:value forKey:kW3ContactOrganizations]; - } - - // for simple properties, could make this a bit more efficient by storing all simple properties in a single - // array in the returnFields dictionary and setting them via a for loop through the array - - // add dates - // NSLog(@"getting dates"); - NSNumber* ms; - - /** Contact Revision field removed from June 16, 2011 version of specification - - if ([self.returnFields valueForKey:kW3ContactUpdated]){ - ms = [self getDateAsNumber: kABPersonModificationDateProperty]; - if (!ms){ - // try and get published date - ms = [self getDateAsNumber: kABPersonCreationDateProperty]; - } - if (ms){ - [nc setObject: ms forKey:kW3ContactUpdated]; - } - - } - */ - - if ([self.returnFields valueForKey:kW3ContactBirthday]) { - ms = [self getDateAsNumber:kABPersonBirthdayProperty]; - if (ms) { - [nc setObject:ms forKey:kW3ContactBirthday]; - } - } - - /* Anniversary removed from 12-09-2010 W3C Contacts api spec - if ([self.returnFields valueForKey:kW3ContactAnniversary]){ - // Anniversary date is stored in a multivalue property - ABMultiValueRef multi = ABRecordCopyValue(self.record, kABPersonDateProperty); - if (multi){ - CFStringRef label = nil; - CFIndex count = ABMultiValueGetCount(multi); - // see if contains an Anniversary date - for(CFIndex i=0; i 0) { // ?? this will always be true since we set id,label,primary field?? - [(NSMutableArray*)addresses addObject : newAddress]; - } - CFRelease(dict); - } // end of loop through addresses - } else { - addresses = [NSNull null]; - } - if (multi) { - CFRelease(multi); - } - - return addresses; -} - -/* Create array of Dictionaries to match JavaScript ContactField object for ims - * type one of [aim, gtalk, icq, xmpp, msn, skype, qq, yahoo] needs other as well - * value - * (bool) primary - * id - * - * iOS IMs are a MultiValue Properties with label, value=dictionary of IM details (service, username), and id - */ -- (NSObject*)extractIms -{ - NSArray* fields = [self.returnFields objectForKey:kW3ContactIms]; - - if (fields == nil) { // no name fields requested - return nil; - } - NSObject* imArray; - ABMultiValueRef multi = ABRecordCopyValue(self.record, kABPersonInstantMessageProperty); - CFIndex count = multi ? ABMultiValueGetCount(multi) : 0; - if (count) { - imArray = [NSMutableArray arrayWithCapacity:count]; - - for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) { - 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); - CFStringRef value; // all values should be CFStringRefs / NSString* - bool bFound; - if ([fields containsObject:kW3ContactFieldValue]) { - // value = user name - bFound = CFDictionaryGetValueIfPresent(dict, kABPersonInstantMessageUsernameKey, (void*)&value); - if (bFound && (value != NULL)) { - CFRetain(value); - [newDict setObject:(__bridge id)value forKey:kW3ContactFieldValue]; - CFRelease(value); - } else { - [newDict setObject:[NSNull null] forKey:kW3ContactFieldValue]; - } - } - if ([fields containsObject:kW3ContactFieldType]) { - bFound = CFDictionaryGetValueIfPresent(dict, kABPersonInstantMessageServiceKey, (void*)&value); - if (bFound && (value != NULL)) { - CFRetain(value); - [newDict setObject:(id)[[CDVContact class] convertPropertyLabelToContactType : (__bridge NSString*)value] forKey:kW3ContactFieldType]; - CFRelease(value); - } else { - [newDict setObject:[NSNull null] forKey:kW3ContactFieldType]; - } - } - // always set ID - id identifier = [NSNumber numberWithUnsignedInt:ABMultiValueGetIdentifierAtIndex(multi, i)]; - [newDict setObject:(identifier != nil) ? identifier:[NSNull null] forKey:kW3ContactFieldId]; - - [(NSMutableArray*)imArray addObject : newDict]; - CFRelease(dict); - } - } else { - imArray = [NSNull null]; - } - - if (multi) { - CFRelease(multi); - } - return imArray; -} - -/* Create array of Dictionaries to match JavaScript ContactOrganization object - * pref - not supported in iOS - * type - not supported in iOS - * name - * department - * title - */ - -- (NSObject*)extractOrganizations -{ - NSArray* fields = [self.returnFields objectForKey:kW3ContactOrganizations]; - - if (fields == nil) { // no name fields requested - return nil; - } - NSObject* array = nil; - NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:5]; - id value; - int validValueCount = 0; - - for (id i in fields) { - id key = [[CDVContact defaultW3CtoAB] valueForKey:i]; - if (key && [key isKindOfClass:[NSNumber class]]) { - value = (__bridge_transfer NSString*)ABRecordCopyValue(self.record, (ABPropertyID)[[[CDVContact defaultW3CtoAB] valueForKey:i] intValue]); - if (value != nil) { - // if there are no organization values we should return null for organization - // this counter keeps indicates if any organization values have been set - validValueCount++; - } - [newDict setObject:(value != nil) ? value:[NSNull null] forKey:i]; - } else { // not a key iOS supports, set to null - [newDict setObject:[NSNull null] forKey:i]; - } - } - - if (([newDict count] > 0) && (validValueCount > 0)) { - // add pref and type - // they are not supported by iOS and thus these values never change - [newDict setObject:@"false" forKey:kW3ContactFieldPrimary]; - [newDict setObject:[NSNull null] forKey:kW3ContactFieldType]; - array = [NSMutableArray arrayWithCapacity:1]; - [(NSMutableArray*)array addObject : newDict]; - } else { - array = [NSNull null]; - } - return array; -} - -// W3C Contacts expects an array of photos. Can return photos in more than one format, currently -// just returning the default format -// Save the photo data into tmp directory and return FileURI - temp directory is deleted upon application exit -- (NSObject*)extractPhotos -{ - NSMutableArray* photos = nil; - - if (ABPersonHasImageData(self.record)) { - CFDataRef photoData = ABPersonCopyImageData(self.record); - NSData* data = (__bridge NSData*)photoData; - // write to temp directory and store URI in photos array - // get the temp directory path - NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath]; - NSError* err = nil; - NSString* filePath = [NSString stringWithFormat:@"%@/photo_XXXXX", docsPath]; - char template[filePath.length + 1]; - strcpy(template, [filePath cStringUsingEncoding:NSASCIIStringEncoding]); - mkstemp(template); - filePath = [[NSFileManager defaultManager] - stringWithFileSystemRepresentation:template - length:strlen(template)]; - - // save file - if ([data writeToFile:filePath options:NSAtomicWrite error:&err]) { - photos = [NSMutableArray arrayWithCapacity:1]; - NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:2]; - [newDict setObject:filePath forKey:kW3ContactFieldValue]; - [newDict setObject:@"url" forKey:kW3ContactFieldType]; - [newDict setObject:@"false" forKey:kW3ContactFieldPrimary]; - [photos addObject:newDict]; - } - - CFRelease(photoData); - } - return photos; -} - -/** - * given an array of W3C Contact field names, create a dictionary of field names to extract - * if field name represents an object, return all properties for that object: "name" - returns all properties in ContactName - * if field name is an explicit property, return only those properties: "name.givenName - returns a ContactName with only ContactName.givenName - * if field contains ONLY ["*"] return all fields - * dictionary format: - * key is W3Contact #define - * value is NSMutableArray* for complex keys: name,addresses,organizations, phone, emails, ims - * value is [NSNull null] for simple keys -*/ -+ (NSDictionary*)calcReturnFields:(NSArray*)fieldsArray // NSLog(@"getting self.returnFields"); -{ - NSMutableDictionary* d = [NSMutableDictionary dictionaryWithCapacity:1]; - - if ((fieldsArray != nil) && [fieldsArray isKindOfClass:[NSArray class]]) { - if (([fieldsArray count] == 1) && [[fieldsArray objectAtIndex:0] isEqualToString:@"*"]) { - return [CDVContact defaultFields]; // return all fields - } - - for (id i in fieldsArray) { - NSMutableArray* keys = nil; - NSString* fieldStr = nil; - if ([i isKindOfClass:[NSNumber class]]) { - fieldStr = [i stringValue]; - } else { - fieldStr = i; - } - - // see if this is specific property request in object - object.property - NSArray* parts = [fieldStr componentsSeparatedByString:@"."]; // returns original string if no separator found - NSString* name = [parts objectAtIndex:0]; - NSString* property = nil; - if ([parts count] > 1) { - property = [parts objectAtIndex:1]; - } - // see if this is a complex field by looking for its array of properties in objectAndProperties dictionary - id fields = [[CDVContact defaultObjectAndProperties] objectForKey:name]; - - // if find complex name (name,addresses,organizations, phone, emails, ims) in fields, add name as key - // with array of associated properties as the value - if ((fields != nil) && (property == nil)) { // request was for full object - keys = [NSMutableArray arrayWithArray:fields]; - if (keys != nil) { - [d setObject:keys forKey:name]; // will replace if prop array already exists - } - } else if ((fields != nil) && (property != nil)) { - // found an individual property request in form of name.property - // verify is real property name by using it as key in W3CtoAB - id abEquiv = [[CDVContact defaultW3CtoAB] objectForKey:property]; - if (abEquiv || [[CDVContact defaultW3CtoNull] containsObject:property]) { - // if existing array add to it - if ((keys = [d objectForKey:name]) != nil) { - [keys addObject:property]; - } else { - keys = [NSMutableArray arrayWithObject:property]; - [d setObject:keys forKey:name]; - } - } else { - NSLog(@"Contacts.find -- request for invalid property ignored: %@.%@", name, property); - } - } else { // is an individual property, verify is real property name by using it as key in W3CtoAB - id valid = [[CDVContact defaultW3CtoAB] objectForKey:name]; - if (valid || [[CDVContact defaultW3CtoNull] containsObject:name]) { - [d setObject:[NSNull null] forKey:name]; - } - } - } - } - if ([d count] == 0) { - // no array or nothing in the array. W3C spec says to return nothing - return nil; // [Contact defaultFields]; - } - return d; -} - -/* - * Search for the specified value in each of the fields specified in the searchFields dictionary. - * NSString* value - the string value to search for (need clarification from W3C on how to search for dates) - * NSDictionary* searchFields - a dictionary created via calcReturnFields where the key is the top level W3C - * object and the object is the array of specific fields within that object or null if it is a single property - * RETURNS - * YES as soon as a match is found in any of the fields - * NO - the specified value does not exist in any of the fields in this contact - * - * Note: I'm not a fan of returning in the middle of methods but have done it some in this method in order to - * keep the code simpler. bgibson - */ -- (BOOL)foundValue:(NSString*)testValue inFields:(NSDictionary*)searchFields -{ - BOOL bFound = NO; - - if ((testValue == nil) || ![testValue isKindOfClass:[NSString class]] || ([testValue length] == 0)) { - // nothing to find so return NO - return NO; - } - NSInteger valueAsInt = [testValue integerValue]; - - // per W3C spec, always include id in search - int recordId = ABRecordGetRecordID(self.record); - if (valueAsInt && (recordId == valueAsInt)) { - return YES; - } - - if (searchFields == nil) { - // no fields to search - return NO; - } - - if ([searchFields valueForKey:kW3ContactNickname]) { - bFound = [self testStringValue:testValue forW3CProperty:kW3ContactNickname]; - if (bFound == YES) { - return bFound; - } - } - - if ([searchFields valueForKeyIsArray:kW3ContactName]) { - // test name fields. All are string properties obtained via ABRecordCopyValue except kW3ContactFormattedName - NSArray* fields = [searchFields valueForKey:kW3ContactName]; - - for (NSString* testItem in fields) { - if ([testItem isEqualToString:kW3ContactFormattedName]) { - NSString* propValue = (__bridge_transfer NSString*)ABRecordCopyCompositeName(self.record); - if ((propValue != nil) && ([propValue length] > 0)) { - NSRange range = [propValue rangeOfString:testValue options:NSCaseInsensitiveSearch]; - bFound = (range.location != NSNotFound); - propValue = nil; - } - } else { - bFound = [self testStringValue:testValue forW3CProperty:testItem]; - } - - if (bFound) { - break; - } - } - } - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactPhoneNumbers]) { - bFound = [self searchContactFields:(NSArray*)[searchFields valueForKey:kW3ContactPhoneNumbers] - forMVStringProperty:kABPersonPhoneProperty withValue:testValue]; - } - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactEmails]) { - bFound = [self searchContactFields:(NSArray*)[searchFields valueForKey:kW3ContactEmails] - forMVStringProperty:kABPersonEmailProperty withValue:testValue]; - } - - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactAddresses]) { - bFound = [self searchContactFields:[searchFields valueForKey:kW3ContactAddresses] - forMVDictionaryProperty:kABPersonAddressProperty withValue:testValue]; - } - - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactIms]) { - bFound = [self searchContactFields:[searchFields valueForKey:kW3ContactIms] - forMVDictionaryProperty:kABPersonInstantMessageProperty withValue:testValue]; - } - - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactOrganizations]) { - NSArray* fields = [searchFields valueForKey:kW3ContactOrganizations]; - - for (NSString* testItem in fields) { - bFound = [self testStringValue:testValue forW3CProperty:testItem]; - if (bFound == YES) { - break; - } - } - } - if (!bFound && [searchFields valueForKey:kW3ContactNote]) { - bFound = [self testStringValue:testValue forW3CProperty:kW3ContactNote]; - } - - // if searching for a date field is requested, get the date field as a localized string then look for match against testValue in date string - // searching for photos is not supported - if (!bFound && [searchFields valueForKey:kW3ContactBirthday]) { - bFound = [self testDateValue:testValue forW3CProperty:kW3ContactBirthday]; - } - if (!bFound && [searchFields valueForKeyIsArray:kW3ContactUrls]) { - bFound = [self searchContactFields:(NSArray*)[searchFields valueForKey:kW3ContactUrls] - forMVStringProperty:kABPersonURLProperty withValue:testValue]; - } - - return bFound; -} - -/* - * Test for the existence of a given string within the value of a ABPersonRecord string property based on the W3c property name. - * - * IN: - * NSString* testValue - the value to find - search is case insensitive - * NSString* property - the W3c property string - * OUT: - * BOOL YES if the given string was found within the property value - * NO if the testValue was not found, W3C property string was invalid or the AddressBook property was not a string - */ -- (BOOL)testStringValue:(NSString*)testValue forW3CProperty:(NSString*)property -{ - BOOL bFound = NO; - - if ([[CDVContact defaultW3CtoAB] valueForKeyIsNumber:property]) { - ABPropertyID propId = [[[CDVContact defaultW3CtoAB] objectForKey:property] intValue]; - if (ABPersonGetTypeOfProperty(propId) == kABStringPropertyType) { - NSString* propValue = (__bridge_transfer NSString*)ABRecordCopyValue(self.record, propId); - if ((propValue != nil) && ([propValue length] > 0)) { - NSPredicate* containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testValue]; - bFound = [containPred evaluateWithObject:propValue]; - // NSRange range = [propValue rangeOfString:testValue options: NSCaseInsensitiveSearch]; - // bFound = (range.location != NSNotFound); - } - } - } - return bFound; -} - -/* - * Test for the existence of a given Date string within the value of a ABPersonRecord datetime property based on the W3c property name. - * - * IN: - * NSString* testValue - the value to find - search is case insensitive - * NSString* property - the W3c property string - * OUT: - * BOOL YES if the given string was found within the localized date string value - * NO if the testValue was not found, W3C property string was invalid or the AddressBook property was not a DateTime - */ -- (BOOL)testDateValue:(NSString*)testValue forW3CProperty:(NSString*)property -{ - BOOL bFound = NO; - - if ([[CDVContact defaultW3CtoAB] valueForKeyIsNumber:property]) { - ABPropertyID propId = [[[CDVContact defaultW3CtoAB] objectForKey:property] intValue]; - if (ABPersonGetTypeOfProperty(propId) == kABDateTimePropertyType) { - NSDate* date = (__bridge_transfer NSDate*)ABRecordCopyValue(self.record, propId); - if (date != nil) { - NSString* dateString = [date descriptionWithLocale:[NSLocale currentLocale]]; - NSPredicate* containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testValue]; - bFound = [containPred evaluateWithObject:dateString]; - } - } - } - return bFound; -} - -/* - * Search the specified fields within an AddressBook multivalue string property for the specified test value. - * Used for phoneNumbers, emails and urls. - * IN: - * NSArray* fields - the fields to search for within the multistring property (value and/or type) - * ABPropertyID - the property to search - * NSString* testValue - the value to search for. Will convert between W3C types and AB types. Will only - * search for types if the testValue is a valid ContactField type. - * OUT: - * YES if the test value was found in one of the specified fields - * NO if the test value was not found - */ -- (BOOL)searchContactFields:(NSArray*)fields forMVStringProperty:(ABPropertyID)propId withValue:testValue -{ - BOOL bFound = NO; - - for (NSString* type in fields) { - NSString* testString = nil; - if ([type isEqualToString:kW3ContactFieldType]) { - if ([CDVContact isValidW3ContactType:testValue]) { - // only search types if the filter string is a valid ContactField.type - testString = (NSString*)[CDVContact convertContactTypeToPropertyLabel:testValue]; - } - } else { - testString = testValue; - } - - if (testString != nil) { - bFound = [self testMultiValueStrings:testString forProperty:propId ofType:type]; - } - if (bFound == YES) { - break; - } - } - - return bFound; -} - -/* - * Searches a multiString value of the specified type for the specified test value. - * - * IN: - * NSString* testValue - the value to test for - * ABPropertyID propId - the property id of the multivalue property to search - * NSString* type - the W3C contact type to search for (value or type) - * OUT: - * YES is the test value was found - * NO if the test value was not found - */ -- (BOOL)testMultiValueStrings:(NSString*)testValue forProperty:(ABPropertyID)propId ofType:(NSString*)type -{ - BOOL bFound = NO; - - if (ABPersonGetTypeOfProperty(propId) == kABMultiStringPropertyType) { - NSArray* valueArray = nil; - if ([type isEqualToString:kW3ContactFieldType]) { - valueArray = [self labelsForProperty:propId inRecord:self.record]; - } else if ([type isEqualToString:kW3ContactFieldValue]) { - valueArray = [self valuesForProperty:propId inRecord:self.record]; - } - if (valueArray) { - NSString* valuesAsString = [valueArray componentsJoinedByString:@" "]; - NSPredicate* containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testValue]; - bFound = [containPred evaluateWithObject:valuesAsString]; - } - } - return bFound; -} - -/* - * Returns the array of values for a multivalue string property of the specified property id - */ -- (__autoreleasing NSArray*)valuesForProperty:(ABPropertyID)propId inRecord:(ABRecordRef)aRecord -{ - ABMultiValueRef multi = ABRecordCopyValue(aRecord, propId); - NSArray* values = (__bridge_transfer NSArray*)ABMultiValueCopyArrayOfAllValues(multi); - - CFRelease(multi); - return values; -} - -/* - * Returns the array of labels for a multivalue string property of the specified property id - */ -- (NSArray*)labelsForProperty:(ABPropertyID)propId inRecord:(ABRecordRef)aRecord -{ - ABMultiValueRef multi = ABRecordCopyValue(aRecord, propId); - CFIndex count = ABMultiValueGetCount(multi); - NSMutableArray* labels = [NSMutableArray arrayWithCapacity:count]; - - for (int i = 0; i < count; i++) { - NSString* label = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(multi, i); - if (label) { - [labels addObject:label]; - } - } - - CFRelease(multi); - return labels; -} - -/* search for values within MultiValue Dictionary properties Address or IM property - * IN: - * (NSArray*) fields - the array of W3C field names to search within - * (ABPropertyID) propId - the AddressBook property that returns a multivalue dictionary - * (NSString*) testValue - the string to search for within the specified fields - * - */ -- (BOOL)searchContactFields:(NSArray*)fields forMVDictionaryProperty:(ABPropertyID)propId withValue:(NSString*)testValue -{ - BOOL bFound = NO; - - NSArray* values = [self valuesForProperty:propId inRecord:self.record]; // array of dictionaries (as CFDictionaryRef) - int dictCount = [values count]; - - // for ims dictionary contains with service (w3C type) and username (W3c value) - // for addresses dictionary contains street, city, state, zip, country - for (int i = 0; i < dictCount; i++) { - CFDictionaryRef dict = (__bridge CFDictionaryRef)[values objectAtIndex:i]; - - for (NSString* member in fields) { - NSString* abKey = [[CDVContact defaultW3CtoAB] valueForKey:member]; // im and address fields are all strings - CFStringRef abValue = nil; - if (abKey) { - NSString* testString = nil; - if ([member isEqualToString:kW3ContactImType]) { - if ([CDVContact isValidW3ContactType:testValue]) { - // only search service/types if the filter string is a valid ContactField.type - testString = (NSString*)[CDVContact convertContactTypeToPropertyLabel:testValue]; - } - } else { - testString = testValue; - } - if (testString != nil) { - BOOL bExists = CFDictionaryGetValueIfPresent(dict, (__bridge const void*)abKey, (void*)&abValue); - if (bExists) { - CFRetain(abValue); - NSPredicate* containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testString]; - bFound = [containPred evaluateWithObject:(__bridge id)abValue]; - CFRelease(abValue); - } - } - } - if (bFound == YES) { - break; - } - } // end of for each member in fields - - if (bFound == YES) { - break; - } - } // end of for each dictionary - - return bFound; -} - -@end diff --git a/CordovaLib/Classes/CDVContacts.h b/CordovaLib/Classes/CDVContacts.h deleted file mode 100755 index 0342f5b..0000000 --- a/CordovaLib/Classes/CDVContacts.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - 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 -#import -#import -#import "CDVPlugin.h" -#import "CDVContact.h" - -@interface CDVContacts : CDVPlugin -{ - ABAddressBookRef addressBook; -} - -/* - * newContact - create a new contact via the GUI - * - * arguments: - * 1: successCallback: this is the javascript function that will be called with the newly created contactId - */ -- (void)newContact:(CDVInvokedUrlCommand*)command; - -/* - * displayContact - IN PROGRESS - * - * arguments: - * 1: recordID of the contact to display in the iPhone contact display - * 2: successCallback - currently not used - * 3: error callback - * options: - * allowsEditing: set to true to allow the user to edit the contact - currently not supported - */ -- (void)displayContact:(CDVInvokedUrlCommand*)command; - -/* - * chooseContact - * - * arguments: - * 1: this is the javascript function that will be called with the contact data as a JSON object (as the first param) - * options: - * allowsEditing: set to true to not choose the contact, but to edit it in the iPhone contact editor - */ -- (void)chooseContact:(CDVInvokedUrlCommand*)command; - -- (void)newPersonViewController:(ABNewPersonViewController*)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person; -- (BOOL)personViewController:(ABPersonViewController*)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person - property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue; - -/* - * search - searches for contacts. Only person records are currently supported. - * - * arguments: - * 1: successcallback - this is the javascript function that will be called with the array of found contacts - * 2: errorCallback - optional javascript function to be called in the event of an error with an error code. - * options: dictionary containing ContactFields and ContactFindOptions - * fields - ContactFields array - * findOptions - ContactFindOptions object as dictionary - * - */ -- (void)search:(CDVInvokedUrlCommand*)command; - -/* - * save - saves a new contact or updates and existing contact - * - * arguments: - * 1: success callback - this is the javascript function that will be called with the JSON representation of the saved contact - * search calls a fixed navigator.service.contacts._findCallback which then calls the success callback stored before making the call into obj-c - */ -- (void)save:(CDVInvokedUrlCommand*)command; - -/* - * remove - removes a contact from the address book - * - * arguments: - * 1: 1: successcallback - this is the javascript function that will be called with a (now) empty contact object - * - * options: dictionary containing Contact object to remove - * contact - Contact object as dictionary - */ -- (void)remove:(CDVInvokedUrlCommand*)command; - -// - (void) dealloc; - -@end - -@interface CDVContactsPicker : ABPeoplePickerNavigationController -{ - BOOL allowsEditing; - NSString* callbackId; - NSDictionary* options; - NSDictionary* pickedContactDictionary; -} - -@property BOOL allowsEditing; -@property (copy) NSString* callbackId; -@property (nonatomic, strong) NSDictionary* options; -@property (nonatomic, strong) NSDictionary* pickedContactDictionary; - -@end - -@interface CDVNewContactsController : ABNewPersonViewController -{ - NSString* callbackId; -} -@property (copy) NSString* callbackId; -@end - -/* ABPersonViewController does not have any UI to dismiss. Adding navigationItems to it does not work properly, the navigationItems are lost when the app goes into the background. - The solution was to create an empty NavController in front of the ABPersonViewController. This - causes the ABPersonViewController to have a back button. By subclassing the ABPersonViewController, - we can override viewWillDisappear and take down the entire NavigationController at that time. - */ -@interface CDVDisplayContactViewController : ABPersonViewController -{} -@property (nonatomic, strong) CDVPlugin* contactsPlugin; - -@end -@interface CDVAddressBookAccessError : NSObject -{} -@property (assign) CDVContactError errorCode; -- (CDVAddressBookAccessError*)initWithCode:(CDVContactError)code; -@end - -typedef void (^ CDVAddressBookWorkerBlock)( - ABAddressBookRef addressBook, - CDVAddressBookAccessError* error - ); -@interface CDVAddressBookHelper : NSObject -{} - -- (void)createAddressBook:(CDVAddressBookWorkerBlock)workerBlock; -@end diff --git a/CordovaLib/Classes/CDVContacts.m b/CordovaLib/Classes/CDVContacts.m deleted file mode 100755 index 6cb9f08..0000000 --- a/CordovaLib/Classes/CDVContacts.m +++ /dev/null @@ -1,593 +0,0 @@ -/* - 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 "CDVContacts.h" -#import -#import "NSArray+Comparisons.h" -#import "NSDictionary+Extensions.h" -#import "CDVNotification.h" - -@implementation CDVContactsPicker - -@synthesize allowsEditing; -@synthesize callbackId; -@synthesize options; -@synthesize pickedContactDictionary; - -@end -@implementation CDVNewContactsController - -@synthesize callbackId; - -@end - -@implementation CDVContacts - -// no longer used since code gets AddressBook for each operation. -// If address book changes during save or remove operation, may get error but not much we can do about it -// If address book changes during UI creation, display or edit, we don't control any saves so no need for callback - -/*void addressBookChanged(ABAddressBookRef addressBook, CFDictionaryRef info, void* context) -{ - // note that this function is only called when another AddressBook instance modifies - // the address book, not the current one. For example, through an OTA MobileMe sync - Contacts* contacts = (Contacts*)context; - [contacts addressBookDirty]; -}*/ - -- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView -{ - self = (CDVContacts*)[super initWithWebView:(UIWebView*)theWebView]; - - /*if (self) { - addressBook = ABAddressBookCreate(); - ABAddressBookRegisterExternalChangeCallback(addressBook, addressBookChanged, self); - }*/ - - return self; -} - -// overridden to clean up Contact statics -- (void)onAppTerminate -{ - // NSLog(@"Contacts::onAppTerminate"); -} - -// iPhone only method to create a new contact through the GUI -- (void)newContact:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - - CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles - - [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errCode) { - if (addrBook == NULL) { - // permission was denied or other error just return (no error callback) - return; - } - CDVNewContactsController* npController = [[CDVNewContactsController alloc] init]; - npController.addressBook = addrBook; // a CF retaining assign - CFRelease(addrBook); - - npController.newPersonViewDelegate = self; - npController.callbackId = callbackId; - - UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:npController]; - - if ([weakSelf.viewController respondsToSelector:@selector(presentViewController:::)]) { - [weakSelf.viewController presentViewController:navController animated:YES completion:nil]; - } else { - [weakSelf.viewController presentModalViewController:navController animated:YES]; - } - }]; -} - -- (void)newPersonViewController:(ABNewPersonViewController*)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person -{ - ABRecordID recordId = kABRecordInvalidID; - CDVNewContactsController* newCP = (CDVNewContactsController*)newPersonViewController; - NSString* callbackId = newCP.callbackId; - - if (person != NULL) { - // return the contact id - recordId = ABRecordGetRecordID(person); - } - - if ([newPersonViewController respondsToSelector:@selector(presentingViewController)]) { - [[newPersonViewController presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[newPersonViewController parentViewController] dismissModalViewControllerAnimated:YES]; - } - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:recordId]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; -} - -- (void)displayContact:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - ABRecordID recordID = [[command.arguments objectAtIndex:0] intValue]; - NSDictionary* options = [command.arguments objectAtIndex:1 withDefault:[NSNull null]]; - bool bEdit = [options isKindOfClass:[NSNull class]] ? false : [options existsValue:@"true" forKey:@"allowsEditing"]; - - CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles - - [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errCode) { - if (addrBook == NULL) { - // permission was denied or other error - return error - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errCode ? errCode.errorCode:UNKNOWN_ERROR]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - return; - } - ABRecordRef rec = ABAddressBookGetPersonWithRecordID(addrBook, recordID); - - if (rec) { - CDVDisplayContactViewController* personController = [[CDVDisplayContactViewController alloc] init]; - personController.displayedPerson = rec; - personController.personViewDelegate = self; - personController.allowsEditing = NO; - - // create this so DisplayContactViewController will have a "back" button. - UIViewController* parentController = [[UIViewController alloc] init]; - UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:parentController]; - - [navController pushViewController:personController animated:YES]; - - if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) { - [self.viewController presentViewController:navController animated:YES completion:nil]; - } else { - [self.viewController presentModalViewController:navController animated:YES]; - } - - if (bEdit) { - // create the editing controller and push it onto the stack - ABPersonViewController* editPersonController = [[ABPersonViewController alloc] init]; - editPersonController.displayedPerson = rec; - editPersonController.personViewDelegate = self; - editPersonController.allowsEditing = YES; - [navController pushViewController:editPersonController animated:YES]; - } - } else { - // no record, return error - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:UNKNOWN_ERROR]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - CFRelease(addrBook); - }]; -} - -- (BOOL)personViewController:(ABPersonViewController*)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person - property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue -{ - return YES; -} - -- (void)chooseContact:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* options = [command.arguments objectAtIndex:0 withDefault:[NSNull null]]; - - CDVContactsPicker* pickerController = [[CDVContactsPicker alloc] init]; - - pickerController.peoplePickerDelegate = self; - pickerController.callbackId = callbackId; - pickerController.options = options; - pickerController.pickedContactDictionary = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:kABRecordInvalidID], kW3ContactId, nil]; - pickerController.allowsEditing = (BOOL)[options existsValue : @"true" forKey : @"allowsEditing"]; - - if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) { - [self.viewController presentViewController:pickerController animated:YES completion:nil]; - } else { - [self.viewController presentModalViewController:pickerController animated:YES]; - } -} - -- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker - shouldContinueAfterSelectingPerson:(ABRecordRef)person -{ - CDVContactsPicker* picker = (CDVContactsPicker*)peoplePicker; - NSNumber* pickedId = [NSNumber numberWithInt:ABRecordGetRecordID(person)]; - - if (picker.allowsEditing) { - ABPersonViewController* personController = [[ABPersonViewController alloc] init]; - personController.displayedPerson = person; - personController.personViewDelegate = self; - personController.allowsEditing = picker.allowsEditing; - // store id so can get info in peoplePickerNavigationControllerDidCancel - picker.pickedContactDictionary = [NSDictionary dictionaryWithObjectsAndKeys:pickedId, kW3ContactId, nil]; - - [peoplePicker pushViewController:personController animated:YES]; - } else { - // Retrieve and return pickedContact information - CDVContact* pickedContact = [[CDVContact alloc] initFromABRecord:(ABRecordRef)person]; - NSArray* fields = [picker.options objectForKey:@"fields"]; - NSDictionary* returnFields = [[CDVContact class] calcReturnFields:fields]; - picker.pickedContactDictionary = [pickedContact toDictionary:returnFields]; - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:picker.pickedContactDictionary]; - [self.commandDelegate sendPluginResult:result callbackId:picker.callbackId]; - - if ([picker respondsToSelector:@selector(presentingViewController)]) { - [[picker presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[picker parentViewController] dismissModalViewControllerAnimated:YES]; - } - } - return NO; -} - -- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker - shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier -{ - return YES; -} - -- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController*)peoplePicker -{ - // return contactId or invalid if none picked - CDVContactsPicker* picker = (CDVContactsPicker*)peoplePicker; - - if (picker.allowsEditing) { - // get the info after possible edit - // 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 -#endif - { - // iOS 4 & 5 - addrBook = ABAddressBookCreate(); - } - ABRecordRef person = ABAddressBookGetPersonWithRecordID(addrBook, [[picker.pickedContactDictionary objectForKey:kW3ContactId] integerValue]); - if (person) { - CDVContact* pickedContact = [[CDVContact alloc] initFromABRecord:(ABRecordRef)person]; - NSArray* fields = [picker.options objectForKey:@"fields"]; - NSDictionary* returnFields = [[CDVContact class] calcReturnFields:fields]; - picker.pickedContactDictionary = [pickedContact toDictionary:returnFields]; - } - CFRelease(addrBook); - } - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:picker.pickedContactDictionary]; - [self.commandDelegate sendPluginResult:result callbackId:picker.callbackId]; - - if ([peoplePicker respondsToSelector:@selector(presentingViewController)]) { - [[peoplePicker presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[peoplePicker parentViewController] dismissModalViewControllerAnimated:YES]; - } -} - -- (void)search:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSArray* fields = [command.arguments objectAtIndex:0]; - NSDictionary* findOptions = [command.arguments objectAtIndex:1 withDefault:[NSNull null]]; - - [self.commandDelegate runInBackground:^{ - // from Apple: Important You must ensure that an instance of ABAddressBookRef is used by only one thread. - // 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* __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 - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errCode ? errCode.errorCode:UNKNOWN_ERROR]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - return; - } - - NSArray* foundRecords = nil; - // get the findOptions values - BOOL multiple = NO; // default is false - NSString* filter = nil; - if (![findOptions isKindOfClass:[NSNull class]]) { - id value = nil; - filter = (NSString*)[findOptions objectForKey:@"filter"]; - value = [findOptions objectForKey:@"multiple"]; - if ([value isKindOfClass:[NSNumber class]]) { - // multiple is a boolean that will come through as an NSNumber - multiple = [(NSNumber*)value boolValue]; - // NSLog(@"multiple is: %d", multiple); - } - } - - NSDictionary* returnFields = [[CDVContact class] calcReturnFields:fields]; - - NSMutableArray* matches = nil; - if (!filter || [filter isEqualToString:@""]) { - // get all records - foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook); - if (foundRecords && ([foundRecords count] > 0)) { - // create Contacts and put into matches array - // doesn't make sense to ask for all records when multiple == NO but better check - int xferCount = multiple == YES ? [foundRecords count] : 1; - matches = [NSMutableArray arrayWithCapacity:xferCount]; - - for (int k = 0; k < xferCount; k++) { - CDVContact* xferContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:k]]; - [matches addObject:xferContact]; - xferContact = nil; - } - } - } else { - foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook); - matches = [NSMutableArray arrayWithCapacity:1]; - BOOL bFound = NO; - int testCount = [foundRecords count]; - - for (int j = 0; j < testCount; j++) { - CDVContact* testContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:j]]; - if (testContact) { - bFound = [testContact foundValue:filter inFields:returnFields]; - if (bFound) { - [matches addObject:testContact]; - } - testContact = nil; - } - } - } - NSMutableArray* returnContacts = [NSMutableArray arrayWithCapacity:1]; - - if ((matches != nil) && ([matches count] > 0)) { - // convert to JS Contacts format and return in callback - // - returnFields determines what properties to return - @autoreleasepool { - int count = multiple == YES ? [matches count] : 1; - - for (int i = 0; i < count; i++) { - CDVContact* newContact = [matches objectAtIndex:i]; - NSDictionary* aContact = [newContact toDictionary:returnFields]; - [returnContacts addObject:aContact]; - } - } - } - // return found contacts (array is empty if no contacts found) - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:returnContacts]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - // NSLog(@"findCallback string: %@", jsString); - - if (addrBook) { - CFRelease(addrBook); - } - }]; - }]; // end of workQueue block - - return; -} - -- (void)save:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* contactDict = [command.arguments objectAtIndex:0]; - - [self.commandDelegate runInBackground:^{ - CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles - - [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errorCode) { - CDVPluginResult* result = nil; - if (addrBook == NULL) { - // permission was denied or other error - return error - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode ? errorCode.errorCode:UNKNOWN_ERROR]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - return; - } - - bool bIsError = FALSE, bSuccess = FALSE; - BOOL bUpdate = NO; - CDVContactError errCode = UNKNOWN_ERROR; - CFErrorRef error; - NSNumber* cId = [contactDict valueForKey:kW3ContactId]; - CDVContact* aContact = nil; - ABRecordRef rec = nil; - if (cId && ![cId isKindOfClass:[NSNull class]]) { - rec = ABAddressBookGetPersonWithRecordID(addrBook, [cId intValue]); - if (rec) { - aContact = [[CDVContact alloc] initFromABRecord:rec]; - bUpdate = YES; - } - } - if (!aContact) { - aContact = [[CDVContact alloc] init]; - } - - bSuccess = [aContact setFromContactDict:contactDict asUpdate:bUpdate]; - if (bSuccess) { - if (!bUpdate) { - bSuccess = ABAddressBookAddRecord(addrBook, [aContact record], &error); - } - if (bSuccess) { - bSuccess = ABAddressBookSave(addrBook, &error); - } - if (!bSuccess) { // need to provide error codes - bIsError = TRUE; - errCode = IO_ERROR; - } else { - // give original dictionary back? If generate dictionary from saved contact, have no returnFields specified - // so would give back all fields (which W3C spec. indicates is not desired) - // for now (while testing) give back saved, full contact - NSDictionary* newContact = [aContact toDictionary:[CDVContact defaultFields]]; - // NSString* contactStr = [newContact JSONRepresentation]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newContact]; - } - } else { - bIsError = TRUE; - errCode = IO_ERROR; - } - CFRelease(addrBook); - - if (bIsError) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode]; - } - - if (result) { - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - }]; - }]; // end of queue -} - -- (void)remove:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSNumber* cId = [command.arguments objectAtIndex:0]; - - CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; - CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles - - [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errorCode) { - CDVPluginResult* result = nil; - if (addrBook == NULL) { - // permission was denied or other error - return error - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode ? errorCode.errorCode:UNKNOWN_ERROR]; - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - return; - } - - bool bIsError = FALSE, bSuccess = FALSE; - CDVContactError errCode = UNKNOWN_ERROR; - CFErrorRef error; - ABRecordRef rec = nil; - if (cId && ![cId isKindOfClass:[NSNull class]] && ([cId intValue] != kABRecordInvalidID)) { - rec = ABAddressBookGetPersonWithRecordID(addrBook, [cId intValue]); - if (rec) { - bSuccess = ABAddressBookRemoveRecord(addrBook, rec, &error); - if (!bSuccess) { - bIsError = TRUE; - errCode = IO_ERROR; - } else { - bSuccess = ABAddressBookSave(addrBook, &error); - if (!bSuccess) { - bIsError = TRUE; - errCode = IO_ERROR; - } else { - // set id to null - // [contactDict setObject:[NSNull null] forKey:kW3ContactId]; - // result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary: contactDict]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - // NSString* contactStr = [contactDict JSONRepresentation]; - } - } - } else { - // no record found return error - bIsError = TRUE; - errCode = UNKNOWN_ERROR; - } - } else { - // invalid contact id provided - bIsError = TRUE; - errCode = INVALID_ARGUMENT_ERROR; - } - - if (addrBook) { - CFRelease(addrBook); - } - if (bIsError) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode]; - } - if (result) { - [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - }]; - return; -} - -@end - -/* ABPersonViewController does not have any UI to dismiss. Adding navigationItems to it does not work properly - * The navigationItems are lost when the app goes into the background. The solution was to create an empty - * NavController in front of the ABPersonViewController. This will cause the ABPersonViewController to have a back button. By subclassing the ABPersonViewController, we can override viewDidDisappear and take down the entire NavigationController. - */ -@implementation CDVDisplayContactViewController -@synthesize contactsPlugin; - -- (void)viewWillDisappear:(BOOL)animated -{ - [super viewWillDisappear:animated]; - - if ([self respondsToSelector:@selector(presentingViewController)]) { - [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[self parentViewController] dismissModalViewControllerAnimated:YES]; - } -} - -@end -@implementation CDVAddressBookAccessError - -@synthesize errorCode; - -- (CDVAddressBookAccessError*)initWithCode:(CDVContactError)code -{ - self = [super init]; - if (self) { - self.errorCode = code; - } - return self; -} - -@end - -@implementation CDVAddressBookHelper - -/** - * NOTE: workerBlock is responsible for releasing the addressBook that is passed to it - */ -- (void)createAddressBook:(CDVAddressBookWorkerBlock)workerBlock -{ - // TODO: this probably should be reworked - seems like the workerBlock can just create and release its own AddressBook, - // and also this important warning from (http://developer.apple.com/library/ios/#documentation/ContactData/Conceptual/AddressBookProgrammingGuideforiPhone/Chapters/BasicObjects.html): - // "Important: Instances of ABAddressBookRef cannot be used by multiple threads. Each thread must make its own instance." - 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) { - // callback can occur in background, address book must be accessed on thread it was created on - dispatch_sync(dispatch_get_main_queue(), ^{ - if (error) { - workerBlock(NULL, [[CDVAddressBookAccessError alloc] initWithCode:UNKNOWN_ERROR]); - } else if (!granted) { - workerBlock(NULL, [[CDVAddressBookAccessError alloc] initWithCode:PERMISSION_DENIED_ERROR]); - } else { - // access granted - workerBlock(addressBook, [[CDVAddressBookAccessError alloc] initWithCode:UNKNOWN_ERROR]); - } - }); - }); - } else -#endif - { - // iOS 4 or 5 no checks needed - addressBook = ABAddressBookCreate(); - workerBlock(addressBook, NULL); - } -} - -@end diff --git a/CordovaLib/Classes/CDVDevice.h b/CordovaLib/Classes/CDVDevice.h deleted file mode 100755 index fd6ea12..0000000 --- a/CordovaLib/Classes/CDVDevice.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - 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 -#import "CDVPlugin.h" - -@interface CDVDevice : CDVPlugin -{} - -+ (NSString*)cordovaVersion; - -- (void)getDeviceInfo:(CDVInvokedUrlCommand*)command; - -@end diff --git a/CordovaLib/Classes/CDVDevice.m b/CordovaLib/Classes/CDVDevice.m deleted file mode 100755 index cc7ad89..0000000 --- a/CordovaLib/Classes/CDVDevice.m +++ /dev/null @@ -1,90 +0,0 @@ -/* - 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. - */ - -#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 - -@implementation CDVDevice - -- (void)getDeviceInfo:(CDVInvokedUrlCommand*)command -{ - NSDictionary* deviceProperties = [self deviceProperties]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:deviceProperties]; - - /* Settings.plist - * Read the optional Settings.plist file and push these user-defined settings down into the web application. - * This can be useful for supplying build-time configuration variables down to the app to change its behavior, - * such as specifying Full / Lite version, or localization (English vs German, for instance). - */ - // TODO: turn this into an iOS only plugin - NSDictionary* temp = [CDVViewController getBundlePlist:@"Settings"]; - - if ([temp respondsToSelector:@selector(JSONString)]) { - NSLog(@"Deprecation warning: window.Setting will be removed Aug 2013. Refer to https://issues.apache.org/jira/browse/CB-2433"); - NSString* js = [NSString stringWithFormat:@"window.Settings = %@;", [temp JSONString]]; - [self.commandDelegate evalJs:js]; - } - - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -- (NSDictionary*)deviceProperties -{ - UIDevice* device = [UIDevice currentDevice]; - NSMutableDictionary* devProps = [NSMutableDictionary dictionaryWithCapacity:4]; - - [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 model] forKey:@"name"]; - [devProps setObject:[[self class] cordovaVersion] forKey:@"cordova"]; - - NSDictionary* devReturn = [NSDictionary dictionaryWithDictionary:devProps]; - return devReturn; -} - -+ (NSString*)cordovaVersion -{ - return CDV_VERSION; -} - -@end diff --git a/CordovaLib/Classes/CDVEcho.h b/CordovaLib/Classes/CDVEcho.h deleted file mode 100755 index 76a4a96..0000000 --- a/CordovaLib/Classes/CDVEcho.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - 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" - -@interface CDVEcho : CDVPlugin -@end diff --git a/CordovaLib/Classes/CDVEcho.m b/CordovaLib/Classes/CDVEcho.m deleted file mode 100755 index c74990d..0000000 --- a/CordovaLib/Classes/CDVEcho.m +++ /dev/null @@ -1,61 +0,0 @@ -/* - 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 "CDVEcho.h" -#import "CDV.h" - -@implementation CDVEcho - -- (void)echo:(CDVInvokedUrlCommand*)command -{ - id message = [command.arguments objectAtIndex:0]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:message]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -- (void)echoAsyncHelper:(NSArray*)args -{ - [self.commandDelegate sendPluginResult:[args objectAtIndex:0] callbackId:[args objectAtIndex:1]]; -} - -- (void)echoAsync:(CDVInvokedUrlCommand*)command -{ - id message = [command.arguments objectAtIndex:0]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:message]; - - [self performSelector:@selector(echoAsyncHelper:) withObject:[NSArray arrayWithObjects:pluginResult, command.callbackId, nil] afterDelay:0]; -} - -- (void)echoArrayBuffer:(CDVInvokedUrlCommand*)command -{ - id message = [command.arguments objectAtIndex:0]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArrayBuffer:message]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -- (void)echoMultiPart:(CDVInvokedUrlCommand*)command -{ - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsMultipart:command.arguments]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -@end diff --git a/CordovaLib/Classes/CDVExif.h b/CordovaLib/Classes/CDVExif.h deleted file mode 100755 index 3e8adbd..0000000 --- a/CordovaLib/Classes/CDVExif.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - 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. - */ - -#ifndef CordovaLib_ExifData_h -#define CordovaLib_ExifData_h - -// exif data types -typedef enum exifDataTypes { - EDT_UBYTE = 1, // 8 bit unsigned integer - EDT_ASCII_STRING, // 8 bits containing 7 bit ASCII code, null terminated - EDT_USHORT, // 16 bit unsigned integer - EDT_ULONG, // 32 bit unsigned integer - EDT_URATIONAL, // 2 longs, first is numerator and second is denominator - EDT_SBYTE, - EDT_UNDEFINED, // 8 bits - EDT_SSHORT, - EDT_SLONG, // 32bit signed integer (2's complement) - EDT_SRATIONAL, // 2 SLONGS, first long is numerator, second is denominator - EDT_SINGLEFLOAT, - EDT_DOUBLEFLOAT -} ExifDataTypes; - -// maps integer code for exif data types to width in bytes -static const int DataTypeToWidth[] = {1,1,2,4,8,1,1,2,4,8,4,8}; - -static const int RECURSE_HORIZON = 8; -#endif diff --git a/CordovaLib/Classes/CDVFile.h b/CordovaLib/Classes/CDVFile.h deleted file mode 100755 index eaf8cbe..0000000 --- a/CordovaLib/Classes/CDVFile.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - 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 -#import "CDVPlugin.h" - -enum CDVFileError { - NO_ERROR = 0, - NOT_FOUND_ERR = 1, - SECURITY_ERR = 2, - ABORT_ERR = 3, - NOT_READABLE_ERR = 4, - ENCODING_ERR = 5, - NO_MODIFICATION_ALLOWED_ERR = 6, - INVALID_STATE_ERR = 7, - SYNTAX_ERR = 8, - INVALID_MODIFICATION_ERR = 9, - QUOTA_EXCEEDED_ERR = 10, - TYPE_MISMATCH_ERR = 11, - PATH_EXISTS_ERR = 12 -}; -typedef int CDVFileError; - -enum CDVFileSystemType { - TEMPORARY = 0, - PERSISTENT = 1 -}; -typedef int CDVFileSystemType; - -extern NSString* const kCDVAssetsLibraryPrefix; - -@interface CDVFile : CDVPlugin { - NSString* appDocsPath; - NSString* appLibraryPath; - NSString* appTempPath; - NSString* persistentPath; - NSString* temporaryPath; - - BOOL userHasAllowed; -} -- (NSNumber*)checkFreeDiskSpace:(NSString*)appPath; -- (NSString*)getAppPath:(NSString*)pathFragment; -// -(NSString*) getFullPath: (NSString*)pathFragment; -- (void)requestFileSystem:(CDVInvokedUrlCommand*)command; -- (NSDictionary*)getDirectoryEntry:(NSString*)fullPath isDirectory:(BOOL)isDir; -- (void)resolveLocalFileSystemURI:(CDVInvokedUrlCommand*)command; -- (void)getDirectory:(CDVInvokedUrlCommand*)command; -- (void)getFile:(CDVInvokedUrlCommand*)command; -- (void)getParent:(CDVInvokedUrlCommand*)command; -- (void)getMetadata:(CDVInvokedUrlCommand*)command; -- (void)removeRecursively:(CDVInvokedUrlCommand*)command; -- (void)remove:(CDVInvokedUrlCommand*)command; -- (CDVPluginResult*)doRemove:(NSString*)fullPath; -- (void)copyTo:(CDVInvokedUrlCommand*)command; -- (void)moveTo:(CDVInvokedUrlCommand*)command; -- (BOOL)canCopyMoveSrc:(NSString*)src ToDestination:(NSString*)dest; -- (void)doCopyMove:(CDVInvokedUrlCommand*)command isCopy:(BOOL)bCopy; -// - (void) toURI:(CDVInvokedUrlCommand*)command; -- (void)getFileMetadata:(CDVInvokedUrlCommand*)command; -- (void)readEntries:(CDVInvokedUrlCommand*)command; - -- (void)readAsText:(CDVInvokedUrlCommand*)command; -- (void)readAsDataURL:(CDVInvokedUrlCommand*)command; -- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command; -- (NSString*)getMimeTypeFromPath:(NSString*)fullPath; -- (void)write:(CDVInvokedUrlCommand*)command; -- (void)testFileExists:(CDVInvokedUrlCommand*)command; -- (void)testDirectoryExists:(CDVInvokedUrlCommand*)command; -// - (void) createDirectory:(CDVInvokedUrlCommand*)command; -// - (void) deleteDirectory:(CDVInvokedUrlCommand*)command; -// - (void) deleteFile:(CDVInvokedUrlCommand*)command; -- (void)getFreeDiskSpace:(CDVInvokedUrlCommand*)command; -- (void)truncate:(CDVInvokedUrlCommand*)command; - -// - (BOOL) fileExists:(NSString*)fileName; -// - (BOOL) directoryExists:(NSString*)dirName; -- (void)writeToFile:(NSString*)fileName withData:(NSString*)data append:(BOOL)shouldAppend callback:(NSString*)callbackId; -- (unsigned long long)truncateFile:(NSString*)filePath atPosition:(unsigned long long)pos; - -@property (nonatomic, strong) NSString* appDocsPath; -@property (nonatomic, strong) NSString* appLibraryPath; -@property (nonatomic, strong) NSString* appTempPath; -@property (nonatomic, strong) NSString* persistentPath; -@property (nonatomic, strong) NSString* temporaryPath; -@property BOOL userHasAllowed; - -@end - -#define kW3FileTemporary @"temporary" -#define kW3FilePersistent @"persistent" diff --git a/CordovaLib/Classes/CDVFile.m b/CordovaLib/Classes/CDVFile.m deleted file mode 100755 index 10908ce..0000000 --- a/CordovaLib/Classes/CDVFile.m +++ /dev/null @@ -1,1414 +0,0 @@ -/* - 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 "CDVFile.h" -#import "NSArray+Comparisons.h" -#import "NSDictionary+Extensions.h" -#import "CDVJSON.h" -#import "NSData+Base64.h" -#import -#import -#import -#import -#import "CDVAvailability.h" -#import "sys/xattr.h" - -extern NSString * const NSURLIsExcludedFromBackupKey __attribute__((weak_import)); - -#ifndef __IPHONE_5_1 - NSString* const NSURLIsExcludedFromBackupKey = @"NSURLIsExcludedFromBackupKey"; -#endif - -NSString* const kCDVAssetsLibraryPrefix = @"assets-library://"; - -@implementation CDVFile - -@synthesize appDocsPath, appLibraryPath, appTempPath, persistentPath, temporaryPath, userHasAllowed; - -- (id)initWithWebView:(UIWebView*)theWebView -{ - self = (CDVFile*)[super initWithWebView:theWebView]; - if (self) { - // get the documents directory path - NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - self.appDocsPath = [paths objectAtIndex:0]; - - paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); - self.appLibraryPath = [paths objectAtIndex:0]; - - self.appTempPath = [NSTemporaryDirectory()stringByStandardizingPath]; // remove trailing slash from NSTemporaryDirectory() - - self.persistentPath = [NSString stringWithFormat:@"/%@", [self.appDocsPath lastPathComponent]]; - self.temporaryPath = [NSString stringWithFormat:@"/%@", [self.appTempPath lastPathComponent]]; - // NSLog(@"docs: %@ - temp: %@", self.appDocsPath, self.appTempPath); - } - - return self; -} - -- (NSNumber*)checkFreeDiskSpace:(NSString*)appPath -{ - NSFileManager* fMgr = [[NSFileManager alloc] init]; - - NSError* __autoreleasing pError = nil; - - NSDictionary* pDict = [fMgr attributesOfFileSystemForPath:appPath error:&pError]; - NSNumber* pNumAvail = (NSNumber*)[pDict objectForKey:NSFileSystemFreeSize]; - - return pNumAvail; -} - -// figure out if the pathFragment represents a persistent of temporary directory and return the full application path. -// returns nil if path is not persistent or temporary -- (NSString*)getAppPath:(NSString*)pathFragment -{ - NSString* appPath = nil; - NSRange rangeP = [pathFragment rangeOfString:self.persistentPath]; - NSRange rangeT = [pathFragment rangeOfString:self.temporaryPath]; - - if ((rangeP.location != NSNotFound) && (rangeT.location != NSNotFound)) { - // we found both in the path, return whichever one is first - if (rangeP.length < rangeT.length) { - appPath = self.appDocsPath; - } else { - appPath = self.appTempPath; - } - } else if (rangeP.location != NSNotFound) { - appPath = self.appDocsPath; - } else if (rangeT.location != NSNotFound) { - appPath = self.appTempPath; - } - return appPath; -} - -/* get the full path to this resource - * IN - * NSString* pathFragment - full Path from File or Entry object (includes system path info) - * OUT - * NSString* fullPath - full iOS path to this resource, nil if not found - */ - -/* Was here in order to NOT have to return full path, but W3C synchronous DirectoryEntry.toURI() killed that idea since I can't call into iOS to - * resolve full URI. Leaving this code here in case W3C spec changes. --(NSString*) getFullPath: (NSString*)pathFragment -{ - return pathFragment; - NSString* fullPath = nil; - NSString *appPath = [ self getAppPath: pathFragment]; - if (appPath){ - - // remove last component from appPath - NSRange range = [appPath rangeOfString:@"/" options: NSBackwardsSearch]; - NSString* newPath = [appPath substringToIndex:range.location]; - // add pathFragment to get test Path - fullPath = [newPath stringByAppendingPathComponent:pathFragment]; - } - return fullPath; -} */ - -/* Request the File System info - * - * IN: - * arguments[0] - type (number as string) - * TEMPORARY = 0, PERSISTENT = 1; - * arguments[1] - size - * - * OUT: - * Dictionary representing FileSystem object - * name - the human readable directory name - * root = DirectoryEntry object - * bool isDirectory - * bool isFile - * string name - * string fullPath - * fileSystem = FileSystem object - !! ignored because creates circular reference !! - */ - -- (void)requestFileSystem:(CDVInvokedUrlCommand*)command -{ - NSArray* arguments = command.arguments; - - // arguments - NSString* strType = [arguments objectAtIndex:0]; - unsigned long long size = [[arguments objectAtIndex:1] longLongValue]; - - int type = [strType intValue]; - CDVPluginResult* result = nil; - - if (type > 1) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:NOT_FOUND_ERR]; - NSLog(@"iOS only supports TEMPORARY and PERSISTENT file systems"); - } else { - // NSString* fullPath = [NSString stringWithFormat:@"/%@", (type == 0 ? [self.appTempPath lastPathComponent] : [self.appDocsPath lastPathComponent])]; - NSString* fullPath = (type == 0 ? self.appTempPath : self.appDocsPath); - // check for avail space for size request - NSNumber* pNumAvail = [self checkFreeDiskSpace:fullPath]; - // NSLog(@"Free space: %@", [NSString stringWithFormat:@"%qu", [ pNumAvail unsignedLongLongValue ]]); - if (pNumAvail && ([pNumAvail unsignedLongLongValue] < size)) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:QUOTA_EXCEEDED_ERR]; - } else { - NSMutableDictionary* fileSystem = [NSMutableDictionary dictionaryWithCapacity:2]; - [fileSystem setObject:(type == TEMPORARY ? kW3FileTemporary : kW3FilePersistent) forKey:@"name"]; - NSDictionary* dirEntry = [self getDirectoryEntry:fullPath isDirectory:YES]; - [fileSystem setObject:dirEntry forKey:@"root"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem]; - } - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* Creates a dictionary representing an Entry Object - * - * IN: - * NSString* fullPath of the entry - * FileSystem type - * BOOL isDirectory - YES if this is a directory, NO if is a file - * OUT: - * NSDictionary* - Entry object - * bool as NSNumber isDirectory - * bool as NSNumber isFile - * NSString* name - last part of path - * NSString* fullPath - * fileSystem = FileSystem object - !! ignored because creates circular reference FileSystem contains DirectoryEntry which contains FileSystem.....!! - */ -- (NSDictionary*)getDirectoryEntry:(NSString*)fullPath isDirectory:(BOOL)isDir -{ - NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:4]; - NSString* lastPart = [fullPath lastPathComponent]; - - [dirEntry setObject:[NSNumber numberWithBool:!isDir] forKey:@"isFile"]; - [dirEntry setObject:[NSNumber numberWithBool:isDir] forKey:@"isDirectory"]; - // NSURL* fileUrl = [NSURL fileURLWithPath:fullPath]; - // [dirEntry setObject: [fileUrl absoluteString] forKey: @"fullPath"]; - [dirEntry setObject:fullPath forKey:@"fullPath"]; - [dirEntry setObject:lastPart forKey:@"name"]; - - return dirEntry; -} - -/* - * Given a URI determine the File System information associated with it and return an appropriate W3C entry object - * IN - * NSString* fileURI - currently requires full file URI - * OUT - * Entry object - * bool isDirectory - * bool isFile - * string name - * string fullPath - * fileSystem = FileSystem object - !! ignored because creates circular reference FileSystem contains DirectoryEntry which contains FileSystem.....!! - */ -- (void)resolveLocalFileSystemURI:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* inputUri = [command.arguments objectAtIndex:0]; - - // don't know if string is encoded or not so unescape - NSString* cleanUri = [inputUri stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - // now escape in order to create URL - NSString* strUri = [cleanUri stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - NSURL* testUri = [NSURL URLWithString:strUri]; - CDVPluginResult* result = nil; - - if (!testUri) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR]; - } else if ([testUri isFileURL]) { - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - NSString* path = [testUri path]; - // NSLog(@"url path: %@", path); - BOOL isDir = NO; - // see if exists and is file or dir - BOOL bExists = [fileMgr fileExistsAtPath:path isDirectory:&isDir]; - if (bExists) { - // see if it contains docs path - NSRange range = [path rangeOfString:self.appDocsPath]; - NSString* foundFullPath = nil; - // there's probably an api or easier way to figure out the path type but I can't find it! - if ((range.location != NSNotFound) && (range.length == [self.appDocsPath length])) { - foundFullPath = self.appDocsPath; - } else { - // see if it contains the temp path - range = [path rangeOfString:self.appTempPath]; - if ((range.location != NSNotFound) && (range.length == [self.appTempPath length])) { - foundFullPath = self.appTempPath; - } - } - if (foundFullPath == nil) { - // error SECURITY_ERR - not one of the two paths types supported - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:SECURITY_ERR]; - } else { - NSDictionary* fileSystem = [self getDirectoryEntry:path isDirectory:isDir]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem]; - } - } else { - // return NOT_FOUND_ERR - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - } - } else if ([strUri hasPrefix:@"assets-library://"]) { - NSDictionary* fileSystem = [self getDirectoryEntry:strUri isDirectory:NO]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR]; - } - - if (result != nil) { - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } -} - -/* Part of DirectoryEntry interface, creates or returns the specified directory - * IN: - * NSString* fullPath - full path for this directory - * NSString* path - directory to be created/returned; may be full path or relative path - * NSDictionary* - Flags object - * boolean as NSNumber create - - * if create is true and directory does not exist, create dir and return directory entry - * if create is true and exclusive is true and directory does exist, return error - * if create is false and directory does not exist, return error - * if create is false and the path represents a file, return error - * boolean as NSNumber exclusive - used in conjunction with create - * if exclusive is true and create is true - specifies failure if directory already exists - * - * - */ -- (void)getDirectory:(CDVInvokedUrlCommand*)command -{ - NSMutableArray* arguments = [NSMutableArray arrayWithArray:command.arguments]; - NSMutableDictionary* options = nil; - - if ([arguments count] >= 3) { - options = [arguments objectAtIndex:2 withDefault:nil]; - } - // add getDir to options and call getFile() - if (options != nil) { - options = [NSMutableDictionary dictionaryWithDictionary:options]; - } else { - options = [NSMutableDictionary dictionaryWithCapacity:1]; - } - [options setObject:[NSNumber numberWithInt:1] forKey:@"getDir"]; - if ([arguments count] >= 3) { - [arguments replaceObjectAtIndex:2 withObject:options]; - } else { - [arguments addObject:options]; - } - CDVInvokedUrlCommand* subCommand = - [[CDVInvokedUrlCommand alloc] initWithArguments:arguments - callbackId:command.callbackId - className:command.className - methodName:command.methodName]; - - [self getFile:subCommand]; -} - -/* Part of DirectoryEntry interface, creates or returns the specified file - * IN: - * NSString* fullPath - full path for this file - * NSString* path - file to be created/returned; may be full path or relative path - * NSDictionary* - Flags object - * boolean as NSNumber create - - * if create is true and file does not exist, create file and return File entry - * if create is true and exclusive is true and file does exist, return error - * if create is false and file does not exist, return error - * if create is false and the path represents a directory, return error - * boolean as NSNumber exclusive - used in conjunction with create - * if exclusive is true and create is true - specifies failure if file already exists - * - * - */ -- (void)getFile:(CDVInvokedUrlCommand*)command -{ - // arguments are URL encoded - NSString* fullPath = [command.arguments objectAtIndex:0]; - NSString* requestedPath = [command.arguments objectAtIndex:1]; - NSDictionary* options = [command.arguments objectAtIndex:2 withDefault:nil]; - - // return unsupported result for assets-library URLs - if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"getFile not supported for assets-library URLs."]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - CDVPluginResult* result = nil; - BOOL bDirRequest = NO; - BOOL create = NO; - BOOL exclusive = NO; - int errorCode = 0; // !!! risky - no error code currently defined for 0 - - if ([options valueForKeyIsNumber:@"create"]) { - create = [(NSNumber*)[options valueForKey:@"create"] boolValue]; - } - if ([options valueForKeyIsNumber:@"exclusive"]) { - exclusive = [(NSNumber*)[options valueForKey:@"exclusive"] boolValue]; - } - - if ([options valueForKeyIsNumber:@"getDir"]) { - // this will not exist for calls directly to getFile but will have been set by getDirectory before calling this method - bDirRequest = [(NSNumber*)[options valueForKey:@"getDir"] boolValue]; - } - // see if the requested path has invalid characters - should we be checking for more than just ":"? - if ([requestedPath rangeOfString:@":"].location != NSNotFound) { - errorCode = ENCODING_ERR; - } else { - // was full or relative path provided? - NSRange range = [requestedPath rangeOfString:fullPath]; - BOOL bIsFullPath = range.location != NSNotFound; - - NSString* reqFullPath = nil; - - if (!bIsFullPath) { - reqFullPath = [fullPath stringByAppendingPathComponent:requestedPath]; - } else { - reqFullPath = requestedPath; - } - - // NSLog(@"reqFullPath = %@", reqFullPath); - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - BOOL bIsDir; - BOOL bExists = [fileMgr fileExistsAtPath:reqFullPath isDirectory:&bIsDir]; - if (bExists && (create == NO) && (bIsDir == !bDirRequest)) { - // path exists and is of requested type - return TYPE_MISMATCH_ERR - errorCode = TYPE_MISMATCH_ERR; - } else if (!bExists && (create == NO)) { - // path does not exist and create is false - return NOT_FOUND_ERR - errorCode = NOT_FOUND_ERR; - } else if (bExists && (create == YES) && (exclusive == YES)) { - // file/dir already exists and exclusive and create are both true - return PATH_EXISTS_ERR - errorCode = PATH_EXISTS_ERR; - } else { - // if bExists and create == YES - just return data - // if bExists and create == NO - just return data - // if !bExists and create == YES - create and return data - BOOL bSuccess = YES; - NSError __autoreleasing* pError = nil; - if (!bExists && (create == YES)) { - if (bDirRequest) { - // create the dir - bSuccess = [fileMgr createDirectoryAtPath:reqFullPath withIntermediateDirectories:NO attributes:nil error:&pError]; - } else { - // create the empty file - bSuccess = [fileMgr createFileAtPath:reqFullPath contents:nil attributes:nil]; - } - } - if (!bSuccess) { - errorCode = ABORT_ERR; - if (pError) { - NSLog(@"error creating directory: %@", [pError localizedDescription]); - } - } else { - // NSLog(@"newly created file/dir (%@) exists: %d", reqFullPath, [fileMgr fileExistsAtPath:reqFullPath]); - // file existed or was created - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getDirectoryEntry:reqFullPath isDirectory:bDirRequest]]; - } - } // are all possible conditions met? - } - - if (errorCode > 0) { - // create error callback - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* - * Look up the parent Entry containing this Entry. - * If this Entry is the root of its filesystem, its parent is itself. - * IN: - * NSArray* arguments - * 0 - NSString* fullPath - * NSMutableDictionary* options - * empty - */ -- (void)getParent:(CDVInvokedUrlCommand*)command -{ - // arguments are URL encoded - NSString* fullPath = [command.arguments objectAtIndex:0]; - - // we don't (yet?) support getting the parent of an asset - if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_READABLE_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - CDVPluginResult* result = nil; - NSString* newPath = nil; - - if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString:self.appTempPath]) { - // return self - newPath = fullPath; - } else { - // since this call is made from an existing Entry object - the parent should already exist so no additional error checking - // remove last component and return Entry - NSRange range = [fullPath rangeOfString:@"/" options:NSBackwardsSearch]; - newPath = [fullPath substringToIndex:range.location]; - } - - if (newPath) { - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - BOOL bIsDir; - BOOL bExists = [fileMgr fileExistsAtPath:newPath isDirectory:&bIsDir]; - if (bExists) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getDirectoryEntry:newPath isDirectory:bIsDir]]; - } - } - if (!result) { - // invalid path or file does not exist - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* - * get MetaData of entry - * Currently MetaData only includes modificationTime. - */ -- (void)getMetadata:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* argPath = [command.arguments objectAtIndex:0]; - __block CDVPluginResult* result = nil; - - if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) { - // In this case, we need to use an asynchronous method to retrieve the file. - // Because of this, we can't just assign to `result` and send it at the end of the method. - // Instead, we return after calling the asynchronous method and send `result` in each of the blocks. - ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) { - if (asset) { - // We have the asset! Retrieve the metadata and send it off. - NSDate* date = [asset valueForProperty:ALAssetPropertyDate]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:[date timeIntervalSince1970] * 1000]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } else { - // We couldn't find the asset. Send the appropriate error. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } - }; - // TODO(maxw): Consider making this a class variable since it's the same every time. - ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) { - // Retrieving the asset failed for some reason. Send the appropriate error. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }; - - ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; - [assetsLibrary assetForURL:[NSURL URLWithString:argPath] resultBlock:resultBlock failureBlock:failureBlock]; - return; - } - - NSString* testPath = argPath; // [self getFullPath: argPath]; - - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - NSError* __autoreleasing error = nil; - - NSDictionary* fileAttribs = [fileMgr attributesOfItemAtPath:testPath error:&error]; - - if (fileAttribs) { - NSDate* modDate = [fileAttribs fileModificationDate]; - if (modDate) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:[modDate timeIntervalSince1970] * 1000]; - } - } else { - // didn't get fileAttribs - CDVFileError errorCode = ABORT_ERR; - NSLog(@"error getting metadata: %@", [error localizedDescription]); - if ([error code] == NSFileNoSuchFileError) { - errorCode = NOT_FOUND_ERR; - } - // log [NSNumber numberWithDouble: theMessage] objCtype to see what it returns - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode]; - } - if (!result) { - // invalid path or file does not exist - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* - * set MetaData of entry - * Currently we only support "com.apple.MobileBackup" (boolean) - */ -- (void)setMetadata:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* filePath = [command.arguments objectAtIndex:0]; - NSDictionary* options = [command.arguments objectAtIndex:1 withDefault:nil]; - CDVPluginResult* result = nil; - BOOL ok = NO; - - // setMetadata doesn't make sense for asset library files - if (![filePath hasPrefix:kCDVAssetsLibraryPrefix]) { - // we only care about this iCloud key for now. - // set to 1/true to skip backup, set to 0/false to back it up (effectively removing the attribute) - NSString* iCloudBackupExtendedAttributeKey = @"com.apple.MobileBackup"; - id iCloudBackupExtendedAttributeValue = [options objectForKey:iCloudBackupExtendedAttributeKey]; - - if ((iCloudBackupExtendedAttributeValue != nil) && [iCloudBackupExtendedAttributeValue isKindOfClass:[NSNumber class]]) { - if (IsAtLeastiOSVersion(@"5.1")) { - NSURL* url = [NSURL fileURLWithPath:filePath]; - NSError* __autoreleasing error = nil; - - ok = [url setResourceValue:[NSNumber numberWithBool:[iCloudBackupExtendedAttributeValue boolValue]] forKey:NSURLIsExcludedFromBackupKey error:&error]; - } else { // below 5.1 (deprecated - only really supported in 5.01) - u_int8_t value = [iCloudBackupExtendedAttributeValue intValue]; - if (value == 0) { // remove the attribute (allow backup, the default) - ok = (removexattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], 0) == 0); - } else { // set the attribute (skip backup) - ok = (setxattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], &value, sizeof(value), 0, 0) == 0); - } - } - } - } - - if (ok) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* removes the directory or file entry - * IN: - * NSArray* arguments - * 0 - NSString* fullPath - * - * returns NO_MODIFICATION_ALLOWED_ERR if is top level directory or no permission to delete dir - * returns INVALID_MODIFICATION_ERR if is non-empty dir or asset library file - * returns NOT_FOUND_ERR if file or dir is not found -*/ -- (void)remove:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* fullPath = [command.arguments objectAtIndex:0]; - CDVPluginResult* result = nil; - CDVFileError errorCode = 0; // !! 0 not currently defined - - // return error for assets-library URLs - if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) { - errorCode = INVALID_MODIFICATION_ERR; - } else if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString:self.appTempPath]) { - // error if try to remove top level (documents or tmp) dir - errorCode = NO_MODIFICATION_ALLOWED_ERR; - } else { - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - BOOL bIsDir = NO; - BOOL bExists = [fileMgr fileExistsAtPath:fullPath isDirectory:&bIsDir]; - if (!bExists) { - errorCode = NOT_FOUND_ERR; - } - if (bIsDir && ([[fileMgr contentsOfDirectoryAtPath:fullPath error:nil] count] != 0)) { - // dir is not empty - errorCode = INVALID_MODIFICATION_ERR; - } - } - if (errorCode > 0) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } else { - // perform actual remove - result = [self doRemove:fullPath]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* recursively removes the directory - * IN: - * NSArray* arguments - * 0 - NSString* fullPath - * - * returns NO_MODIFICATION_ALLOWED_ERR if is top level directory or no permission to delete dir - * returns NOT_FOUND_ERR if file or dir is not found - */ -- (void)removeRecursively:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* fullPath = [command.arguments objectAtIndex:0]; - - // return unsupported result for assets-library URLs - if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"removeRecursively not supported for assets-library URLs."]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - CDVPluginResult* result = nil; - - // error if try to remove top level (documents or tmp) dir - if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString:self.appTempPath]) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR]; - } else { - result = [self doRemove:fullPath]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* remove the file or directory (recursively) - * IN: - * NSString* fullPath - the full path to the file or directory to be removed - * NSString* callbackId - * called from remove and removeRecursively - check all pubic api specific error conditions (dir not empty, etc) before calling - */ - -- (CDVPluginResult*)doRemove:(NSString*)fullPath -{ - CDVPluginResult* result = nil; - BOOL bSuccess = NO; - NSError* __autoreleasing pError = nil; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - - @try { - bSuccess = [fileMgr removeItemAtPath:fullPath error:&pError]; - if (bSuccess) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - // see if we can give a useful error - CDVFileError errorCode = ABORT_ERR; - NSLog(@"error getting metadata: %@", [pError localizedDescription]); - if ([pError code] == NSFileNoSuchFileError) { - errorCode = NOT_FOUND_ERR; - } else if ([pError code] == NSFileWriteNoPermissionError) { - errorCode = NO_MODIFICATION_ALLOWED_ERR; - } - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - } @catch(NSException* e) { // NSInvalidArgumentException if path is . or .. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:SYNTAX_ERR]; - } - - return result; -} - -- (void)copyTo:(CDVInvokedUrlCommand*)command -{ - [self doCopyMove:command isCopy:YES]; -} - -- (void)moveTo:(CDVInvokedUrlCommand*)command -{ - [self doCopyMove:command isCopy:NO]; -} - -/** - * Helper function to check to see if the user attempted to copy an entry into its parent without changing its name, - * or attempted to copy a directory into a directory that it contains directly or indirectly. - * - * IN: - * NSString* srcDir - * NSString* destinationDir - * OUT: - * YES copy/ move is allows - * NO move is onto itself - */ -- (BOOL)canCopyMoveSrc:(NSString*)src ToDestination:(NSString*)dest -{ - // This weird test is to determine if we are copying or moving a directory into itself. - // Copy /Documents/myDir to /Documents/myDir-backup is okay but - // Copy /Documents/myDir to /Documents/myDir/backup not okay - BOOL copyOK = YES; - NSRange range = [dest rangeOfString:src]; - - if (range.location != NSNotFound) { - NSRange testRange = {range.length - 1, ([dest length] - range.length)}; - NSRange resultRange = [dest rangeOfString:@"/" options:0 range:testRange]; - if (resultRange.location != NSNotFound) { - copyOK = NO; - } - } - return copyOK; -} - -/* Copy/move a file or directory to a new location - * IN: - * NSArray* arguments - * 0 - NSString* fullPath of entry - * 1 - NSString* newName the new name of the entry, defaults to the current name - * NSMutableDictionary* options - DirectoryEntry to which to copy the entry - * BOOL - bCopy YES if copy, NO if move - * - */ -- (void)doCopyMove:(CDVInvokedUrlCommand*)command isCopy:(BOOL)bCopy -{ - NSArray* arguments = command.arguments; - - // arguments - NSString* srcFullPath = [arguments objectAtIndex:0]; - NSString* destRootPath = [arguments objectAtIndex:1]; - // optional argument - NSString* newName = ([arguments count] > 2) ? [arguments objectAtIndex:2] : [srcFullPath lastPathComponent]; // use last component from appPath if new name not provided - - __block CDVPluginResult* result = nil; - CDVFileError errCode = 0; // !! Currently 0 is not defined, use this to signal error !! - - /*NSString* destRootPath = nil; - NSString* key = @"fullPath"; - if([options valueForKeyIsString:key]){ - destRootPath = [options objectForKey:@"fullPath"]; - }*/ - - if (!destRootPath) { - // no destination provided - errCode = NOT_FOUND_ERR; - } else if ([newName rangeOfString:@":"].location != NSNotFound) { - // invalid chars in new name - errCode = ENCODING_ERR; - } else { - NSString* newFullPath = [destRootPath stringByAppendingPathComponent:newName]; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - if ([newFullPath isEqualToString:srcFullPath]) { - // source and destination can not be the same - errCode = INVALID_MODIFICATION_ERR; - } else if ([srcFullPath hasPrefix:kCDVAssetsLibraryPrefix]) { - if (bCopy) { - // Copying (as opposed to moving) an assets library file is okay. - // In this case, we need to use an asynchronous method to retrieve the file. - // Because of this, we can't just assign to `result` and send it at the end of the method. - // Instead, we return after calling the asynchronous method and send `result` in each of the blocks. - ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) { - if (asset) { - // We have the asset! Get the data and try to copy it over. - if (![fileMgr fileExistsAtPath:destRootPath]) { - // The destination directory doesn't exist. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } else if ([fileMgr fileExistsAtPath:newFullPath]) { - // A file already exists at the destination path. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:PATH_EXISTS_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - // We're good to go! Write the file to the new destination. - ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation]; - Byte* buffer = (Byte*)malloc([assetRepresentation size]); - NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil]; - NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES]; - [data writeToFile:newFullPath atomically:YES]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getDirectoryEntry:newFullPath isDirectory:NO]]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } else { - // We couldn't find the asset. Send the appropriate error. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } - }; - ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) { - // Retrieving the asset failed for some reason. Send the appropriate error. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }; - - ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; - [assetsLibrary assetForURL:[NSURL URLWithString:srcFullPath] resultBlock:resultBlock failureBlock:failureBlock]; - return; - } else { - // Moving an assets library file is not doable, since we can't remove it. - errCode = INVALID_MODIFICATION_ERR; - } - } else { - BOOL bSrcIsDir = NO; - BOOL bDestIsDir = NO; - BOOL bNewIsDir = NO; - BOOL bSrcExists = [fileMgr fileExistsAtPath:srcFullPath isDirectory:&bSrcIsDir]; - BOOL bDestExists = [fileMgr fileExistsAtPath:destRootPath isDirectory:&bDestIsDir]; - BOOL bNewExists = [fileMgr fileExistsAtPath:newFullPath isDirectory:&bNewIsDir]; - if (!bSrcExists || !bDestExists) { - // the source or the destination root does not exist - errCode = NOT_FOUND_ERR; - } else if (bSrcIsDir && (bNewExists && !bNewIsDir)) { - // can't copy/move dir to file - errCode = INVALID_MODIFICATION_ERR; - } else { // no errors yet - NSError* __autoreleasing error = nil; - BOOL bSuccess = NO; - if (bCopy) { - if (bSrcIsDir && ![self canCopyMoveSrc:srcFullPath ToDestination:newFullPath] /*[newFullPath hasPrefix:srcFullPath]*/) { - // can't copy dir into self - errCode = INVALID_MODIFICATION_ERR; - } else if (bNewExists) { - // the full destination should NOT already exist if a copy - errCode = PATH_EXISTS_ERR; - } else { - bSuccess = [fileMgr copyItemAtPath:srcFullPath toPath:newFullPath error:&error]; - } - } else { // move - // iOS requires that destination must not exist before calling moveTo - // is W3C INVALID_MODIFICATION_ERR error if destination dir exists and has contents - // - if (!bSrcIsDir && (bNewExists && bNewIsDir)) { - // can't move a file to directory - errCode = INVALID_MODIFICATION_ERR; - } else if (bSrcIsDir && ![self canCopyMoveSrc:srcFullPath ToDestination:newFullPath]) { // [newFullPath hasPrefix:srcFullPath]){ - // can't move a dir into itself - errCode = INVALID_MODIFICATION_ERR; - } else if (bNewExists) { - if (bNewIsDir && ([[fileMgr contentsOfDirectoryAtPath:newFullPath error:NULL] count] != 0)) { - // can't move dir to a dir that is not empty - errCode = INVALID_MODIFICATION_ERR; - newFullPath = nil; // so we won't try to move - } else { - // remove destination so can perform the moveItemAtPath - bSuccess = [fileMgr removeItemAtPath:newFullPath error:NULL]; - if (!bSuccess) { - errCode = INVALID_MODIFICATION_ERR; // is this the correct error? - newFullPath = nil; - } - } - } else if (bNewIsDir && [newFullPath hasPrefix:srcFullPath]) { - // can't move a directory inside itself or to any child at any depth; - errCode = INVALID_MODIFICATION_ERR; - newFullPath = nil; - } - - if (newFullPath != nil) { - bSuccess = [fileMgr moveItemAtPath:srcFullPath toPath:newFullPath error:&error]; - } - } - if (bSuccess) { - // should verify it is there and of the correct type??? - NSDictionary* newEntry = [self getDirectoryEntry:newFullPath isDirectory:bSrcIsDir]; // should be the same type as source - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newEntry]; - } else { - errCode = INVALID_MODIFICATION_ERR; // catch all - if (error) { - if (([error code] == NSFileReadUnknownError) || ([error code] == NSFileReadTooLargeError)) { - errCode = NOT_READABLE_ERR; - } else if ([error code] == NSFileWriteOutOfSpaceError) { - errCode = QUOTA_EXCEEDED_ERR; - } else if ([error code] == NSFileWriteNoPermissionError) { - errCode = NO_MODIFICATION_ALLOWED_ERR; - } - } - } - } - } - } - if (errCode > 0) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errCode]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -/* return the URI to the entry - * IN: - * NSArray* arguments - * 0 - NSString* fullPath of entry - * 1 - desired mime type of entry - ignored - always returns file:// - */ - -/* Not needed since W3C toURI is synchronous. Leaving code here for now in case W3C spec changes..... -- (void) toURI:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSString* argPath = [command.arguments objectAtIndex:0]; - PluginResult* result = nil; - NSString* jsString = nil; - - NSString* fullPath = [self getFullPath: argPath]; - if (fullPath) { - // do we need to make sure the file actually exists? - // create file uri - NSString* strUri = [fullPath stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; - NSURL* fileUrl = [NSURL fileURLWithPath:strUri]; - if (fileUrl) { - result = [PluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: [fileUrl absoluteString]]; - jsString = [result toSuccessCallbackString:callbackId]; - } // else NOT_FOUND_ERR - } - if(!jsString) { - // was error - result = [PluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: NOT_FOUND_ERR cast: @"window.localFileSystem._castError"]; - jsString = [result toErrorCallbackString:callbackId]; - } - - [self writeJavascript:jsString]; -}*/ -- (void)getFileMetadata:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* argPath = [command.arguments objectAtIndex:0]; - - __block CDVPluginResult* result = nil; - - NSString* fullPath = argPath; // [self getFullPath: argPath]; - - if (fullPath) { - if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) { - // In this case, we need to use an asynchronous method to retrieve the file. - // Because of this, we can't just assign to `result` and send it at the end of the method. - // Instead, we return after calling the asynchronous method and send `result` in each of the blocks. - ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) { - if (asset) { - // We have the asset! Populate the dictionary and send it off. - NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5]; - ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation]; - [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[assetRepresentation size]] forKey:@"size"]; - [fileInfo setObject:argPath forKey:@"fullPath"]; - NSString* filename = [assetRepresentation filename]; - [fileInfo setObject:filename forKey:@"name"]; - [fileInfo setObject:[self getMimeTypeFromPath:filename] forKey:@"type"]; - NSDate* creationDate = [asset valueForProperty:ALAssetPropertyDate]; - NSNumber* msDate = [NSNumber numberWithDouble:[creationDate timeIntervalSince1970] * 1000]; - [fileInfo setObject:msDate forKey:@"lastModifiedDate"]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } else { - // We couldn't find the asset. Send the appropriate error. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } - }; - ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) { - // Retrieving the asset failed for some reason. Send the appropriate error. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }; - - ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; - [assetsLibrary assetForURL:[NSURL URLWithString:argPath] resultBlock:resultBlock failureBlock:failureBlock]; - return; - } else { - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - BOOL bIsDir = NO; - // make sure it exists and is not a directory - BOOL bExists = [fileMgr fileExistsAtPath:fullPath isDirectory:&bIsDir]; - if (!bExists || bIsDir) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - } else { - // create dictionary of file info - NSError* __autoreleasing error = nil; - NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:fullPath error:&error]; - NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5]; - [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[fileAttrs fileSize]] forKey:@"size"]; - [fileInfo setObject:argPath forKey:@"fullPath"]; - [fileInfo setObject:@"" forKey:@"type"]; // can't easily get the mimetype unless create URL, send request and read response so skipping - [fileInfo setObject:[argPath lastPathComponent] forKey:@"name"]; - NSDate* modDate = [fileAttrs fileModificationDate]; - NSNumber* msDate = [NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000]; - [fileInfo setObject:msDate forKey:@"lastModifiedDate"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]; - } - } - } - if (!result) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_INSTANTIATION_EXCEPTION]; - } - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -- (void)readEntries:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* fullPath = [command.arguments objectAtIndex:0]; - - // return unsupported result for assets-library URLs - if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"readEntries not supported for assets-library URLs."]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - CDVPluginResult* result = nil; - - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - NSError* __autoreleasing error = nil; - NSArray* contents = [fileMgr contentsOfDirectoryAtPath:fullPath error:&error]; - - if (contents) { - NSMutableArray* entries = [NSMutableArray arrayWithCapacity:1]; - if ([contents count] > 0) { - // create an Entry (as JSON) for each file/dir - for (NSString* name in contents) { - // see if is dir or file - NSString* entryPath = [fullPath stringByAppendingPathComponent:name]; - BOOL bIsDir = NO; - [fileMgr fileExistsAtPath:entryPath isDirectory:&bIsDir]; - NSDictionary* entryDict = [self getDirectoryEntry:entryPath isDirectory:bIsDir]; - [entries addObject:entryDict]; - } - } - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:entries]; - } else { - // assume not found but could check error for more specific error conditions - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -- (void)readFileWithPath:(NSString*)path start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback -{ - if (path == nil) { - callback(nil, nil, SYNTAX_ERR); - } else { - [self.commandDelegate runInBackground:^ { - if ([path hasPrefix:kCDVAssetsLibraryPrefix]) { - // In this case, we need to use an asynchronous method to retrieve the file. - // Because of this, we can't just assign to `result` and send it at the end of the method. - // Instead, we return after calling the asynchronous method and send `result` in each of the blocks. - ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) { - if (asset) { - // We have the asset! Get the data and send it off. - ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation]; - Byte* buffer = (Byte*)malloc([assetRepresentation size]); - NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil]; - NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES]; - NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType); - - callback(data, MIMEType, NO_ERROR); - } else { - callback(nil, nil, NOT_FOUND_ERR); - } - }; - ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) { - // Retrieving the asset failed for some reason. Send the appropriate error. - NSLog(@"Error: %@", error); - callback(nil, nil, SECURITY_ERR); - }; - - ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; - [assetsLibrary assetForURL:[NSURL URLWithString:path] resultBlock:resultBlock failureBlock:failureBlock]; - } else { - NSString* mimeType = [self getMimeTypeFromPath:path]; - if (mimeType == nil) { - mimeType = @"*/*"; - } - NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:path]; - if (start > 0) { - [file seekToFileOffset:start]; - } - - NSData* readData; - if (end < 0) { - readData = [file readDataToEndOfFile]; - } else { - readData = [file readDataOfLength:(end - start)]; - } - - [file closeFile]; - - callback(readData, mimeType, readData != nil ? NO_ERROR : NOT_FOUND_ERR); - } - }]; - } -} - -/* read and return file data - * IN: - * NSArray* arguments - * 0 - NSString* fullPath - * 1 - NSString* encoding - * 2 - NSString* start - * 3 - NSString* end - */ -- (void)readAsText:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* path = [command argumentAtIndex:0]; - NSString* encoding = [command argumentAtIndex:1]; - NSInteger start = [[command argumentAtIndex:2] integerValue]; - NSInteger end = [[command argumentAtIndex:3] integerValue]; - - // TODO: implement - if (![@"UTF-8" isEqualToString : encoding]) { - NSLog(@"Only UTF-8 encodings are currently supported by readAsText"); - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:ENCODING_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { - CDVPluginResult* result = nil; - if (data != nil) { - NSString* str = [[NSString alloc] initWithBytesNoCopy:(void*)[data bytes] length:[data length] encoding:NSUTF8StringEncoding freeWhenDone:NO]; - // Check that UTF8 conversion did not fail. - if (str != nil) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:str]; - result.associatedObject = data; - } else { - errorCode = ENCODING_ERR; - } - } - if (result == nil) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }]; -} - -/* Read content of text file and return as base64 encoded data url. - * IN: - * NSArray* arguments - * 0 - NSString* fullPath - * 1 - NSString* start - * 2 - NSString* end - * - * Determines the mime type from the file extension, returns ENCODING_ERR if mimetype can not be determined. - */ - -- (void)readAsDataURL:(CDVInvokedUrlCommand*)command -{ - NSString* path = [command argumentAtIndex:0]; - NSInteger start = [[command argumentAtIndex:1] integerValue]; - NSInteger end = [[command argumentAtIndex:2] integerValue]; - - [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { - CDVPluginResult* result = nil; - if (data != nil) { - // TODO: Would be faster to base64 encode directly to the final string. - NSString* output = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, [data base64EncodedString]]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:output]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }]; -} - -/* Read content of text file and return as an arraybuffer - * IN: - * NSArray* arguments - * 0 - NSString* fullPath - * 1 - NSString* start - * 2 - NSString* end - */ - -- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command -{ - NSString* path = [command argumentAtIndex:0]; - NSInteger start = [[command argumentAtIndex:1] integerValue]; - NSInteger end = [[command argumentAtIndex:2] integerValue]; - - [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { - CDVPluginResult* result = nil; - if (data != nil) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArrayBuffer:data]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }]; -} - -- (void)readAsBinaryString:(CDVInvokedUrlCommand*)command -{ - NSString* path = [command argumentAtIndex:0]; - NSInteger start = [[command argumentAtIndex:1] integerValue]; - NSInteger end = [[command argumentAtIndex:2] integerValue]; - - [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) { - CDVPluginResult* result = nil; - if (data != nil) { - NSString* payload = [[NSString alloc] initWithBytesNoCopy:(void*)[data bytes] length:[data length] encoding:NSASCIIStringEncoding freeWhenDone:NO]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:payload]; - result.associatedObject = data; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode]; - } - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }]; -} - -/* helper function to get the mimeType from the file extension - * IN: - * NSString* fullPath - filename (may include path) - * OUT: - * NSString* the mime type as type/subtype. nil if not able to determine - */ -- (NSString*)getMimeTypeFromPath:(NSString*)fullPath -{ - NSString* mimeType = nil; - - if (fullPath) { - CFStringRef typeId = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[fullPath pathExtension], NULL); - if (typeId) { - mimeType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass(typeId, kUTTagClassMIMEType); - if (!mimeType) { - // special case for m4a - if ([(__bridge NSString*)typeId rangeOfString : @"m4a-audio"].location != NSNotFound) { - mimeType = @"audio/mp4"; - } else if ([[fullPath pathExtension] rangeOfString:@"wav"].location != NSNotFound) { - mimeType = @"audio/wav"; - } - } - CFRelease(typeId); - } - } - return mimeType; -} - -- (void)truncate:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* argPath = [command.arguments objectAtIndex:0]; - unsigned long long pos = (unsigned long long)[[command.arguments objectAtIndex:1] longLongValue]; - - // assets-library files can't be truncated - if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - NSString* appFile = argPath; // [self getFullPath:argPath]; - - unsigned long long newPos = [self truncateFile:appFile atPosition:pos]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:newPos]; - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -- (unsigned long long)truncateFile:(NSString*)filePath atPosition:(unsigned long long)pos -{ - unsigned long long newPos = 0UL; - - NSFileHandle* file = [NSFileHandle fileHandleForWritingAtPath:filePath]; - - if (file) { - [file truncateFileAtOffset:(unsigned long long)pos]; - newPos = [file offsetInFile]; - [file synchronizeFile]; - [file closeFile]; - } - return newPos; -} - -/* write - * IN: - * NSArray* arguments - * 0 - NSString* file path to write to - * 1 - NSString* data to write - * 2 - NSNumber* position to begin writing - */ -- (void)write:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSArray* arguments = command.arguments; - - // arguments - NSString* argPath = [arguments objectAtIndex:0]; - NSString* argData = [arguments objectAtIndex:1]; - unsigned long long pos = (unsigned long long)[[arguments objectAtIndex:2] longLongValue]; - - // text can't be written into assets-library files - if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - NSString* fullPath = argPath; // [self getFullPath:argPath]; - - [self truncateFile:fullPath atPosition:pos]; - - [self writeToFile:fullPath withData:argData append:YES callback:callbackId]; -} - -- (void)writeToFile:(NSString*)filePath withData:(NSString*)data append:(BOOL)shouldAppend callback:(NSString*)callbackId -{ - CDVPluginResult* result = nil; - CDVFileError errCode = INVALID_MODIFICATION_ERR; - int bytesWritten = 0; - NSData* encData = [data dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; - - if (filePath) { - NSOutputStream* fileStream = [NSOutputStream outputStreamToFileAtPath:filePath append:shouldAppend]; - if (fileStream) { - NSUInteger len = [encData length]; - [fileStream open]; - - bytesWritten = [fileStream write:[encData bytes] maxLength:len]; - - [fileStream close]; - if (bytesWritten > 0) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:bytesWritten]; - // } else { - // can probably get more detailed error info via [fileStream streamError] - // errCode already set to INVALID_MODIFICATION_ERR; - // bytesWritten = 0; // may be set to -1 on error - } - } // else fileStream not created return INVALID_MODIFICATION_ERR - } else { - // invalid filePath - errCode = NOT_FOUND_ERR; - } - if (!result) { - // was an error - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode]; - } - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; -} - -- (void)testFileExists:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* argPath = [command.arguments objectAtIndex:0]; - - // Get the file manager - NSFileManager* fMgr = [NSFileManager defaultManager]; - NSString* appFile = argPath; // [ self getFullPath: argPath]; - - BOOL bExists = [fMgr fileExistsAtPath:appFile]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(bExists ? 1 : 0)]; - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -- (void)testDirectoryExists:(CDVInvokedUrlCommand*)command -{ - // arguments - NSString* argPath = [command.arguments objectAtIndex:0]; - - // Get the file manager - NSFileManager* fMgr = [[NSFileManager alloc] init]; - NSString* appFile = argPath; // [self getFullPath: argPath]; - BOOL bIsDir = NO; - BOOL bExists = [fMgr fileExistsAtPath:appFile isDirectory:&bIsDir]; - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:((bExists && bIsDir) ? 1 : 0)]; - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -// Returns number of bytes available via callback -- (void)getFreeDiskSpace:(CDVInvokedUrlCommand*)command -{ - // no arguments - - NSNumber* pNumAvail = [self checkFreeDiskSpace:self.appDocsPath]; - - NSString* strFreeSpace = [NSString stringWithFormat:@"%qu", [pNumAvail unsignedLongLongValue]]; - // NSLog(@"Free space is %@", strFreeSpace ); - - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:strFreeSpace]; - - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; -} - -@end diff --git a/CordovaLib/Classes/CDVFileTransfer.h b/CordovaLib/Classes/CDVFileTransfer.h deleted file mode 100755 index 233a114..0000000 --- a/CordovaLib/Classes/CDVFileTransfer.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - 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 -#import "CDVPlugin.h" - -enum CDVFileTransferError { - FILE_NOT_FOUND_ERR = 1, - INVALID_URL_ERR = 2, - CONNECTION_ERR = 3, - CONNECTION_ABORTED = 4 -}; -typedef int CDVFileTransferError; - -enum CDVFileTransferDirection { - CDV_TRANSFER_UPLOAD = 1, - CDV_TRANSFER_DOWNLOAD = 2, -}; -typedef int CDVFileTransferDirection; - -// Magic value within the options dict used to set a cookie. -extern NSString* const kOptionsKeyCookie; - -@interface CDVFileTransfer : CDVPlugin {} - -- (void)upload:(CDVInvokedUrlCommand*)command; -- (void)download:(CDVInvokedUrlCommand*)command; -- (NSString*)escapePathComponentForUrlString:(NSString*)urlString; - -// Visible for testing. -- (NSURLRequest*)requestForUploadCommand:(CDVInvokedUrlCommand*)command fileData:(NSData*)fileData; -- (NSMutableDictionary*)createFileTransferError:(int)code AndSource:(NSString*)source AndTarget:(NSString*)target; - -- (NSMutableDictionary*)createFileTransferError:(int)code - AndSource:(NSString*)source - AndTarget:(NSString*)target - AndHttpStatus:(int)httpStatus - AndBody:(NSString*)body; -@property (readonly) NSMutableDictionary* activeTransfers; -@property (nonatomic, assign) UIBackgroundTaskIdentifier backgroundTaskID; -@end - -@class CDVFileTransferEntityLengthRequest; - -@interface CDVFileTransferDelegate : NSObject {} - -- (void)updateBytesExpected:(NSInteger)newBytesExpected; - -@property (strong) NSMutableData* responseData; // atomic -@property (nonatomic, strong) CDVFileTransfer* command; -@property (nonatomic, assign) CDVFileTransferDirection direction; -@property (nonatomic, strong) NSURLConnection* connection; -@property (nonatomic, copy) NSString* callbackId; -@property (nonatomic, copy) NSString* objectId; -@property (nonatomic, copy) NSString* source; -@property (nonatomic, copy) NSString* target; -@property (nonatomic, copy) NSString* mimeType; -@property (assign) int responseCode; // atomic -@property (nonatomic, assign) NSInteger bytesTransfered; -@property (nonatomic, assign) NSInteger bytesExpected; -@property (nonatomic, assign) BOOL trustAllHosts; -@property (strong) NSFileHandle* targetFileHandle; -@property (nonatomic, strong) CDVFileTransferEntityLengthRequest* entityLengthRequest; - -@end; diff --git a/CordovaLib/Classes/CDVFileTransfer.m b/CordovaLib/Classes/CDVFileTransfer.m deleted file mode 100755 index 5536715..0000000 --- a/CordovaLib/Classes/CDVFileTransfer.m +++ /dev/null @@ -1,714 +0,0 @@ -/* - 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 "CDV.h" - -#import -#import -#import -#import - -@interface CDVFileTransfer () -// Sets the requests headers for the request. -- (void)applyRequestHeaders:(NSDictionary*)headers toRequest:(NSMutableURLRequest*)req; -// Creates a delegate to handle an upload. -- (CDVFileTransferDelegate*)delegateForUploadCommand:(CDVInvokedUrlCommand*)command; -// Creates an NSData* for the file for the given upload arguments. -- (void)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command; -@end - -// Buffer size to use for streaming uploads. -static const NSUInteger kStreamBufferSize = 32768; -// Magic value within the options dict used to set a cookie. -NSString* const kOptionsKeyCookie = @"__cookie"; -// Form boundary for multi-part requests. -NSString* const kFormBoundary = @"+++++org.apache.cordova.formBoundary"; - -// Writes the given data to the stream in a blocking way. -// If successful, returns bytesToWrite. -// If the stream was closed on the other end, returns 0. -// If there was an error, returns -1. -static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream) -{ - UInt8* bytes = (UInt8*)[data bytes]; - NSUInteger bytesToWrite = [data length]; - NSUInteger totalBytesWritten = 0; - - while (totalBytesWritten < bytesToWrite) { - CFIndex result = CFWriteStreamWrite(stream, - bytes + totalBytesWritten, - bytesToWrite - totalBytesWritten); - if (result < 0) { - CFStreamError error = CFWriteStreamGetError(stream); - NSLog(@"WriteStreamError domain: %ld error: %ld", error.domain, error.error); - return result; - } else if (result == 0) { - return result; - } - totalBytesWritten += result; - } - - return totalBytesWritten; -} - -@implementation CDVFileTransfer -@synthesize activeTransfers; - -- (NSString*)escapePathComponentForUrlString:(NSString*)urlString -{ - NSRange schemeAndHostRange = [urlString rangeOfString:@"://.*?/" options:NSRegularExpressionSearch]; - - if (schemeAndHostRange.length == 0) { - return urlString; - } - - NSInteger schemeAndHostEndIndex = NSMaxRange(schemeAndHostRange); - NSString* schemeAndHost = [urlString substringToIndex:schemeAndHostEndIndex]; - NSString* pathComponent = [urlString substringFromIndex:schemeAndHostEndIndex]; - pathComponent = [pathComponent stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - - return [schemeAndHost stringByAppendingString:pathComponent]; -} - -- (void)applyRequestHeaders:(NSDictionary*)headers toRequest:(NSMutableURLRequest*)req -{ - [req setValue:@"XMLHttpRequest" forHTTPHeaderField:@"X-Requested-With"]; - - NSString* userAgent = [self.commandDelegate userAgent]; - if (userAgent) { - [req setValue:userAgent forHTTPHeaderField:@"User-Agent"]; - } - - for (NSString* headerName in headers) { - id value = [headers objectForKey:headerName]; - if (!value || (value == [NSNull null])) { - value = @"null"; - } - - // First, remove an existing header if one exists. - [req setValue:nil forHTTPHeaderField:headerName]; - - if (![value isKindOfClass:[NSArray class]]) { - value = [NSArray arrayWithObject:value]; - } - - // Then, append all header values. - for (id __strong subValue in value) { - // Convert from an NSNumber -> NSString. - if ([subValue respondsToSelector:@selector(stringValue)]) { - subValue = [subValue stringValue]; - } - if ([subValue isKindOfClass:[NSString class]]) { - [req addValue:subValue forHTTPHeaderField:headerName]; - } - } - } -} - -- (NSURLRequest*)requestForUploadCommand:(CDVInvokedUrlCommand*)command fileData:(NSData*)fileData -{ - // arguments order from js: [filePath, server, fileKey, fileName, mimeType, params, debug, chunkedMode] - // however, params is a JavaScript object and during marshalling is put into the options dict, - // thus debug and chunkedMode are the 6th and 7th arguments - NSString* target = [command argumentAtIndex:0]; - NSString* server = [command argumentAtIndex:1]; - NSString* fileKey = [command argumentAtIndex:2 withDefault:@"file"]; - NSString* fileName = [command argumentAtIndex:3 withDefault:@"no-filename"]; - NSString* mimeType = [command argumentAtIndex:4 withDefault:nil]; - NSDictionary* options = [command argumentAtIndex:5 withDefault:nil]; - // BOOL trustAllHosts = [[arguments objectAtIndex:6 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs - BOOL chunkedMode = [[command argumentAtIndex:7 withDefault:[NSNumber numberWithBool:YES]] boolValue]; - NSDictionary* headers = [command argumentAtIndex:8 withDefault:nil]; - // Allow alternative http method, default to POST. JS side checks - // for allowed methods, currently PUT or POST (forces POST for - // unrecognised values) - NSString* httpMethod = [command argumentAtIndex:10 withDefault:@"POST"]; - CDVPluginResult* result = nil; - CDVFileTransferError errorCode = 0; - - // NSURL does not accepts URLs with spaces in the path. We escape the path in order - // to be more lenient. - NSURL* url = [NSURL URLWithString:server]; - - if (!url) { - errorCode = INVALID_URL_ERR; - NSLog(@"File Transfer Error: Invalid server URL %@", server); - } else if (!fileData) { - errorCode = FILE_NOT_FOUND_ERR; - } - - if (errorCode > 0) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:errorCode AndSource:target AndTarget:server]]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return nil; - } - - NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url]; - - [req setHTTPMethod:httpMethod]; - - // Magic value to set a cookie - if ([options objectForKey:kOptionsKeyCookie]) { - [req setValue:[options objectForKey:kOptionsKeyCookie] forHTTPHeaderField:@"Cookie"]; - [req setHTTPShouldHandleCookies:NO]; - } - - NSString* contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", kFormBoundary]; - [req setValue:contentType forHTTPHeaderField:@"Content-Type"]; - [self applyRequestHeaders:headers toRequest:req]; - - NSData* formBoundaryData = [[NSString stringWithFormat:@"--%@\r\n", kFormBoundary] dataUsingEncoding:NSUTF8StringEncoding]; - NSMutableData* postBodyBeforeFile = [NSMutableData data]; - - for (NSString* key in options) { - id val = [options objectForKey:key]; - if (!val || (val == [NSNull null]) || [key isEqualToString:kOptionsKeyCookie]) { - continue; - } - // if it responds to stringValue selector (eg NSNumber) get the NSString - if ([val respondsToSelector:@selector(stringValue)]) { - val = [val stringValue]; - } - // finally, check whether it is a NSString (for dataUsingEncoding selector below) - if (![val isKindOfClass:[NSString class]]) { - continue; - } - - [postBodyBeforeFile appendData:formBoundaryData]; - [postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]]; - [postBodyBeforeFile appendData:[val dataUsingEncoding:NSUTF8StringEncoding]]; - [postBodyBeforeFile appendData:[@"\r\n" dataUsingEncoding : NSUTF8StringEncoding]]; - } - - [postBodyBeforeFile appendData:formBoundaryData]; - [postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", fileKey, fileName] dataUsingEncoding:NSUTF8StringEncoding]]; - if (mimeType != nil) { - [postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n", mimeType] dataUsingEncoding:NSUTF8StringEncoding]]; - } - [postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Length: %d\r\n\r\n", [fileData length]] dataUsingEncoding:NSUTF8StringEncoding]]; - - DLog(@"fileData length: %d", [fileData length]); - NSData* postBodyAfterFile = [[NSString stringWithFormat:@"\r\n--%@--\r\n", kFormBoundary] dataUsingEncoding:NSUTF8StringEncoding]; - - NSUInteger totalPayloadLength = [postBodyBeforeFile length] + [fileData length] + [postBodyAfterFile length]; - [req setValue:[[NSNumber numberWithInteger:totalPayloadLength] stringValue] forHTTPHeaderField:@"Content-Length"]; - - if (chunkedMode) { - CFReadStreamRef readStream = NULL; - CFWriteStreamRef writeStream = NULL; - CFStreamCreateBoundPair(NULL, &readStream, &writeStream, kStreamBufferSize); - [req setHTTPBodyStream:CFBridgingRelease(readStream)]; - - self.backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ - [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskID]; - self.backgroundTaskID = UIBackgroundTaskInvalid; - NSLog(@"Background task to upload media finished."); - }]; - - [self.commandDelegate runInBackground:^{ - if (CFWriteStreamOpen(writeStream)) { - NSData* chunks[] = {postBodyBeforeFile, fileData, postBodyAfterFile}; - int numChunks = sizeof(chunks) / sizeof(chunks[0]); - - for (int i = 0; i < numChunks; ++i) { - CFIndex result = WriteDataToStream(chunks[i], writeStream); - if (result <= 0) { - break; - } - } - } else { - NSLog(@"FileTransfer: Failed to open writeStream"); - } - CFWriteStreamClose(writeStream); - CFRelease(writeStream); - }]; - } else { - [postBodyBeforeFile appendData:fileData]; - [postBodyBeforeFile appendData:postBodyAfterFile]; - [req setHTTPBody:postBodyBeforeFile]; - } - return req; -} - -- (CDVFileTransferDelegate*)delegateForUploadCommand:(CDVInvokedUrlCommand*)command -{ - NSString* source = [command.arguments objectAtIndex:0]; - NSString* server = [command.arguments objectAtIndex:1]; - BOOL trustAllHosts = [[command.arguments objectAtIndex:6 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs - NSString* objectId = [command.arguments objectAtIndex:9]; - - CDVFileTransferDelegate* delegate = [[CDVFileTransferDelegate alloc] init]; - - delegate.command = self; - delegate.callbackId = command.callbackId; - delegate.direction = CDV_TRANSFER_UPLOAD; - delegate.objectId = objectId; - delegate.source = source; - delegate.target = server; - delegate.trustAllHosts = trustAllHosts; - - return delegate; -} - -- (void)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command -{ - NSString* target = (NSString*)[command.arguments objectAtIndex:0]; - NSError* __autoreleasing err = nil; - - // return unsupported result for assets-library URLs - if ([target hasPrefix:kCDVAssetsLibraryPrefix]) { - // Instead, we return after calling the asynchronous method and send `result` in each of the blocks. - ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) { - if (asset) { - // We have the asset! Get the data and send it off. - ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation]; - Byte* buffer = (Byte*)malloc([assetRepresentation size]); - NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil]; - NSData* fileData = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES]; - [self uploadData:fileData command:command]; - } else { - // We couldn't find the asset. Send the appropriate error. - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } - }; - ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) { - // Retrieving the asset failed for some reason. Send the appropriate error. - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - }; - - ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; - [assetsLibrary assetForURL:[NSURL URLWithString:target] resultBlock:resultBlock failureBlock:failureBlock]; - return; - } else { - // Extract the path part out of a file: URL. - NSString* filePath = [target hasPrefix:@"/"] ? [target copy] : [[NSURL URLWithString:target] path]; - if (filePath == nil) { - // We couldn't find the asset. Send the appropriate error. - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - // Memory map the file so that it can be read efficiently even if it is large. - NSData* fileData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&err]; - - if (err != nil) { - NSLog(@"Error opening file %@: %@", target, err); - } - [self uploadData:fileData command:command]; - } -} - -- (void)upload:(CDVInvokedUrlCommand*)command -{ - // fileData and req are split into helper functions to ease the unit testing of delegateForUpload. - // First, get the file data. This method will call `uploadData:command`. - [self fileDataForUploadCommand:command]; -} - -- (void)uploadData:(NSData*)fileData command:(CDVInvokedUrlCommand*)command -{ - NSURLRequest* req = [self requestForUploadCommand:command fileData:fileData]; - - if (req == nil) { - return; - } - CDVFileTransferDelegate* delegate = [self delegateForUploadCommand:command]; - [NSURLConnection connectionWithRequest:req delegate:delegate]; - - if (activeTransfers == nil) { - activeTransfers = [[NSMutableDictionary alloc] init]; - } - - [activeTransfers setObject:delegate forKey:delegate.objectId]; -} - -- (void)abort:(CDVInvokedUrlCommand*)command -{ - NSString* objectId = [command.arguments objectAtIndex:0]; - - CDVFileTransferDelegate* delegate = [activeTransfers objectForKey:objectId]; - - 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]; - } -} - -- (void)download:(CDVInvokedUrlCommand*)command -{ - DLog(@"File Transfer downloading file..."); - NSString* sourceUrl = [command.arguments objectAtIndex:0]; - NSString* filePath = [command.arguments objectAtIndex:1]; - BOOL trustAllHosts = [[command.arguments objectAtIndex:2 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs - NSString* objectId = [command.arguments objectAtIndex:3]; - NSDictionary* headers = [command.arguments objectAtIndex:4 withDefault:nil]; - - // return unsupported result for assets-library URLs - if ([filePath hasPrefix:kCDVAssetsLibraryPrefix]) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"download not supported for assets-library URLs."]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - CDVPluginResult* result = nil; - CDVFileTransferError errorCode = 0; - - NSURL* file; - - if ([filePath hasPrefix:@"/"]) { - file = [NSURL fileURLWithPath:filePath]; - } else { - file = [NSURL URLWithString:filePath]; - } - - NSURL* url = [NSURL URLWithString:sourceUrl]; - - if (!url) { - errorCode = INVALID_URL_ERR; - NSLog(@"File Transfer Error: Invalid server URL %@", sourceUrl); - } else if (![file isFileURL]) { - errorCode = FILE_NOT_FOUND_ERR; - NSLog(@"File Transfer Error: Invalid file path or URL %@", filePath); - } - - if (errorCode > 0) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:errorCode AndSource:sourceUrl AndTarget:filePath]]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - return; - } - - NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url]; - [self applyRequestHeaders:headers toRequest:req]; - - CDVFileTransferDelegate* delegate = [[CDVFileTransferDelegate alloc] init]; - delegate.command = self; - delegate.direction = CDV_TRANSFER_DOWNLOAD; - delegate.callbackId = command.callbackId; - delegate.objectId = objectId; - delegate.source = sourceUrl; - delegate.target = filePath; - delegate.trustAllHosts = trustAllHosts; - - delegate.connection = [NSURLConnection connectionWithRequest:req delegate:delegate]; - - if (activeTransfers == nil) { - activeTransfers = [[NSMutableDictionary alloc] init]; - } - - [activeTransfers setObject:delegate forKey:delegate.objectId]; -} - -- (NSMutableDictionary*)createFileTransferError:(int)code AndSource:(NSString*)source AndTarget:(NSString*)target -{ - NSMutableDictionary* result = [NSMutableDictionary dictionaryWithCapacity:3]; - - [result setObject:[NSNumber numberWithInt:code] forKey:@"code"]; - [result setObject:source forKey:@"source"]; - [result setObject:target forKey:@"target"]; - NSLog(@"FileTransferError %@", result); - - return result; -} - -- (NSMutableDictionary*)createFileTransferError:(int)code - AndSource:(NSString*)source - AndTarget:(NSString*)target - AndHttpStatus:(int)httpStatus - AndBody:(NSString*)body -{ - NSMutableDictionary* result = [NSMutableDictionary dictionaryWithCapacity:5]; - - [result setObject:[NSNumber numberWithInt:code] forKey:@"code"]; - [result setObject:source forKey:@"source"]; - [result setObject:target forKey:@"target"]; - [result setObject:[NSNumber numberWithInt:httpStatus] forKey:@"http_status"]; - [result setObject:body forKey:@"body"]; - NSLog(@"FileTransferError %@", result); - - return result; -} - -- (void)onReset -{ - for (CDVFileTransferDelegate* delegate in [activeTransfers allValues]) { - [delegate.connection cancel]; - } - - [activeTransfers removeAllObjects]; -} - -@end - -@interface CDVFileTransferEntityLengthRequest : NSObject { - NSURLConnection* _connection; - CDVFileTransferDelegate* __weak _originalDelegate; -} - -- (CDVFileTransferEntityLengthRequest*)initWithOriginalRequest:(NSURLRequest*)originalRequest andDelegate:(CDVFileTransferDelegate*)originalDelegate; - -@end; - -@implementation CDVFileTransferEntityLengthRequest; - -- (CDVFileTransferEntityLengthRequest*)initWithOriginalRequest:(NSURLRequest*)originalRequest andDelegate:(CDVFileTransferDelegate*)originalDelegate -{ - if (self) { - DLog(@"Requesting entity length for GZIPped content..."); - - NSMutableURLRequest* req = [originalRequest mutableCopy]; - [req setHTTPMethod:@"HEAD"]; - [req setValue:@"identity" forHTTPHeaderField:@"Accept-Encoding"]; - - _originalDelegate = originalDelegate; - _connection = [NSURLConnection connectionWithRequest:req delegate:self]; - } - return self; -} - -- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response -{ - DLog(@"HEAD request returned; content-length is %lld", [response expectedContentLength]); - [_originalDelegate updateBytesExpected:[response expectedContentLength]]; -} - -- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data -{} - -- (void)connectionDidFinishLoading:(NSURLConnection*)connection -{} - -@end - -@implementation CDVFileTransferDelegate - -@synthesize callbackId, connection = _connection, source, target, responseData, command, bytesTransfered, bytesExpected, direction, responseCode, objectId, targetFileHandle; - -- (void)connectionDidFinishLoading:(NSURLConnection*)connection -{ - NSString* uploadResponse = nil; - NSString* downloadResponse = nil; - NSMutableDictionary* uploadResult; - CDVPluginResult* result = nil; - BOOL bDirRequest = NO; - CDVFile* file; - - NSLog(@"File Transfer Finished with response code %d", self.responseCode); - - if (self.direction == CDV_TRANSFER_UPLOAD) { - uploadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding]; - - if ((self.responseCode >= 200) && (self.responseCode < 300)) { - // create dictionary to return FileUploadResult object - uploadResult = [NSMutableDictionary dictionaryWithCapacity:3]; - if (uploadResponse != nil) { - [uploadResult setObject:uploadResponse forKey:@"response"]; - } - [uploadResult setObject:[NSNumber numberWithInt:self.bytesTransfered] forKey:@"bytesSent"]; - [uploadResult setObject:[NSNumber numberWithInt:self.responseCode] forKey:@"responseCode"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:uploadResult]; - } else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:uploadResponse]]; - } - } - if (self.direction == CDV_TRANSFER_DOWNLOAD) { - if (self.targetFileHandle) { - [self.targetFileHandle closeFile]; - self.targetFileHandle = nil; - DLog(@"File Transfer Download success"); - - file = [[CDVFile alloc] init]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[file getDirectoryEntry:target isDirectory:bDirRequest]]; - } else { - downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]]; - } - } - - [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; - - // remove connection for activeTransfers - [command.activeTransfers removeObjectForKey:objectId]; - - // remove background id task in case our upload was done in the background - [[UIApplication sharedApplication] endBackgroundTask:self.command.backgroundTaskID]; - self.command.backgroundTaskID = UIBackgroundTaskInvalid; -} - -- (void)cancelTransferWithError:(NSURLConnection*)connection errorMessage:(NSString*)errorMessage -{ - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsDictionary:[self.command createFileTransferError:FILE_NOT_FOUND_ERR AndSource:self.source AndTarget:self.target AndHttpStatus:self.responseCode AndBody:errorMessage]]; - - NSLog(@"File Transfer Error: %@", errorMessage); - [connection cancel]; - [self.command.activeTransfers removeObjectForKey:self.objectId]; - [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; -} - -- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response -{ - NSError* __autoreleasing error = nil; - - self.mimeType = [response MIMEType]; - self.targetFileHandle = nil; - - // required for iOS 4.3, for some reason; response is - // a plain NSURLResponse, not the HTTP subclass - if ([response isKindOfClass:[NSHTTPURLResponse class]]) { - NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; - - self.responseCode = [httpResponse statusCode]; - self.bytesExpected = [response expectedContentLength]; - if ((self.direction == CDV_TRANSFER_DOWNLOAD) && (self.responseCode == 200) && (self.bytesExpected == NSURLResponseUnknownLength)) { - // Kick off HEAD request to server to get real length - // bytesExpected will be updated when that response is returned - self.entityLengthRequest = [[CDVFileTransferEntityLengthRequest alloc] initWithOriginalRequest:connection.currentRequest andDelegate:self]; - } - } else if ([response.URL isFileURL]) { - NSDictionary* attr = [[NSFileManager defaultManager] attributesOfItemAtPath:[response.URL path] error:nil]; - self.responseCode = 200; - self.bytesExpected = [attr[NSFileSize] longLongValue]; - } else { - self.responseCode = 200; - self.bytesExpected = NSURLResponseUnknownLength; - } - if ((self.direction == CDV_TRANSFER_DOWNLOAD) && (self.responseCode >= 200) && (self.responseCode < 300)) { - // Download response is okay; begin streaming output to file - NSString* parentPath = [self.target stringByDeletingLastPathComponent]; - - // create parent directories if needed - if ([[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:&error] == NO) { - if (error) { - [self cancelTransferWithError:connection errorMessage:[NSString stringWithFormat:@"Could not create path to save downloaded file: %@", [error localizedDescription]]]; - } else { - [self cancelTransferWithError:connection errorMessage:@"Could not create path to save downloaded file"]; - } - return; - } - // create target file - if ([[NSFileManager defaultManager] createFileAtPath:self.target contents:nil attributes:nil] == NO) { - [self cancelTransferWithError:connection errorMessage:@"Could not create target file"]; - return; - } - // open target file for writing - self.targetFileHandle = [NSFileHandle fileHandleForWritingAtPath:self.target]; - if (self.targetFileHandle == nil) { - [self cancelTransferWithError:connection errorMessage:@"Could not open target file for writing"]; - } - DLog(@"Streaming to file %@", target); - } -} - -- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error -{ - NSString* body = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:body]]; - - NSLog(@"File Transfer Error: %@", [error localizedDescription]); - - // remove connection for activeTransfers - [command.activeTransfers removeObjectForKey:objectId]; - [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; -} - -- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data -{ - self.bytesTransfered += data.length; - if (self.targetFileHandle) { - [self.targetFileHandle writeData:data]; - } else { - [self.responseData appendData:data]; - } - [self updateProgress]; -} - -- (void)updateBytesExpected:(NSInteger)newBytesExpected -{ - DLog(@"Updating bytesExpected to %d", newBytesExpected); - self.bytesExpected = newBytesExpected; - [self updateProgress]; -} - -- (void)updateProgress -{ - if (self.direction == CDV_TRANSFER_DOWNLOAD) { - BOOL lengthComputable = (self.bytesExpected != NSURLResponseUnknownLength); - // If the response is GZipped, and we have an outstanding HEAD request to get - // the length, then hold off on sending progress events. - if (!lengthComputable && (self.entityLengthRequest != nil)) { - return; - } - NSMutableDictionary* downloadProgress = [NSMutableDictionary dictionaryWithCapacity:3]; - [downloadProgress setObject:[NSNumber numberWithBool:lengthComputable] forKey:@"lengthComputable"]; - [downloadProgress setObject:[NSNumber numberWithInt:self.bytesTransfered] forKey:@"loaded"]; - [downloadProgress setObject:[NSNumber numberWithInt:self.bytesExpected] forKey:@"total"]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:downloadProgress]; - [result setKeepCallbackAsBool:true]; - [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; - } -} - -- (void)connection:(NSURLConnection*)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite -{ - if (self.direction == CDV_TRANSFER_UPLOAD) { - NSMutableDictionary* uploadProgress = [NSMutableDictionary dictionaryWithCapacity:3]; - - [uploadProgress setObject:[NSNumber numberWithBool:true] forKey:@"lengthComputable"]; - [uploadProgress setObject:[NSNumber numberWithInt:totalBytesWritten] forKey:@"loaded"]; - [uploadProgress setObject:[NSNumber numberWithInt:totalBytesExpectedToWrite] forKey:@"total"]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:uploadProgress]; - [result setKeepCallbackAsBool:true]; - [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - self.bytesTransfered = totalBytesWritten; -} - -// for self signed certificates -- (void)connection:(NSURLConnection*)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge*)challenge -{ - if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { - if (self.trustAllHosts) { - NSURLCredential* credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; - [challenge.sender useCredential:credential forAuthenticationChallenge:challenge]; - } - [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; - } else { - [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge]; - } -} - -- (id)init -{ - if ((self = [super init])) { - self.responseData = [NSMutableData data]; - self.targetFileHandle = nil; - } - return self; -} - -@end; diff --git a/CordovaLib/Classes/CDVGlobalization.h b/CordovaLib/Classes/CDVGlobalization.h deleted file mode 100755 index 0384656..0000000 --- a/CordovaLib/Classes/CDVGlobalization.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - 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 -#import "CDVPlugin.h" - -#define CDV_FORMAT_SHORT 0 -#define CDV_FORMAT_MEDIUM 1 -#define CDV_FORMAT_LONG 2 -#define CDV_FORMAT_FULL 3 -#define CDV_SELECTOR_MONTHS 0 -#define CDV_SELECTOR_DAYS 1 - -enum CDVGlobalizationError { - CDV_UNKNOWN_ERROR = 0, - CDV_FORMATTING_ERROR = 1, - CDV_PARSING_ERROR = 2, - CDV_PATTERN_ERROR = 3, -}; -typedef NSUInteger CDVGlobalizationError; - -@interface CDVGlobalization : CDVPlugin { - CFLocaleRef currentLocale; -} - -- (void)getPreferredLanguage:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns the string identifier for the clients current locale setting. - * It returns the locale identifier string to the successCB callback with a - * properties object as a parameter. If there is an error getting the locale, - * then the errorCB callback is invoked. - */ -- (void)getLocaleName:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns a date formatted as a string according to the clients user preferences and - * calendar using the time zone of the client. It returns the formatted date string to the - * successCB callback with a properties object as a parameter. If there is an error - * formatting the date, then the errorCB callback is invoked. - * - * options: "date" contains the number of milliseconds that represents the JavaScript date - */ -- (void)dateToString:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Parses a date formatted as a string according to the clients user - * preferences and calendar using the time zone of the client and returns - * the corresponding date object. It returns the date to the successCB - * callback with a properties object as a parameter. If there is an error - * parsing the date string, then the errorCB callback is invoked. - * - * options: "dateString" contains the JavaScript string to parse for a date - */ -- (void)stringToDate:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns a pattern string for formatting and parsing dates according to the clients - * user preferences. It returns the pattern to the successCB callback with a - * properties object as a parameter. If there is an error obtaining the pattern, - * then the errorCB callback is invoked. - * - */ -- (void)getDatePattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns an array of either the names of the months or days of the week - * according to the clients user preferences and calendar. It returns the array of names to the - * successCB callback with a properties object as a parameter. If there is an error obtaining the - * names, then the errorCB callback is invoked. - * - */ -- (void)getDateNames:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns whether daylight savings time is in effect for a given date using the clients - * time zone and calendar. It returns whether or not daylight savings time is in effect - * to the successCB callback with a properties object as a parameter. If there is an error - * reading the date, then the errorCB callback is invoked. - * - * options: "date" contains the number of milliseconds that represents the JavaScript date - * - */ -- (void)isDayLightSavingsTime:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns the first day of the week according to the clients user preferences and calendar. - * The days of the week are numbered starting from 1 where 1 is considered to be Sunday. - * It returns the day to the successCB callback with a properties object as a parameter. - * If there is an error obtaining the pattern, then the errorCB callback is invoked. - * - */ -- (void)getFirstDayOfWeek:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns a number formatted as a string according to the clients user preferences. - * It returns the formatted number string to the successCB callback with a properties object as a - * parameter. If there is an error formatting the number, then the errorCB callback is invoked. - * - * options: "number" contains the JavaScript number to format - * - */ -- (void)numberToString:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Parses a number formatted as a string according to the clients user preferences and - * returns the corresponding number. It returns the number to the successCB callback with a - * properties object as a parameter. If there is an error parsing the number string, then - * the errorCB callback is invoked. - * - * options: "numberString" contains the JavaScript string to parse for a number - * - */ -- (void)stringToNumber:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns a pattern string for formatting and parsing numbers according to the clients user - * preferences. It returns the pattern to the successCB callback with a properties object as a - * parameter. If there is an error obtaining the pattern, then the errorCB callback is invoked. - * - */ -- (void)getNumberPattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Returns a pattern string for formatting and parsing currency values according to the clients - * user preferences and ISO 4217 currency code. It returns the pattern to the successCB callback with a - * properties object as a parameter. If there is an error obtaining the pattern, then the errorCB - * callback is invoked. - * - * options: "currencyCode" contains the ISO currency code from JavaScript - */ -- (void)getCurrencyPattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -@end diff --git a/CordovaLib/Classes/CDVGlobalization.m b/CordovaLib/Classes/CDVGlobalization.m deleted file mode 100755 index 9eb9721..0000000 --- a/CordovaLib/Classes/CDVGlobalization.m +++ /dev/null @@ -1,790 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVGlobalization.h" - -@implementation CDVGlobalization - -- (id)initWithWebView:(UIWebView*)theWebView -{ - self = (CDVGlobalization*)[super initWithWebView:theWebView]; - if (self) { - currentLocale = CFLocaleCopyCurrent(); - } - return self; -} - -- (void)getPreferredLanguage:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - NSString* callbackId = [arguments objectAtIndex:0]; - CDVPluginResult* result = nil; - - NSLog(@"log1"); - // Source: http://stackoverflow.com/questions/3910244/getting-current-device-language-in-ios - // (should be OK) - NSString* language = [[NSLocale preferredLanguages] objectAtIndex:0]; - - if (language) { - NSDictionary* dictionary = [NSDictionary dictionaryWithObject:language forKey:@"value"]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK - messageAsDictionary:dictionary]; - } else { - // TBD is this ever expected to happen? - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unknown error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; -} - -- (void)getLocaleName:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CDVPluginResult* result = nil; - NSString* callbackId = [arguments objectAtIndex:0]; - NSDictionary* dictionary = nil; - - NSLocale* locale = [NSLocale currentLocale]; - - if (locale) { - dictionary = [NSDictionary dictionaryWithObject:[locale localeIdentifier] forKey:@"value"]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } else { - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unknown error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; -} - -- (void)dateToString:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CFDateFormatterStyle style = kCFDateFormatterShortStyle; - CFDateFormatterStyle dateStyle = kCFDateFormatterShortStyle; - CFDateFormatterStyle timeStyle = kCFDateFormatterShortStyle; - NSDate* date = nil; - NSString* dateString = nil; - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - - id milliseconds = [options valueForKey:@"date"]; - - if (milliseconds && [milliseconds isKindOfClass:[NSNumber class]]) { - // get the number of seconds since 1970 and create the date object - date = [NSDate dateWithTimeIntervalSince1970:[milliseconds doubleValue] / 1000]; - } - - // see if any options have been specified - id items = [options valueForKey:@"options"]; - if (items && [items isKindOfClass:[NSMutableDictionary class]]) { - NSEnumerator* enumerator = [items keyEnumerator]; - id key; - - // iterate through all the options - while ((key = [enumerator nextObject])) { - id item = [items valueForKey:key]; - - // make sure that only string values are present - if ([item isKindOfClass:[NSString class]]) { - // get the desired format length - if ([key isEqualToString:@"formatLength"]) { - if ([item isEqualToString:@"short"]) { - style = kCFDateFormatterShortStyle; - } else if ([item isEqualToString:@"medium"]) { - style = kCFDateFormatterMediumStyle; - } else if ([item isEqualToString:@"long"]) { - style = kCFDateFormatterLongStyle; - } else if ([item isEqualToString:@"full"]) { - style = kCFDateFormatterFullStyle; - } - } - // get the type of date and time to generate - else if ([key isEqualToString:@"selector"]) { - if ([item isEqualToString:@"date"]) { - dateStyle = style; - timeStyle = kCFDateFormatterNoStyle; - } else if ([item isEqualToString:@"time"]) { - dateStyle = kCFDateFormatterNoStyle; - timeStyle = style; - } else if ([item isEqualToString:@"date and time"]) { - dateStyle = style; - timeStyle = style; - } - } - } - } - } - - // create the formatter using the user's current default locale and formats for dates and times - CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault, - currentLocale, - dateStyle, - timeStyle); - // if we have a valid date object then call the formatter - if (date) { - dateString = (__bridge_transfer NSString*)CFDateFormatterCreateStringWithDate(kCFAllocatorDefault, - formatter, - (__bridge CFDateRef)date); - } - - // if the date was converted to a string successfully then return the result - if (dateString) { - NSDictionary* dictionary = [NSDictionary dictionaryWithObject:dateString forKey:@"value"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - // DLog(@"GlobalizationCommand dateToString unable to format %@", [date description]); - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_FORMATTING_ERROR] forKey:@"code"]; - [dictionary setValue:@"Formatting error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; - - CFRelease(formatter); -} - -- (void)stringToDate:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CFDateFormatterStyle style = kCFDateFormatterShortStyle; - CFDateFormatterStyle dateStyle = kCFDateFormatterShortStyle; - CFDateFormatterStyle timeStyle = kCFDateFormatterShortStyle; - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - NSString* dateString = nil; - NSDateComponents* comps = nil; - - // get the string that is to be parsed for a date - id ms = [options valueForKey:@"dateString"]; - - if (ms && [ms isKindOfClass:[NSString class]]) { - dateString = ms; - } - - // see if any options have been specified - id items = [options valueForKey:@"options"]; - if (items && [items isKindOfClass:[NSMutableDictionary class]]) { - NSEnumerator* enumerator = [items keyEnumerator]; - id key; - - // iterate through all the options - while ((key = [enumerator nextObject])) { - id item = [items valueForKey:key]; - - // make sure that only string values are present - if ([item isKindOfClass:[NSString class]]) { - // get the desired format length - if ([key isEqualToString:@"formatLength"]) { - if ([item isEqualToString:@"short"]) { - style = kCFDateFormatterShortStyle; - } else if ([item isEqualToString:@"medium"]) { - style = kCFDateFormatterMediumStyle; - } else if ([item isEqualToString:@"long"]) { - style = kCFDateFormatterLongStyle; - } else if ([item isEqualToString:@"full"]) { - style = kCFDateFormatterFullStyle; - } - } - // get the type of date and time to generate - else if ([key isEqualToString:@"selector"]) { - if ([item isEqualToString:@"date"]) { - dateStyle = style; - timeStyle = kCFDateFormatterNoStyle; - } else if ([item isEqualToString:@"time"]) { - dateStyle = kCFDateFormatterNoStyle; - timeStyle = style; - } else if ([item isEqualToString:@"date and time"]) { - dateStyle = style; - timeStyle = style; - } - } - } - } - } - - // get the user's default settings for date and time formats - CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault, - currentLocale, - dateStyle, - timeStyle); - - // set the parsing to be more lenient - CFDateFormatterSetProperty(formatter, kCFDateFormatterIsLenient, kCFBooleanTrue); - - // parse tha date and time string - CFDateRef date = CFDateFormatterCreateDateFromString(kCFAllocatorDefault, - formatter, - (__bridge CFStringRef)dateString, - NULL); - - // if we were able to parse the date then get the date and time components - if (date != NULL) { - NSCalendar* calendar = [NSCalendar currentCalendar]; - - unsigned unitFlags = NSYearCalendarUnit | - NSMonthCalendarUnit | - NSDayCalendarUnit | - NSHourCalendarUnit | - NSMinuteCalendarUnit | - NSSecondCalendarUnit; - - comps = [calendar components:unitFlags fromDate:(__bridge NSDate*)date]; - CFRelease(date); - } - - // put the various elements of the date and time into a dictionary - if (comps != nil) { - NSArray* keys = [NSArray arrayWithObjects:@"year", @"month", @"day", @"hour", @"minute", @"second", @"millisecond", nil]; - NSArray* values = [NSArray arrayWithObjects:[NSNumber numberWithInt:[comps year]], - [NSNumber numberWithInt:[comps month] - 1], - [NSNumber numberWithInt:[comps day]], - [NSNumber numberWithInt:[comps hour]], - [NSNumber numberWithInt:[comps minute]], - [NSNumber numberWithInt:[comps second]], - [NSNumber numberWithInt:0], /* iOS does not provide milliseconds */ - nil]; - - NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - // Dlog(@"GlobalizationCommand stringToDate unable to parse %@", dateString); - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_PARSING_ERROR] forKey:@"code"]; - [dictionary setValue:@"unable to parse" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; - - CFRelease(formatter); -} - -- (void)getDatePattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CFDateFormatterStyle style = kCFDateFormatterShortStyle; - CFDateFormatterStyle dateStyle = kCFDateFormatterShortStyle; - CFDateFormatterStyle timeStyle = kCFDateFormatterShortStyle; - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - - // see if any options have been specified - id items = [options valueForKey:@"options"]; - - if (items && [items isKindOfClass:[NSMutableDictionary class]]) { - NSEnumerator* enumerator = [items keyEnumerator]; - id key; - - // iterate through all the options - while ((key = [enumerator nextObject])) { - id item = [items valueForKey:key]; - - // make sure that only string values are present - if ([item isKindOfClass:[NSString class]]) { - // get the desired format length - if ([key isEqualToString:@"formatLength"]) { - if ([item isEqualToString:@"short"]) { - style = kCFDateFormatterShortStyle; - } else if ([item isEqualToString:@"medium"]) { - style = kCFDateFormatterMediumStyle; - } else if ([item isEqualToString:@"long"]) { - style = kCFDateFormatterLongStyle; - } else if ([item isEqualToString:@"full"]) { - style = kCFDateFormatterFullStyle; - } - } - // get the type of date and time to generate - else if ([key isEqualToString:@"selector"]) { - if ([item isEqualToString:@"date"]) { - dateStyle = style; - timeStyle = kCFDateFormatterNoStyle; - } else if ([item isEqualToString:@"time"]) { - dateStyle = kCFDateFormatterNoStyle; - timeStyle = style; - } else if ([item isEqualToString:@"date and time"]) { - dateStyle = style; - timeStyle = style; - } - } - } - } - } - - // get the user's default settings for date and time formats - CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault, - currentLocale, - dateStyle, - timeStyle); - - // get the date pattern to apply when formatting and parsing - CFStringRef datePattern = CFDateFormatterGetFormat(formatter); - // get the user's current time zone information - CFTimeZoneRef timezone = (CFTimeZoneRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterTimeZone); - - // put the pattern and time zone information into the dictionary - if ((datePattern != nil) && (timezone != nil)) { - NSArray* keys = [NSArray arrayWithObjects:@"pattern", @"timezone", @"utc_offset", @"dst_offset", nil]; - NSArray* values = [NSArray arrayWithObjects:((__bridge NSString*)datePattern), - [((__bridge NSTimeZone*)timezone)abbreviation], - [NSNumber numberWithLong:[((__bridge NSTimeZone*)timezone)secondsFromGMT]], - [NSNumber numberWithDouble:[((__bridge NSTimeZone*)timezone)daylightSavingTimeOffset]], - nil]; - - NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_PATTERN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Pattern error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; - - if (timezone) { - CFRelease(timezone); - } - CFRelease(formatter); -} - -- (void)getDateNames:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - int style = CDV_FORMAT_LONG; - int selector = CDV_SELECTOR_MONTHS; - CFStringRef dataStyle = kCFDateFormatterMonthSymbols; - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - - // see if any options have been specified - id items = [options valueForKey:@"options"]; - - if (items && [items isKindOfClass:[NSMutableDictionary class]]) { - NSEnumerator* enumerator = [items keyEnumerator]; - id key; - - // iterate through all the options - while ((key = [enumerator nextObject])) { - id item = [items valueForKey:key]; - - // make sure that only string values are present - if ([item isKindOfClass:[NSString class]]) { - // get the desired type of name - if ([key isEqualToString:@"type"]) { - if ([item isEqualToString:@"narrow"]) { - style = CDV_FORMAT_SHORT; - } else if ([item isEqualToString:@"wide"]) { - style = CDV_FORMAT_LONG; - } - } - // determine if months or days are needed - else if ([key isEqualToString:@"item"]) { - if ([item isEqualToString:@"months"]) { - selector = CDV_SELECTOR_MONTHS; - } else if ([item isEqualToString:@"days"]) { - selector = CDV_SELECTOR_DAYS; - } - } - } - } - } - - CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault, - currentLocale, - kCFDateFormatterFullStyle, - kCFDateFormatterFullStyle); - - if ((selector == CDV_SELECTOR_MONTHS) && (style == CDV_FORMAT_LONG)) { - dataStyle = kCFDateFormatterMonthSymbols; - } else if ((selector == CDV_SELECTOR_MONTHS) && (style == CDV_FORMAT_SHORT)) { - dataStyle = kCFDateFormatterShortMonthSymbols; - } else if ((selector == CDV_SELECTOR_DAYS) && (style == CDV_FORMAT_LONG)) { - dataStyle = kCFDateFormatterWeekdaySymbols; - } else if ((selector == CDV_SELECTOR_DAYS) && (style == CDV_FORMAT_SHORT)) { - dataStyle = kCFDateFormatterShortWeekdaySymbols; - } - - CFArrayRef names = (CFArrayRef)CFDateFormatterCopyProperty(formatter, dataStyle); - - if (names) { - NSDictionary* dictionary = [NSDictionary dictionaryWithObject:((__bridge NSArray*)names) forKey:@"value"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - CFRelease(names); - } - // error - else { - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unknown error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; - - CFRelease(formatter); -} - -- (void)isDayLightSavingsTime:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - NSDate* date = nil; - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - - id milliseconds = [options valueForKey:@"date"]; - - if (milliseconds && [milliseconds isKindOfClass:[NSNumber class]]) { - // get the number of seconds since 1970 and create the date object - date = [NSDate dateWithTimeIntervalSince1970:[milliseconds doubleValue] / 1000]; - } - - if (date) { - // get the current calendar for the user and check if the date is using DST - NSCalendar* calendar = [NSCalendar currentCalendar]; - NSTimeZone* timezone = [calendar timeZone]; - NSNumber* dst = [NSNumber numberWithBool:[timezone isDaylightSavingTimeForDate:date]]; - - NSDictionary* dictionary = [NSDictionary dictionaryWithObject:dst forKey:@"dst"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unknown error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; -} - -- (void)getFirstDayOfWeek:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - - NSCalendar* calendar = [NSCalendar autoupdatingCurrentCalendar]; - - NSNumber* day = [NSNumber numberWithInt:[calendar firstWeekday]]; - - if (day) { - NSDictionary* dictionary = [NSDictionary dictionaryWithObject:day forKey:@"value"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_UNKNOWN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unknown error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; -} - -- (void)numberToString:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - CFNumberFormatterStyle style = kCFNumberFormatterDecimalStyle; - NSNumber* number = nil; - - id value = [options valueForKey:@"number"]; - - if (value && [value isKindOfClass:[NSNumber class]]) { - number = (NSNumber*)value; - } - - // see if any options have been specified - id items = [options valueForKey:@"options"]; - if (items && [items isKindOfClass:[NSMutableDictionary class]]) { - NSEnumerator* enumerator = [items keyEnumerator]; - id key; - - // iterate through all the options - while ((key = [enumerator nextObject])) { - id item = [items valueForKey:key]; - - // make sure that only string values are present - if ([item isKindOfClass:[NSString class]]) { - // get the desired style of formatting - if ([key isEqualToString:@"type"]) { - if ([item isEqualToString:@"percent"]) { - style = kCFNumberFormatterPercentStyle; - } else if ([item isEqualToString:@"currency"]) { - style = kCFNumberFormatterCurrencyStyle; - } else if ([item isEqualToString:@"decimal"]) { - style = kCFNumberFormatterDecimalStyle; - } - } - } - } - } - - CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault, - currentLocale, - style); - - // get the localized string based upon the locale and user preferences - NSString* numberString = (__bridge_transfer NSString*)CFNumberFormatterCreateStringWithNumber(kCFAllocatorDefault, - formatter, - (__bridge CFNumberRef)number); - - if (numberString) { - NSDictionary* dictionary = [NSDictionary dictionaryWithObject:numberString forKey:@"value"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - // DLog(@"GlobalizationCommand numberToString unable to format %@", [number stringValue]); - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_FORMATTING_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unable to format" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; - - CFRelease(formatter); -} - -- (void)stringToNumber:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - CFNumberFormatterStyle style = kCFNumberFormatterDecimalStyle; - NSString* numberString = nil; - double doubleValue; - - id value = [options valueForKey:@"numberString"]; - - if (value && [value isKindOfClass:[NSString class]]) { - numberString = (NSString*)value; - } - - // see if any options have been specified - id items = [options valueForKey:@"options"]; - if (items && [items isKindOfClass:[NSMutableDictionary class]]) { - NSEnumerator* enumerator = [items keyEnumerator]; - id key; - - // iterate through all the options - while ((key = [enumerator nextObject])) { - id item = [items valueForKey:key]; - - // make sure that only string values are present - if ([item isKindOfClass:[NSString class]]) { - // get the desired style of formatting - if ([key isEqualToString:@"type"]) { - if ([item isEqualToString:@"percent"]) { - style = kCFNumberFormatterPercentStyle; - } else if ([item isEqualToString:@"currency"]) { - style = kCFNumberFormatterCurrencyStyle; - } else if ([item isEqualToString:@"decimal"]) { - style = kCFNumberFormatterDecimalStyle; - } - } - } - } - } - - CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault, - currentLocale, - style); - - // we need to make this lenient so as to avoid problems with parsing currencies that have non-breaking space characters - if (style == kCFNumberFormatterCurrencyStyle) { - CFNumberFormatterSetProperty(formatter, kCFNumberFormatterIsLenient, kCFBooleanTrue); - } - - // parse againist the largest type to avoid data loss - Boolean rc = CFNumberFormatterGetValueFromString(formatter, - (__bridge CFStringRef)numberString, - NULL, - kCFNumberDoubleType, - &doubleValue); - - if (rc) { - NSDictionary* dictionary = [NSDictionary dictionaryWithObject:[NSNumber numberWithDouble:doubleValue] forKey:@"value"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - // DLog(@"GlobalizationCommand stringToNumber unable to parse %@", numberString); - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_PARSING_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unable to parse" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; - - CFRelease(formatter); -} - -- (void)getNumberPattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - CFNumberFormatterStyle style = kCFNumberFormatterDecimalStyle; - CFStringRef symbolType = NULL; - NSString* symbol = @""; - - // see if any options have been specified - id items = [options valueForKey:@"options"]; - - if (items && [items isKindOfClass:[NSMutableDictionary class]]) { - NSEnumerator* enumerator = [items keyEnumerator]; - id key; - - // iterate through all the options - while ((key = [enumerator nextObject])) { - id item = [items valueForKey:key]; - - // make sure that only string values are present - if ([item isKindOfClass:[NSString class]]) { - // get the desired style of formatting - if ([key isEqualToString:@"type"]) { - if ([item isEqualToString:@"percent"]) { - style = kCFNumberFormatterPercentStyle; - } else if ([item isEqualToString:@"currency"]) { - style = kCFNumberFormatterCurrencyStyle; - } else if ([item isEqualToString:@"decimal"]) { - style = kCFNumberFormatterDecimalStyle; - } - } - } - } - } - - CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault, - currentLocale, - style); - - NSString* numberPattern = (__bridge NSString*)CFNumberFormatterGetFormat(formatter); - - if (style == kCFNumberFormatterCurrencyStyle) { - symbolType = kCFNumberFormatterCurrencySymbol; - } else if (style == kCFNumberFormatterPercentStyle) { - symbolType = kCFNumberFormatterPercentSymbol; - } - - if (symbolType) { - symbol = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, symbolType); - } - - NSString* decimal = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterDecimalSeparator); - NSString* grouping = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterGroupingSeparator); - NSString* posSign = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterPlusSign); - NSString* negSign = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterMinusSign); - NSNumber* fracDigits = (__bridge_transfer NSNumber*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterMinFractionDigits); - NSNumber* roundingDigits = (__bridge_transfer NSNumber*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterRoundingIncrement); - - // put the pattern information into the dictionary - if (numberPattern != nil) { - NSArray* keys = [NSArray arrayWithObjects:@"pattern", @"symbol", @"fraction", @"rounding", - @"positive", @"negative", @"decimal", @"grouping", nil]; - NSArray* values = [NSArray arrayWithObjects:numberPattern, symbol, fracDigits, roundingDigits, - posSign, negSign, decimal, grouping, nil]; - NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - } - // error - else { - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_PATTERN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Pattern error" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; - - CFRelease(formatter); -} - -- (void)getCurrencyPattern:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CDVPluginResult* result = nil; - NSString* callBackId = [arguments objectAtIndex:0]; - NSString* currencyCode = nil; - NSString* numberPattern = nil; - NSString* decimal = nil; - NSString* grouping = nil; - int32_t defaultFractionDigits; - double roundingIncrement; - Boolean rc; - - id value = [options valueForKey:@"currencyCode"]; - - if (value && [value isKindOfClass:[NSString class]]) { - currencyCode = (NSString*)value; - } - - // first see if there is base currency info available and fill in the currency_info structure - rc = CFNumberFormatterGetDecimalInfoForCurrencyCode((__bridge CFStringRef)currencyCode, &defaultFractionDigits, &roundingIncrement); - - // now set the currency code in the formatter - if (rc) { - CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault, - currentLocale, - kCFNumberFormatterCurrencyStyle); - - CFNumberFormatterSetProperty(formatter, kCFNumberFormatterCurrencyCode, (__bridge CFStringRef)currencyCode); - CFNumberFormatterSetProperty(formatter, kCFNumberFormatterInternationalCurrencySymbol, (__bridge CFStringRef)currencyCode); - - numberPattern = (__bridge NSString*)CFNumberFormatterGetFormat(formatter); - decimal = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterCurrencyDecimalSeparator); - grouping = (__bridge_transfer NSString*)CFNumberFormatterCopyProperty(formatter, kCFNumberFormatterCurrencyGroupingSeparator); - - NSArray* keys = [NSArray arrayWithObjects:@"pattern", @"code", @"fraction", @"rounding", - @"decimal", @"grouping", nil]; - NSArray* values = [NSArray arrayWithObjects:numberPattern, currencyCode, [NSNumber numberWithInt:defaultFractionDigits], - [NSNumber numberWithDouble:roundingIncrement], decimal, grouping, nil]; - NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary]; - CFRelease(formatter); - } - // error - else { - // DLog(@"GlobalizationCommand getCurrencyPattern unable to get pattern for %@", currencyCode); - NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; - [dictionary setValue:[NSNumber numberWithInt:CDV_PATTERN_ERROR] forKey:@"code"]; - [dictionary setValue:@"Unable to get pattern" forKey:@"message"]; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary]; - } - - [self.commandDelegate sendPluginResult:result callbackId:callBackId]; -} - -- (void)dealloc -{ - if (currentLocale) { - CFRelease(currentLocale); - currentLocale = nil; - } -} - -@end diff --git a/CordovaLib/Classes/CDVInAppBrowser.h b/CordovaLib/Classes/CDVInAppBrowser.h deleted file mode 100755 index 765326a..0000000 --- a/CordovaLib/Classes/CDVInAppBrowser.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - 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" -#import "CDVWebViewDelegate.h" - -@class CDVInAppBrowserViewController; - -@interface CDVInAppBrowser : CDVPlugin { - BOOL _injectedIframeBridge; -} - -@property (nonatomic, retain) CDVInAppBrowserViewController* inAppBrowserViewController; -@property (nonatomic, copy) NSString* callbackId; - -- (void)open:(CDVInvokedUrlCommand*)command; -- (void)close:(CDVInvokedUrlCommand*)command; -- (void)injectScriptCode:(CDVInvokedUrlCommand*)command; - -@end - -@interface CDVInAppBrowserViewController : UIViewController { - @private - NSString* _userAgent; - NSString* _prevUserAgent; - NSInteger _userAgentLockToken; - CDVWebViewDelegate* _webViewDelegate; -} - -@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) CDVInAppBrowser* navigationDelegate; -@property (nonatomic) NSURL* currentURL; - -- (void)close; -- (void)navigateTo:(NSURL*)url; -- (void)showLocationBar:(BOOL)show; - -- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent; - -@end - -@interface CDVInAppBrowserOptions : NSObject {} - -@property (nonatomic, assign) BOOL location; -@property (nonatomic, copy) NSString* presentationstyle; -@property (nonatomic, copy) NSString* transitionstyle; - -@property (nonatomic, assign) BOOL enableviewportscale; -@property (nonatomic, assign) BOOL mediaplaybackrequiresuseraction; -@property (nonatomic, assign) BOOL allowinlinemediaplayback; -@property (nonatomic, assign) BOOL keyboarddisplayrequiresuseraction; -@property (nonatomic, assign) BOOL suppressesincrementalrendering; - -+ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options; - -@end diff --git a/CordovaLib/Classes/CDVInAppBrowser.m b/CordovaLib/Classes/CDVInAppBrowser.m deleted file mode 100755 index b03d1fe..0000000 --- a/CordovaLib/Classes/CDVInAppBrowser.m +++ /dev/null @@ -1,705 +0,0 @@ -/* - 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 "CDVUserAgentUtil.h" -#import "CDVJSON.h" - -#define kInAppBrowserTargetSelf @"_self" -#define kInAppBrowserTargetSystem @"_system" -#define kInAppBrowserTargetBlank @"_blank" - -#define TOOLBAR_HEIGHT 44.0 -#define LOCATIONBAR_HEIGHT 21.0 -#define FOOTER_HEIGHT ((TOOLBAR_HEIGHT) + (LOCATIONBAR_HEIGHT)) - -#pragma mark CDVInAppBrowser - -@implementation CDVInAppBrowser - -- (CDVInAppBrowser*)initWithWebView:(UIWebView*)theWebView -{ - self = [super initWithWebView:theWebView]; - if (self != nil) { - // your initialization here - } - - return self; -} - -- (void)onReset -{ - [self close:nil]; -} - -- (void)close:(CDVInvokedUrlCommand*)command -{ - if (self.inAppBrowserViewController != nil) { - [self.inAppBrowserViewController close]; - self.inAppBrowserViewController = nil; - } - - self.callbackId = nil; -} - -- (void)open:(CDVInvokedUrlCommand*)command -{ - CDVPluginResult* pluginResult; - - NSString* url = [command argumentAtIndex:0]; - NSString* target = [command argumentAtIndex:1 withDefault:kInAppBrowserTargetSelf]; - NSString* options = [command argumentAtIndex:2 withDefault:@"" andClass:[NSString class]]; - - self.callbackId = command.callbackId; - - if (url != nil) { - NSURL* baseUrl = [self.webView.request URL]; - NSURL* absoluteUrl = [[NSURL URLWithString:url relativeToURL:baseUrl] absoluteURL]; - if ([target isEqualToString:kInAppBrowserTargetSelf]) { - [self openInCordovaWebView:absoluteUrl withOptions:options]; - } else if ([target isEqualToString:kInAppBrowserTargetSystem]) { - [self openInSystem:absoluteUrl]; - } else { // _blank or anything else - [self openInInAppBrowser:absoluteUrl withOptions:options]; - } - - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"incorrect number of arguments"]; - } - - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -- (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options -{ - if (self.inAppBrowserViewController == nil) { - NSString* originalUA = [CDVUserAgentUtil originalUserAgent]; - self.inAppBrowserViewController = [[CDVInAppBrowserViewController alloc] initWithUserAgent:originalUA prevUserAgent:[self.commandDelegate userAgent]]; - self.inAppBrowserViewController.navigationDelegate = self; - - if ([self.viewController conformsToProtocol:@protocol(CDVScreenOrientationDelegate)]) { - self.inAppBrowserViewController.orientationDelegate = (UIViewController *)self.viewController; - } - } - - CDVInAppBrowserOptions* browserOptions = [CDVInAppBrowserOptions parseOptions:options]; - [self.inAppBrowserViewController showLocationBar:browserOptions.location]; - - // Set Presentation Style - UIModalPresentationStyle presentationStyle = UIModalPresentationFullScreen; // default - if (browserOptions.presentationstyle != nil) { - if ([browserOptions.presentationstyle isEqualToString:@"pagesheet"]) { - presentationStyle = UIModalPresentationPageSheet; - } else if ([browserOptions.presentationstyle isEqualToString:@"formsheet"]) { - presentationStyle = UIModalPresentationFormSheet; - } - } - self.inAppBrowserViewController.modalPresentationStyle = presentationStyle; - - // Set Transition Style - UIModalTransitionStyle transitionStyle = UIModalTransitionStyleCoverVertical; // default - if (browserOptions.transitionstyle != nil) { - if ([browserOptions.transitionstyle isEqualToString:@"fliphorizontal"]) { - transitionStyle = UIModalTransitionStyleFlipHorizontal; - } else if ([browserOptions.transitionstyle isEqualToString:@"crossdissolve"]) { - transitionStyle = UIModalTransitionStyleCrossDissolve; - } - } - self.inAppBrowserViewController.modalTransitionStyle = transitionStyle; - - // UIWebView options - self.inAppBrowserViewController.webView.scalesPageToFit = browserOptions.enableviewportscale; - self.inAppBrowserViewController.webView.mediaPlaybackRequiresUserAction = browserOptions.mediaplaybackrequiresuseraction; - self.inAppBrowserViewController.webView.allowsInlineMediaPlayback = browserOptions.allowinlinemediaplayback; - if (IsAtLeastiOSVersion(@"6.0")) { - self.inAppBrowserViewController.webView.keyboardDisplayRequiresUserAction = browserOptions.keyboarddisplayrequiresuseraction; - self.inAppBrowserViewController.webView.suppressesIncrementalRendering = browserOptions.suppressesincrementalrendering; - } - - if (self.viewController.modalViewController != self.inAppBrowserViewController) { - [self.viewController presentModalViewController:self.inAppBrowserViewController animated:YES]; - } - [self.inAppBrowserViewController navigateTo:url]; -} - -- (void)openInCordovaWebView:(NSURL*)url withOptions:(NSString*)options -{ - if ([self.commandDelegate URLIsWhitelisted:url]) { - 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]]; - } -} - -// This is a helper method for the inject{Script|Style}{Code|File} API calls, which -// provides a consistent method for injecting JavaScript code into the document. -// -// If a wrapper string is supplied, then the source string will be JSON-encoded (adding -// quotes) and wrapped using string formatting. (The wrapper string should have a single -// '%@' marker). -// -// If no wrapper is supplied, then the source string is executed directly. - -- (void)injectDeferredObject:(NSString*)source withWrapper:(NSString*)jsWrapper -{ - if (!_injectedIframeBridge) { - _injectedIframeBridge = YES; - // Create an iframe bridge in the new document to communicate with the CDVInAppBrowserViewController - [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:@"(function(d){var e = _cdvIframeBridge = d.createElement('iframe');e.style.display='none';d.body.appendChild(e);})(document)"]; - } - - if (jsWrapper != nil) { - NSString* sourceArrayString = [@[source] JSONString]; - if (sourceArrayString) { - NSString* sourceString = [sourceArrayString substringWithRange:NSMakeRange(1, [sourceArrayString length] - 2)]; - NSString* jsToInject = [NSString stringWithFormat:jsWrapper, sourceString]; - [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:jsToInject]; - } - } else { - [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:source]; - } -} - -- (void)injectScriptCode:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper = nil; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"_cdvIframeBridge.src='gap-iab://%@/'+window.escape(JSON.stringify([eval(%%@)]));", command.callbackId]; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -- (void)injectScriptFile:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('script'); c.src = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId]; - } else { - jsWrapper = @"(function(d) { var c = d.createElement('script'); c.src = %@; d.body.appendChild(c); })(document)"; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -- (void)injectStyleCode:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('style'); c.innerHTML = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId]; - } else { - jsWrapper = @"(function(d) { var c = d.createElement('style'); c.innerHTML = %@; d.body.appendChild(c); })(document)"; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -- (void)injectStyleFile:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId]; - } else { - jsWrapper = @"(function(d) { var c = d.createElement('link'); c.rel='stylesheet', c.type='text/css'; c.href = %@; d.body.appendChild(c); })(document)"; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -/** - * The iframe bridge provided for the InAppBrowser is capable of executing any oustanding callback belonging - * to the InAppBrowser plugin. Care has been taken that other callbacks cannot be triggered, and that no - * other code execution is possible. - * - * To trigger the bridge, the iframe (or any other resource) should attempt to load a url of the form: - * - * gap-iab:/// - * - * where is the string id of the callback to trigger (something like "InAppBrowser0123456789") - * - * If present, the path component of the special gap-iab:// url is expected to be a URL-escaped JSON-encoded - * value to pass to the callback. [NSURL path] should take care of the URL-unescaping, and a JSON_EXCEPTION - * is returned if the JSON is invalid. - */ -- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType -{ - NSURL* url = request.URL; - BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]]; - - // See if the url uses the 'gap-iab' protocol. If so, the host should be the id of a callback to execute, - // and the path, if present, should be a JSON-encoded value to pass to the callback. - if ([[url scheme] isEqualToString:@"gap-iab"]) { - NSString* scriptCallbackId = [url host]; - CDVPluginResult* pluginResult = nil; - - if ([scriptCallbackId hasPrefix:@"InAppBrowser"]) { - NSString* scriptResult = [url path]; - NSError* __autoreleasing error = nil; - - // The message should be a JSON-encoded array of the result of the script which executed. - if ((scriptResult != nil) && ([scriptResult length] > 1)) { - scriptResult = [scriptResult substringFromIndex:1]; - NSData* decodedResult = [NSJSONSerialization JSONObjectWithData:[scriptResult dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; - if ((error == nil) && [decodedResult isKindOfClass:[NSArray class]]) { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:(NSArray*)decodedResult]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_JSON_EXCEPTION]; - } - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:@[]]; - } - [self.commandDelegate sendPluginResult:pluginResult callbackId:scriptCallbackId]; - return NO; - } - } else if ((self.callbackId != nil) && isTopLevelNavigation) { - // Send a loadstart event for each top-level navigation (includes redirects). - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK - messageAsDictionary:@{@"type":@"loadstart", @"url":[url absoluteString]}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } - - return YES; -} - -- (void)webViewDidStartLoad:(UIWebView*)theWebView -{ - _injectedIframeBridge = NO; -} - -- (void)webViewDidFinishLoad:(UIWebView*)theWebView -{ - if (self.callbackId != nil) { - // TODO: It would be more useful to return the URL the page is actually on (e.g. if it's been redirected). - NSString* url = [self.inAppBrowserViewController.currentURL absoluteString]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK - messageAsDictionary:@{@"type":@"loadstop", @"url":url}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } -} - -- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error -{ - if (self.callbackId != nil) { - NSString* url = [self.inAppBrowserViewController.currentURL absoluteString]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR - messageAsDictionary:@{@"type":@"loaderror", @"url":url, @"code": [NSNumber numberWithInt:error.code], @"message": error.localizedDescription}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } -} - -- (void)browserExit -{ - if (self.callbackId != nil) { - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK - messageAsDictionary:@{@"type":@"exit"}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } - // Don't recycle the ViewController since it may be consuming a lot of memory. - // Also - this is required for the PDF/User-Agent bug work-around. - self.inAppBrowserViewController = nil; -} - -@end - -#pragma mark CDVInAppBrowserViewController - -@implementation CDVInAppBrowserViewController - -@synthesize currentURL; - -- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent -{ - self = [super init]; - if (self != nil) { - _userAgent = userAgent; - _prevUserAgent = prevUserAgent; - _webViewDelegate = [[CDVWebViewDelegate alloc] initWithDelegate:self]; - [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; - - self.webView = [[UIWebView alloc] initWithFrame:webViewBounds]; - self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); - - [self.view addSubview:self.webView]; - [self.view sendSubviewToBack:self.webView]; - - self.webView.delegate = _webViewDelegate; - 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]; - [CDVUserAgentUtil releaseLock:&_userAgentLockToken]; - [super viewDidUnload]; -} - -- (void)close -{ - [CDVUserAgentUtil releaseLock:&_userAgentLockToken]; - - if ([self respondsToSelector:@selector(presentingViewController)]) { - [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[self parentViewController] dismissModalViewControllerAnimated:YES]; - } - - self.currentURL = nil; - - if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserExit)]) { - [self.navigationDelegate browserExit]; - } -} - -- (void)navigateTo:(NSURL*)url -{ - NSURLRequest* request = [NSURLRequest requestWithURL:url]; - - if (_userAgentLockToken != 0) { - [self.webView loadRequest:request]; - } else { - [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) { - _userAgentLockToken = lockToken; - [CDVUserAgentUtil setUserAgent:_userAgent lockToken:lockToken]; - [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]; - - return [self.navigationDelegate webViewDidStartLoad:theWebView]; -} - -- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType -{ - BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]]; - - if (isTopLevelNavigation) { - self.currentURL = request.URL; - } - return [self.navigationDelegate webView:theWebView shouldStartLoadWithRequest:request navigationType:navigationType]; -} - -- (void)webViewDidFinishLoad:(UIWebView*)theWebView -{ - // update url, stop spinner, update back/forward - - self.addressLabel.text = [self.currentURL absoluteString]; - self.backButton.enabled = theWebView.canGoBack; - self.forwardButton.enabled = theWebView.canGoForward; - - [self.spinner stopAnimating]; - - // Work around a bug where the first time a PDF is opened, all UIWebViews - // reload their User-Agent from NSUserDefaults. - // This work-around makes the following assumptions: - // 1. The app has only a single Cordova Webview. If not, then the app should - // take it upon themselves to load a PDF in the background as a part of - // their start-up flow. - // 2. That the PDF does not require any additional network requests. We change - // the user-agent here back to that of the CDVViewController, so requests - // from it must pass through its white-list. This *does* break PDFs that - // contain links to other remote PDF/websites. - // More info at https://issues.apache.org/jira/browse/CB-2225 - BOOL isPDF = [@"true" isEqualToString :[theWebView stringByEvaluatingJavaScriptFromString:@"document.body==null"]]; - if (isPDF) { - [CDVUserAgentUtil setUserAgent:_prevUserAgent lockToken:_userAgentLockToken]; - } - - [self.navigationDelegate webViewDidFinishLoad:theWebView]; -} - -- (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"; - - [self.navigationDelegate webView:theWebView didFailLoadWithError:error]; -} - -#pragma mark CDVScreenOrientationDelegate - -- (BOOL)shouldAutorotate -{ - if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotate)]) { - return [self.orientationDelegate shouldAutorotate]; - } - return YES; -} - -- (NSUInteger)supportedInterfaceOrientations -{ - if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(supportedInterfaceOrientations)]) { - return [self.orientationDelegate supportedInterfaceOrientations]; - } - - return 1 << UIInterfaceOrientationPortrait; -} - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) { - return [self.orientationDelegate shouldAutorotateToInterfaceOrientation:interfaceOrientation]; - } - - return YES; -} - -@end - -@implementation CDVInAppBrowserOptions - -- (id)init -{ - if (self = [super init]) { - // default values - self.location = YES; - - self.enableviewportscale = NO; - self.mediaplaybackrequiresuseraction = NO; - self.allowinlinemediaplayback = NO; - self.keyboarddisplayrequiresuseraction = YES; - self.suppressesincrementalrendering = NO; - } - - return self; -} - -+ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options -{ - CDVInAppBrowserOptions* obj = [[CDVInAppBrowserOptions alloc] init]; - - // NOTE: this parsing does not handle quotes within values - NSArray* pairs = [options componentsSeparatedByString:@","]; - - // parse keys and values, set the properties - for (NSString* pair in pairs) { - NSArray* keyvalue = [pair componentsSeparatedByString:@"="]; - - if ([keyvalue count] == 2) { - NSString* key = [[keyvalue objectAtIndex:0] lowercaseString]; - NSString* value = [[keyvalue objectAtIndex:1] lowercaseString]; - - BOOL isBoolean = [value isEqualToString:@"yes"] || [value isEqualToString:@"no"]; - NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init]; - [numberFormatter setAllowsFloats:YES]; - BOOL isNumber = [numberFormatter numberFromString:value] != nil; - - // set the property according to the key name - if ([obj respondsToSelector:NSSelectorFromString(key)]) { - if (isNumber) { - [obj setValue:[numberFormatter numberFromString:value] forKey:key]; - } else if (isBoolean) { - [obj setValue:[NSNumber numberWithBool:[value isEqualToString:@"yes"]] forKey:key]; - } else { - [obj setValue:value forKey:key]; - } - } - } - } - - return obj; -} - -@end diff --git a/CordovaLib/Classes/CDVJpegHeaderWriter.h b/CordovaLib/Classes/CDVJpegHeaderWriter.h deleted file mode 100755 index 3b43ef0..0000000 --- a/CordovaLib/Classes/CDVJpegHeaderWriter.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - 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 - -@interface CDVJpegHeaderWriter : NSObject { - NSDictionary * SubIFDTagFormatDict; - NSDictionary * IFD0TagFormatDict; -} - -- (NSData*) spliceExifBlockIntoJpeg: (NSData*) jpegdata - withExifBlock: (NSString*) exifstr; -- (NSString*) createExifAPP1 : (NSDictionary*) datadict; -- (NSString*) formattedHexStringFromDecimalNumber: (NSNumber*) numb - withPlaces: (NSNumber*) width; -- (NSString*) formatNumberWithLeadingZeroes: (NSNumber*) numb - withPlaces: (NSNumber*) places; -- (NSString*) decimalToUnsignedRational: (NSNumber*) numb - withResultNumerator: (NSNumber**) numerator - withResultDenominator: (NSNumber**) denominator; -- (void) continuedFraction: (double) val - withFractionList: (NSMutableArray*) fractionlist - withHorizon: (int) horizon; -//- (void) expandContinuedFraction: (NSArray*) fractionlist; -- (void) splitDouble: (double) val - withIntComponent: (int*) rightside - withFloatRemainder: (double*) leftside; -- (NSString*) formatRationalWithNumerator: (NSNumber*) numerator - withDenominator: (NSNumber*) denominator - asSigned: (Boolean) signedFlag; -- (NSString*) hexStringFromData : (NSData*) data; -- (NSNumber*) numericFromHexString : (NSString *) hexstring; - -/* -- (void) readExifMetaData : (NSData*) imgdata; -- (void) spliceImageData : (NSData*) imgdata withExifData: (NSDictionary*) exifdata; -- (void) locateExifMetaData : (NSData*) imgdata; -- (NSString*) createExifAPP1 : (NSDictionary*) datadict; -- (void) createExifDataString : (NSDictionary*) datadict; -- (NSString*) createDataElement : (NSString*) element - withElementData: (NSString*) data - withExternalDataBlock: (NSDictionary*) memblock; -- (NSString*) hexStringFromData : (NSData*) data; -- (NSNumber*) numericFromHexString : (NSString *) hexstring; -*/ -@end diff --git a/CordovaLib/Classes/CDVJpegHeaderWriter.m b/CordovaLib/Classes/CDVJpegHeaderWriter.m deleted file mode 100755 index 93cafb8..0000000 --- a/CordovaLib/Classes/CDVJpegHeaderWriter.m +++ /dev/null @@ -1,547 +0,0 @@ -/* - 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 "CDVJpegHeaderWriter.h" -#include "CDVExif.h" - -/* macros for tag info shorthand: - tagno : tag number - typecode : data type - components : number of components - appendString (TAGINF_W_APPEND only) : string to append to data - Exif date data format include an extra 0x00 to the end of the data - */ -#define TAGINF(tagno, typecode, components) [NSArray arrayWithObjects: tagno, typecode, components, nil] -#define TAGINF_W_APPEND(tagno, typecode, components, appendString) [NSArray arrayWithObjects: tagno, typecode, components, appendString, nil] - -const uint mJpegId = 0xffd8; // JPEG format marker -const uint mExifMarker = 0xffe1; // APP1 jpeg header marker -const uint mExif = 0x45786966; // ASCII 'Exif', first characters of valid exif header after size -const uint mMotorallaByteAlign = 0x4d4d; // 'MM', motorola byte align, msb first or 'sane' -const uint mIntelByteAlgin = 0x4949; // 'II', Intel byte align, lsb first or 'batshit crazy reverso world' -const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a(MM) or 0x2a00(II), tiff version number - - -@implementation CDVJpegHeaderWriter - -- (id) init { - self = [super init]; - // supported tags for exif IFD - IFD0TagFormatDict = [[NSDictionary alloc] initWithObjectsAndKeys: - // TAGINF(@"010e", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"ImageDescription", - TAGINF_W_APPEND(@"0132", [NSNumber numberWithInt:EDT_ASCII_STRING], @20, @"00"), @"DateTime", - TAGINF(@"010f", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Make", - TAGINF(@"0110", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Model", - TAGINF(@"0131", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Software", - TAGINF(@"011a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"XResolution", - TAGINF(@"011b", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"YResolution", - // currently supplied outside of Exif data block by UIImagePickerControllerMediaMetadata, this is set manually in CDVCamera.m - /* TAGINF(@"0112", [NSNumber numberWithInt:EDT_USHORT], @1), @"Orientation", - - // rest of the tags are supported by exif spec, but are not specified by UIImagePickerControllerMediaMedadata - // should camera hardware supply these values in future versions, or if they can be derived, ImageHeaderWriter will include them gracefully - TAGINF(@"0128", [NSNumber numberWithInt:EDT_USHORT], @1), @"ResolutionUnit", - TAGINF(@"013e", [NSNumber numberWithInt:EDT_URATIONAL], @2), @"WhitePoint", - TAGINF(@"013f", [NSNumber numberWithInt:EDT_URATIONAL], @6), @"PrimaryChromaticities", - TAGINF(@"0211", [NSNumber numberWithInt:EDT_URATIONAL], @3), @"YCbCrCoefficients", - TAGINF(@"0213", [NSNumber numberWithInt:EDT_USHORT], @1), @"YCbCrPositioning", - TAGINF(@"0214", [NSNumber numberWithInt:EDT_URATIONAL], @6), @"ReferenceBlackWhite", - TAGINF(@"8298", [NSNumber numberWithInt:EDT_URATIONAL], @0), @"Copyright", - - // offset to exif subifd, we determine this dynamically based on the size of the main exif IFD - TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1), @"ExifOffset",*/ - nil]; - - - // supported tages for exif subIFD - SubIFDTagFormatDict = [[NSDictionary alloc] initWithObjectsAndKeys: - //TAGINF(@"9000", [NSNumber numberWithInt:], @), @"ExifVersion", - //TAGINF(@"9202",[NSNumber numberWithInt:EDT_URATIONAL],@1), @"ApertureValue", - //TAGINF(@"9203",[NSNumber numberWithInt:EDT_SRATIONAL],@1), @"BrightnessValue", - TAGINF(@"a001",[NSNumber numberWithInt:EDT_USHORT],@1), @"ColorSpace", - TAGINF_W_APPEND(@"9004",[NSNumber numberWithInt:EDT_ASCII_STRING],@20,@"00"), @"DateTimeDigitized", - TAGINF_W_APPEND(@"9003",[NSNumber numberWithInt:EDT_ASCII_STRING],@20,@"00"), @"DateTimeOriginal", - TAGINF(@"a402", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureMode", - TAGINF(@"8822", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureProgram", - //TAGINF(@"829a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"ExposureTime", - //TAGINF(@"829d", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FNumber", - TAGINF(@"9209", [NSNumber numberWithInt:EDT_USHORT], @1), @"Flash", - // FocalLengthIn35mmFilm - TAGINF(@"a405", [NSNumber numberWithInt:EDT_USHORT], @1), @"FocalLenIn35mmFilm", - //TAGINF(@"920a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FocalLength", - //TAGINF(@"8827", [NSNumber numberWithInt:EDT_USHORT], @2), @"ISOSpeedRatings", - TAGINF(@"9207", [NSNumber numberWithInt:EDT_USHORT],@1), @"MeteringMode", - // specific to compressed data - TAGINF(@"a002", [NSNumber numberWithInt:EDT_ULONG],@1), @"PixelXDimension", - TAGINF(@"a003", [NSNumber numberWithInt:EDT_ULONG],@1), @"PixelYDimension", - // data type undefined, but this is a DSC camera, so value is always 1, treat as ushort - TAGINF(@"a301", [NSNumber numberWithInt:EDT_USHORT],@1), @"SceneType", - TAGINF(@"a217",[NSNumber numberWithInt:EDT_USHORT],@1), @"SensingMethod", - //TAGINF(@"9201", [NSNumber numberWithInt:EDT_SRATIONAL], @1), @"ShutterSpeedValue", - // specifies location of main subject in scene (x,y,wdith,height) expressed before rotation processing - //TAGINF(@"9214", [NSNumber numberWithInt:EDT_USHORT], @4), @"SubjectArea", - TAGINF(@"a403", [NSNumber numberWithInt:EDT_USHORT], @1), @"WhiteBalance", - nil]; - return self; -} - -- (NSData*) spliceExifBlockIntoJpeg: (NSData*) jpegdata withExifBlock: (NSString*) exifstr { - - CDVJpegHeaderWriter * exifWriter = [[CDVJpegHeaderWriter alloc] init]; - - NSMutableData * exifdata = [NSMutableData dataWithCapacity: [exifstr length]/2]; - int idx; - for (idx = 0; idx+1 < [exifstr length]; idx+=2) { - NSRange range = NSMakeRange(idx, 2); - NSString* hexStr = [exifstr substringWithRange:range]; - NSScanner* scanner = [NSScanner scannerWithString:hexStr]; - unsigned int intValue; - [scanner scanHexInt:&intValue]; - [exifdata appendBytes:&intValue length:1]; - } - - NSMutableData * ddata = [NSMutableData dataWithCapacity: [jpegdata length]]; - NSMakeRange(0,4); - int loc = 0; - bool done = false; - // read the jpeg data until we encounter the app1==0xFFE1 marker - while (loc+1 < [jpegdata length]) { - NSData * blag = [jpegdata subdataWithRange: NSMakeRange(loc,2)]; - if( [[blag description] isEqualToString : @""]) { - // read the APP1 block size bits - NSString * the = [exifWriter hexStringFromData:[jpegdata subdataWithRange: NSMakeRange(loc+2,2)]]; - NSNumber * app1width = [exifWriter numericFromHexString:the]; - //consume the original app1 block - [ddata appendData:exifdata]; - // advance our loc marker past app1 - loc += [app1width intValue] + 2; - done = true; - } else { - if(!done) { - [ddata appendData:blag]; - loc += 2; - } else { - break; - } - } - } - // copy the remaining data - [ddata appendData:[jpegdata subdataWithRange: NSMakeRange(loc,[jpegdata length]-loc)]]; - return ddata; -} - - - -/** - * Create the Exif data block as a hex string - * jpeg uses Application Markers (APP's) as markers for application data - * APP1 is the application marker reserved for exif data - * - * (NSDictionary*) datadict - with subdictionaries marked '{TIFF}' and '{EXIF}' as returned by imagePickerController with a valid - * didFinishPickingMediaWithInfo data dict, under key @"UIImagePickerControllerMediaMetadata" - * - * the following constructs a hex string to Exif specifications, and is therefore brittle - * altering the order of arguments to the string constructors, modifying field sizes or formats, - * and any other minor change will likely prevent the exif data from being read - */ -- (NSString*) createExifAPP1 : (NSDictionary*) datadict { - NSMutableString * app1; // holds finalized product - NSString * exifIFD; // exif information file directory - NSString * subExifIFD; // subexif information file directory - - // FFE1 is the hex APP1 marker code, and will allow client apps to read the data - NSString * app1marker = @"ffe1"; - // SSSS size, to be determined - // EXIF ascii characters followed by 2bytes of zeros - NSString * exifmarker = @"457869660000"; - // Tiff header: 4d4d is motorolla byte align (big endian), 002a is hex for 42 - NSString * tiffheader = @"4d4d002a"; - //first IFD offset from the Tiff header to IFD0. Since we are writing it, we know it's address 0x08 - NSString * ifd0offset = @"00000008"; - // current offset to next data area - int currentDataOffset = 0; - - //data labeled as TIFF in UIImagePickerControllerMediaMetaData is part of the EXIF IFD0 portion of APP1 - exifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{TIFF}"] withFormatDict: IFD0TagFormatDict isIFD0:YES currentDataOffset:¤tDataOffset]; - - //data labeled as EXIF in UIImagePickerControllerMediaMetaData is part of the EXIF Sub IFD portion of APP1 - subExifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{Exif}"] withFormatDict: SubIFDTagFormatDict isIFD0:NO currentDataOffset:¤tDataOffset]; - /* - NSLog(@"SUB EXIF IFD %@ WITH SIZE: %d",exifIFD,[exifIFD length]); - - NSLog(@"SUB EXIF IFD %@ WITH SIZE: %d",subExifIFD,[subExifIFD length]); - */ - // construct the complete app1 data block - app1 = [[NSMutableString alloc] initWithFormat: @"%@%04x%@%@%@%@%@", - app1marker, - 16 + ([exifIFD length]/2) + ([subExifIFD length]/2) /*16+[exifIFD length]/2*/, - exifmarker, - tiffheader, - ifd0offset, - exifIFD, - subExifIFD]; - - return app1; -} - -// returns hex string representing a valid exif information file directory constructed from the datadict and formatdict -- (NSString*) createExifIFDFromDict : (NSDictionary*) datadict - withFormatDict : (NSDictionary*) formatdict - isIFD0 : (BOOL) ifd0flag - currentDataOffset : (int*) dataoffset { - NSArray * datakeys = [datadict allKeys]; // all known data keys - NSArray * knownkeys = [formatdict allKeys]; // only keys in knowkeys are considered for entry in this IFD - NSMutableArray * ifdblock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // all ifd entries - NSMutableArray * ifddatablock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // data block entries - // ifd0flag = NO; // ifd0 requires a special flag and has offset to next ifd appended to end - - // iterate through known provided data keys - for (int i = 0; i < [datakeys count]; i++) { - NSString * key = [datakeys objectAtIndex:i]; - // don't muck about with unknown keys - if ([knownkeys indexOfObject: key] != NSNotFound) { - // create new IFD entry - NSString * entry = [self createIFDElement: key - withFormat: [formatdict objectForKey:key] - withElementData: [datadict objectForKey:key]]; - // create the IFD entry's data block - NSString * data = [self createIFDElementDataWithFormat: [formatdict objectForKey:key] - withData: [datadict objectForKey:key]]; - if (entry) { - [ifdblock addObject:entry]; - if(!data) { - [ifdblock addObject:@""]; - } else { - [ifddatablock addObject:data]; - } - } - } - } - - NSMutableString * exifstr = [[NSMutableString alloc] initWithCapacity: [ifdblock count] * 24]; - NSMutableString * dbstr = [[NSMutableString alloc] initWithCapacity: 100]; - - int addr=*dataoffset; // current offset/address in datablock - if (ifd0flag) { - // calculate offset to datablock based on ifd file entry count - addr += 14+(12*([ifddatablock count]+1)); // +1 for tag 0x8769, exifsubifd offset - } else { - // current offset + numSubIFDs (2-bytes) + 12*numSubIFDs + endMarker (4-bytes) - addr += 2+(12*[ifddatablock count])+4; - } - - for (int i = 0; i < [ifdblock count]; i++) { - NSString * entry = [ifdblock objectAtIndex:i]; - NSString * data = [ifddatablock objectAtIndex:i]; - - // check if the data fits into 4 bytes - if( [data length] <= 8) { - // concatenate the entry and the (4byte) data entry into the final IFD entry and append to exif ifd string - [exifstr appendFormat : @"%@%@", entry, data]; - } else { - [exifstr appendFormat : @"%@%08x", entry, addr]; - [dbstr appendFormat: @"%@", data]; - addr+= [data length] / 2; - /* - NSLog(@"=====data-length[%i]=======",[data length]); - NSLog(@"addr-offset[%i]",addr); - NSLog(@"entry[%@]",entry); - NSLog(@"data[%@]",data); - */ - } - } - - // calculate IFD0 terminal offset tags, currently ExifSubIFD - int entrycount = [ifdblock count]; - if (ifd0flag) { - // 18 accounts for 8769's width + offset to next ifd, 8 accounts for start of header - NSNumber * offset = [NSNumber numberWithInt:[exifstr length] / 2 + [dbstr length] / 2 + 18+8]; - - [self appendExifOffsetTagTo: exifstr - withOffset : offset]; - entrycount++; - } - *dataoffset = addr; - return [[NSString alloc] initWithFormat: @"%04x%@%@%@", - entrycount, - exifstr, - @"00000000", // offset to next IFD, 0 since there is none - dbstr]; // lastly, the datablock -} - -// Creates an exif formatted exif information file directory entry -- (NSString*) createIFDElement: (NSString*) elementName withFormat: (NSArray*) formtemplate withElementData: (NSString*) data { - //NSArray * fielddata = [formatdict objectForKey: elementName];// format data of desired field - if (formtemplate) { - // format string @"%@%@%@%@", tag number, data format, components, value - NSNumber * dataformat = [formtemplate objectAtIndex:1]; - NSNumber * components = [formtemplate objectAtIndex:2]; - if([components intValue] == 0) { - components = [NSNumber numberWithInt: [data length] * DataTypeToWidth[[dataformat intValue]-1]]; - } - - return [[NSString alloc] initWithFormat: @"%@%@%08x", - [formtemplate objectAtIndex:0], // the field code - [self formatNumberWithLeadingZeroes: dataformat withPlaces: @4], // the data type code - [components intValue]]; // number of components - } - return NULL; -} - -/** - * appends exif IFD0 tag 8769 "ExifOffset" to the string provided - * (NSMutableString*) str - string you wish to append the 8769 tag to: APP1 or IFD0 hex data string - * // TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1), @"ExifOffset", - */ -- (void) appendExifOffsetTagTo: (NSMutableString*) str withOffset : (NSNumber*) offset { - NSArray * format = TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1); - - NSString * entry = [self createIFDElement: @"ExifOffset" - withFormat: format - withElementData: [offset stringValue]]; - - NSString * data = [self createIFDElementDataWithFormat: format - withData: [offset stringValue]]; - [str appendFormat:@"%@%@", entry, data]; -} - -// formats the Information File Directory Data to exif format -- (NSString*) createIFDElementDataWithFormat: (NSArray*) dataformat withData: (NSString*) data { - NSMutableString * datastr = nil; - NSNumber * tmp = nil; - NSNumber * formatcode = [dataformat objectAtIndex:1]; - NSUInteger formatItemsCount = [dataformat count]; - NSNumber * num = @0; - NSNumber * denom = @0; - - switch ([formatcode intValue]) { - case EDT_UBYTE: - break; - case EDT_ASCII_STRING: - datastr = [[NSMutableString alloc] init]; - for (int i = 0; i < [data length]; i++) { - [datastr appendFormat:@"%02x",[data characterAtIndex:i]]; - } - if (formatItemsCount > 3) { - // We have additional data to append. - // currently used by Date format to append final 0x00 but can be used by other data types as well in the future - [datastr appendString:[dataformat objectAtIndex:3]]; - } - if ([datastr length] < 8) { - NSString * format = [NSString stringWithFormat:@"%%0%dd", 8 - [datastr length]]; - [datastr appendFormat:format,0]; - } - return datastr; - case EDT_USHORT: - return [[NSString alloc] initWithFormat : @"%@%@", - [self formattedHexStringFromDecimalNumber: [NSNumber numberWithInt: [data intValue]] withPlaces: @4], - @"0000"]; - case EDT_ULONG: - tmp = [NSNumber numberWithUnsignedLong:[data intValue]]; - return [NSString stringWithFormat : @"%@", - [self formattedHexStringFromDecimalNumber: tmp withPlaces: @8]]; - case EDT_URATIONAL: - return [self decimalToUnsignedRational: [NSNumber numberWithDouble:[data doubleValue]] - withResultNumerator: &num - withResultDenominator: &denom]; - case EDT_SBYTE: - - break; - case EDT_UNDEFINED: - break; // 8 bits - case EDT_SSHORT: - break; - case EDT_SLONG: - break; // 32bit signed integer (2's complement) - case EDT_SRATIONAL: - break; // 2 SLONGS, first long is numerator, second is denominator - case EDT_SINGLEFLOAT: - break; - case EDT_DOUBLEFLOAT: - break; - } - return datastr; -} - -//====================================================================================================================== -// Utility Methods -//====================================================================================================================== - -// creates a formatted little endian hex string from a number and width specifier -- (NSString*) formattedHexStringFromDecimalNumber: (NSNumber*) numb withPlaces: (NSNumber*) width { - NSMutableString * str = [[NSMutableString alloc] initWithCapacity:[width intValue]]; - NSString * formatstr = [[NSString alloc] initWithFormat: @"%%%@%dx", @"0", [width intValue]]; - [str appendFormat:formatstr, [numb intValue]]; - return str; -} - -// format number as string with leading 0's -- (NSString*) formatNumberWithLeadingZeroes: (NSNumber *) numb withPlaces: (NSNumber *) places { - NSNumberFormatter * formatter = [[NSNumberFormatter alloc] init]; - NSString *formatstr = [@"" stringByPaddingToLength:[places unsignedIntegerValue] withString:@"0" startingAtIndex:0]; - [formatter setPositiveFormat:formatstr]; - return [formatter stringFromNumber:numb]; -} - -// approximate a decimal with a rational by method of continued fraction -// can be collasped into decimalToUnsignedRational after testing -- (void) decimalToRational: (NSNumber *) numb - withResultNumerator: (NSNumber**) numerator - withResultDenominator: (NSNumber**) denominator { - NSMutableArray * fractionlist = [[NSMutableArray alloc] initWithCapacity:8]; - - [self continuedFraction: [numb doubleValue] - withFractionList: fractionlist - withHorizon: 8]; - - // simplify complex fraction represented by partial fraction list - [self expandContinuedFraction: fractionlist - withResultNumerator: numerator - withResultDenominator: denominator]; - -} - -// approximate a decimal with an unsigned rational by method of continued fraction -- (NSString*) decimalToUnsignedRational: (NSNumber *) numb - withResultNumerator: (NSNumber**) numerator - withResultDenominator: (NSNumber**) denominator { - NSMutableArray * fractionlist = [[NSMutableArray alloc] initWithCapacity:8]; - - // generate partial fraction list - [self continuedFraction: [numb doubleValue] - withFractionList: fractionlist - withHorizon: 8]; - - // simplify complex fraction represented by partial fraction list - [self expandContinuedFraction: fractionlist - withResultNumerator: numerator - withResultDenominator: denominator]; - - return [self formatFractionList: fractionlist]; -} - -// recursive implementation of decimal approximation by continued fraction -- (void) continuedFraction: (double) val - withFractionList: (NSMutableArray*) fractionlist - withHorizon: (int) horizon { - int whole; - double remainder; - // 1. split term - [self splitDouble: val withIntComponent: &whole withFloatRemainder: &remainder]; - [fractionlist addObject: [NSNumber numberWithInt:whole]]; - - // 2. calculate reciprocal of remainder - if (!remainder) return; // early exit, exact fraction found, avoids recip/0 - double recip = 1 / remainder; - - // 3. exit condition - if ([fractionlist count] > horizon) { - return; - } - - // 4. recurse - [self continuedFraction:recip withFractionList: fractionlist withHorizon: horizon]; - -} - -// expand continued fraction list, creating a single level rational approximation --(void) expandContinuedFraction: (NSArray*) fractionlist - withResultNumerator: (NSNumber**) numerator - withResultDenominator: (NSNumber**) denominator { - int i = 0; - int den = 0; - int num = 0; - if ([fractionlist count] == 1) { - *numerator = [NSNumber numberWithInt:[[fractionlist objectAtIndex:0] intValue]]; - *denominator = @1; - return; - } - - //begin at the end of the list - i = [fractionlist count] - 1; - num = 1; - den = [[fractionlist objectAtIndex:i] intValue]; - - while (i > 0) { - int t = [[fractionlist objectAtIndex: i-1] intValue]; - num = t * den + num; - if (i==1) { - break; - } else { - t = num; - num = den; - den = t; - } - i--; - } - // set result parameters values - *numerator = [NSNumber numberWithInt: num]; - *denominator = [NSNumber numberWithInt: den]; -} - -// formats expanded fraction list to string matching exif specification -- (NSString*) formatFractionList: (NSArray *) fractionlist { - NSMutableString * str = [[NSMutableString alloc] initWithCapacity:16]; - - if ([fractionlist count] == 1){ - [str appendFormat: @"%08x00000001", [[fractionlist objectAtIndex:0] intValue]]; - } - return str; -} - -// format rational as -- (NSString*) formatRationalWithNumerator: (NSNumber*) numerator withDenominator: (NSNumber*) denominator asSigned: (Boolean) signedFlag { - NSMutableString * str = [[NSMutableString alloc] initWithCapacity:16]; - if (signedFlag) { - long num = [numerator longValue]; - long den = [denominator longValue]; - [str appendFormat: @"%08lx%08lx", num >= 0 ? num : ~ABS(num) + 1, num >= 0 ? den : ~ABS(den) + 1]; - } else { - [str appendFormat: @"%08lx%08lx", [numerator unsignedLongValue], [denominator unsignedLongValue]]; - } - return str; -} - -// split a floating point number into two integer values representing the left and right side of the decimal -- (void) splitDouble: (double) val withIntComponent: (int*) rightside withFloatRemainder: (double*) leftside { - *rightside = val; // convert numb to int representation, which truncates the decimal portion - *leftside = val - *rightside; -} - - -// -- (NSString*) hexStringFromData : (NSData*) data { - //overflow detection - const unsigned char *dataBuffer = [data bytes]; - return [[NSString alloc] initWithFormat: @"%02x%02x", - (unsigned char)dataBuffer[0], - (unsigned char)dataBuffer[1]]; -} - -// convert a hex string to a number -- (NSNumber*) numericFromHexString : (NSString *) hexstring { - NSScanner * scan = NULL; - unsigned int numbuf= 0; - - scan = [NSScanner scannerWithString:hexstring]; - [scan scanHexInt:&numbuf]; - return [NSNumber numberWithInt:numbuf]; -} - -@end diff --git a/CordovaLib/Classes/CDVLocation.h b/CordovaLib/Classes/CDVLocation.h deleted file mode 100755 index caf0798..0000000 --- a/CordovaLib/Classes/CDVLocation.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - 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 -#import -#import "CDVPlugin.h" - -enum CDVHeadingStatus { - HEADINGSTOPPED = 0, - HEADINGSTARTING, - HEADINGRUNNING, - HEADINGERROR -}; -typedef NSUInteger CDVHeadingStatus; - -enum CDVLocationStatus { - PERMISSIONDENIED = 1, - POSITIONUNAVAILABLE, - TIMEOUT -}; -typedef NSUInteger CDVLocationStatus; - -// simple object to keep track of heading information -@interface CDVHeadingData : NSObject {} - -@property (nonatomic, assign) CDVHeadingStatus headingStatus; -@property (nonatomic, strong) CLHeading* headingInfo; -@property (nonatomic, strong) NSMutableArray* headingCallbacks; -@property (nonatomic, copy) NSString* headingFilter; -@property (nonatomic, strong) NSDate* headingTimestamp; -@property (assign) NSInteger timeout; - -@end - -// simple object to keep track of location information -@interface CDVLocationData : NSObject { - CDVLocationStatus locationStatus; - NSMutableArray* locationCallbacks; - NSMutableDictionary* watchCallbacks; - CLLocation* locationInfo; -} - -@property (nonatomic, assign) CDVLocationStatus locationStatus; -@property (nonatomic, strong) CLLocation* locationInfo; -@property (nonatomic, strong) NSMutableArray* locationCallbacks; -@property (nonatomic, strong) NSMutableDictionary* watchCallbacks; - -@end - -@interface CDVLocation : CDVPlugin { - @private BOOL __locationStarted; - @private BOOL __highAccuracyEnabled; - CDVHeadingData* headingData; - CDVLocationData* locationData; -} - -@property (nonatomic, strong) CLLocationManager* locationManager; -@property (strong) CDVHeadingData* headingData; -@property (nonatomic, strong) CDVLocationData* locationData; - -- (BOOL)hasHeadingSupport; -- (void)getLocation:(CDVInvokedUrlCommand*)command; -- (void)addWatch:(CDVInvokedUrlCommand*)command; -- (void)clearWatch:(CDVInvokedUrlCommand*)command; -- (void)returnLocationInfo:(NSString*)callbackId andKeepCallback:(BOOL)keepCallback; -- (void)returnLocationError:(NSUInteger)errorCode withMessage:(NSString*)message; -- (void)startLocation:(BOOL)enableHighAccuracy; - -- (void)locationManager:(CLLocationManager*)manager - didUpdateToLocation:(CLLocation*)newLocation - fromLocation:(CLLocation*)oldLocation; - -- (void)locationManager:(CLLocationManager*)manager - didFailWithError:(NSError*)error; - -- (BOOL)isLocationServicesEnabled; - -- (void)getHeading:(CDVInvokedUrlCommand*)command; -- (void)returnHeadingInfo:(NSString*)callbackId keepCallback:(BOOL)bRetain; -- (void)watchHeadingFilter:(CDVInvokedUrlCommand*)command; -- (void)stopHeading:(CDVInvokedUrlCommand*)command; -- (void)startHeadingWithFilter:(CLLocationDegrees)filter; -- (void)locationManager:(CLLocationManager*)manager - didUpdateHeading:(CLHeading*)heading; - -- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager*)manager; - -@end diff --git a/CordovaLib/Classes/CDVLocation.m b/CordovaLib/Classes/CDVLocation.m deleted file mode 100755 index ed9ec26..0000000 --- a/CordovaLib/Classes/CDVLocation.m +++ /dev/null @@ -1,623 +0,0 @@ -/* - 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 "CDVLocation.h" -#import "NSArray+Comparisons.h" - -#pragma mark Constants - -#define kPGLocationErrorDomain @"kPGLocationErrorDomain" -#define kPGLocationDesiredAccuracyKey @"desiredAccuracy" -#define kPGLocationForcePromptKey @"forcePrompt" -#define kPGLocationDistanceFilterKey @"distanceFilter" -#define kPGLocationFrequencyKey @"frequency" - -#pragma mark - -#pragma mark Categories - -@interface NSError (JSONMethods) - -- (NSString*)JSONRepresentation; - -@end - -@interface CLLocation (JSONMethods) - -- (NSString*)JSONRepresentation; - -@end - -@interface CLHeading (JSONMethods) - -- (NSString*)JSONRepresentation; - -@end - -#pragma mark - -#pragma mark CDVHeadingData - -@implementation CDVHeadingData - -@synthesize headingStatus, headingInfo, headingCallbacks, headingFilter, headingTimestamp, timeout; -- (CDVHeadingData*)init -{ - self = (CDVHeadingData*)[super init]; - if (self) { - self.headingStatus = HEADINGSTOPPED; - self.headingInfo = nil; - self.headingCallbacks = nil; - self.headingFilter = nil; - self.headingTimestamp = nil; - self.timeout = 10; - } - return self; -} - -@end - -@implementation CDVLocationData - -@synthesize locationStatus, locationInfo, locationCallbacks, watchCallbacks; -- (CDVLocationData*)init -{ - self = (CDVLocationData*)[super init]; - if (self) { - self.locationInfo = nil; - self.locationCallbacks = nil; - self.watchCallbacks = nil; - } - return self; -} - -@end - -#pragma mark - -#pragma mark CDVLocation - -@implementation CDVLocation - -@synthesize locationManager, headingData, locationData; - -- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView -{ - self = (CDVLocation*)[super initWithWebView:(UIWebView*)theWebView]; - if (self) { - self.locationManager = [[CLLocationManager alloc] init]; - self.locationManager.delegate = self; // Tells the location manager to send updates to this object - __locationStarted = NO; - __highAccuracyEnabled = NO; - self.headingData = nil; - self.locationData = nil; - } - return self; -} - -- (BOOL)hasHeadingSupport -{ - BOOL headingInstancePropertyAvailable = [self.locationManager respondsToSelector:@selector(headingAvailable)]; // iOS 3.x - BOOL headingClassPropertyAvailable = [CLLocationManager respondsToSelector:@selector(headingAvailable)]; // iOS 4.x - - if (headingInstancePropertyAvailable) { // iOS 3.x - return [(id)self.locationManager headingAvailable]; - } else if (headingClassPropertyAvailable) { // iOS 4.x - return [CLLocationManager headingAvailable]; - } else { // iOS 2.x - return NO; - } -} - -- (BOOL)isAuthorized -{ - BOOL authorizationStatusClassPropertyAvailable = [CLLocationManager respondsToSelector:@selector(authorizationStatus)]; // iOS 4.2+ - - if (authorizationStatusClassPropertyAvailable) { - NSUInteger authStatus = [CLLocationManager authorizationStatus]; - return (authStatus == kCLAuthorizationStatusAuthorized) || (authStatus == kCLAuthorizationStatusNotDetermined); - } - - // by default, assume YES (for iOS < 4.2) - return YES; -} - -- (BOOL)isLocationServicesEnabled -{ - BOOL locationServicesEnabledInstancePropertyAvailable = [self.locationManager respondsToSelector:@selector(locationServicesEnabled)]; // iOS 3.x - BOOL locationServicesEnabledClassPropertyAvailable = [CLLocationManager respondsToSelector:@selector(locationServicesEnabled)]; // iOS 4.x - - if (locationServicesEnabledClassPropertyAvailable) { // iOS 4.x - return [CLLocationManager locationServicesEnabled]; - } else if (locationServicesEnabledInstancePropertyAvailable) { // iOS 2.x, iOS 3.x - return [(id)self.locationManager locationServicesEnabled]; - } else { - return NO; - } -} - -- (void)startLocation:(BOOL)enableHighAccuracy -{ - if (![self isLocationServicesEnabled]) { - [self returnLocationError:PERMISSIONDENIED withMessage:@"Location services are not enabled."]; - return; - } - if (![self isAuthorized]) { - NSString* message = nil; - BOOL authStatusAvailable = [CLLocationManager respondsToSelector:@selector(authorizationStatus)]; // iOS 4.2+ - if (authStatusAvailable) { - NSUInteger code = [CLLocationManager authorizationStatus]; - if (code == kCLAuthorizationStatusNotDetermined) { - // could return POSITION_UNAVAILABLE but need to coordinate with other platforms - message = @"User undecided on application's use of location services."; - } else if (code == kCLAuthorizationStatusRestricted) { - message = @"Application's use of location services is restricted."; - } - } - // PERMISSIONDENIED is only PositionError that makes sense when authorization denied - [self returnLocationError:PERMISSIONDENIED withMessage:message]; - - return; - } - - // Tell the location manager to start notifying us of location updates. We - // first stop, and then start the updating to ensure we get at least one - // update, even if our location did not change. - [self.locationManager stopUpdatingLocation]; - [self.locationManager startUpdatingLocation]; - __locationStarted = YES; - if (enableHighAccuracy) { - __highAccuracyEnabled = YES; - // Set to distance filter to "none" - which should be the minimum for best results. - self.locationManager.distanceFilter = kCLDistanceFilterNone; - // Set desired accuracy to Best. - self.locationManager.desiredAccuracy = kCLLocationAccuracyBest; - } else { - __highAccuracyEnabled = NO; - // TODO: Set distance filter to 10 meters? and desired accuracy to nearest ten meters? arbitrary. - self.locationManager.distanceFilter = 10; - self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; - } -} - -- (void)_stopLocation -{ - if (__locationStarted) { - if (![self isLocationServicesEnabled]) { - return; - } - - [self.locationManager stopUpdatingLocation]; - __locationStarted = NO; - __highAccuracyEnabled = NO; - } -} - -- (void)locationManager:(CLLocationManager*)manager - didUpdateToLocation:(CLLocation*)newLocation - fromLocation:(CLLocation*)oldLocation -{ - CDVLocationData* cData = self.locationData; - - cData.locationInfo = newLocation; - if (self.locationData.locationCallbacks.count > 0) { - for (NSString* callbackId in self.locationData.locationCallbacks) { - [self returnLocationInfo:callbackId andKeepCallback:NO]; - } - - [self.locationData.locationCallbacks removeAllObjects]; - } - if (self.locationData.watchCallbacks.count > 0) { - for (NSString* timerId in self.locationData.watchCallbacks) { - [self returnLocationInfo:[self.locationData.watchCallbacks objectForKey:timerId] andKeepCallback:YES]; - } - } else { - // No callbacks waiting on us anymore, turn off listening. - [self _stopLocation]; - } -} - -- (void)getLocation:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - BOOL enableHighAccuracy = [[command.arguments objectAtIndex:0] boolValue]; - - if ([self isLocationServicesEnabled] == NO) { - NSMutableDictionary* posError = [NSMutableDictionary dictionaryWithCapacity:2]; - [posError setObject:[NSNumber numberWithInt:PERMISSIONDENIED] forKey:@"code"]; - [posError setObject:@"Location services are disabled." forKey:@"message"]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:posError]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } else { - if (!self.locationData) { - self.locationData = [[CDVLocationData alloc] init]; - } - CDVLocationData* lData = self.locationData; - if (!lData.locationCallbacks) { - lData.locationCallbacks = [NSMutableArray arrayWithCapacity:1]; - } - - if (!__locationStarted || (__highAccuracyEnabled != enableHighAccuracy)) { - // add the callbackId into the array so we can call back when get data - if (callbackId != nil) { - [lData.locationCallbacks addObject:callbackId]; - } - // Tell the location manager to start notifying us of heading updates - [self startLocation:enableHighAccuracy]; - } else { - [self returnLocationInfo:callbackId andKeepCallback:NO]; - } - } -} - -- (void)addWatch:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSString* timerId = [command.arguments objectAtIndex:0]; - BOOL enableHighAccuracy = [[command.arguments objectAtIndex:1] boolValue]; - - if (!self.locationData) { - self.locationData = [[CDVLocationData alloc] init]; - } - CDVLocationData* lData = self.locationData; - - if (!lData.watchCallbacks) { - lData.watchCallbacks = [NSMutableDictionary dictionaryWithCapacity:1]; - } - - // add the callbackId into the dictionary so we can call back whenever get data - [lData.watchCallbacks setObject:callbackId forKey:timerId]; - - if ([self isLocationServicesEnabled] == NO) { - NSMutableDictionary* posError = [NSMutableDictionary dictionaryWithCapacity:2]; - [posError setObject:[NSNumber numberWithInt:PERMISSIONDENIED] forKey:@"code"]; - [posError setObject:@"Location services are disabled." forKey:@"message"]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:posError]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } else { - if (!__locationStarted || (__highAccuracyEnabled != enableHighAccuracy)) { - // Tell the location manager to start notifying us of location updates - [self startLocation:enableHighAccuracy]; - } - } -} - -- (void)clearWatch:(CDVInvokedUrlCommand*)command -{ - NSString* timerId = [command.arguments objectAtIndex:0]; - - if (self.locationData && self.locationData.watchCallbacks && [self.locationData.watchCallbacks objectForKey:timerId]) { - [self.locationData.watchCallbacks removeObjectForKey:timerId]; - } -} - -- (void)stopLocation:(CDVInvokedUrlCommand*)command -{ - [self _stopLocation]; -} - -- (void)returnLocationInfo:(NSString*)callbackId andKeepCallback:(BOOL)keepCallback -{ - CDVPluginResult* result = nil; - CDVLocationData* lData = self.locationData; - - if (lData && !lData.locationInfo) { - // return error - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:POSITIONUNAVAILABLE]; - } else if (lData && lData.locationInfo) { - CLLocation* lInfo = lData.locationInfo; - NSMutableDictionary* returnInfo = [NSMutableDictionary dictionaryWithCapacity:8]; - NSNumber* timestamp = [NSNumber numberWithDouble:([lInfo.timestamp timeIntervalSince1970] * 1000)]; - [returnInfo setObject:timestamp forKey:@"timestamp"]; - [returnInfo setObject:[NSNumber numberWithDouble:lInfo.speed] forKey:@"velocity"]; - [returnInfo setObject:[NSNumber numberWithDouble:lInfo.verticalAccuracy] forKey:@"altitudeAccuracy"]; - [returnInfo setObject:[NSNumber numberWithDouble:lInfo.horizontalAccuracy] forKey:@"accuracy"]; - [returnInfo setObject:[NSNumber numberWithDouble:lInfo.course] forKey:@"heading"]; - [returnInfo setObject:[NSNumber numberWithDouble:lInfo.altitude] forKey:@"altitude"]; - [returnInfo setObject:[NSNumber numberWithDouble:lInfo.coordinate.latitude] forKey:@"latitude"]; - [returnInfo setObject:[NSNumber numberWithDouble:lInfo.coordinate.longitude] forKey:@"longitude"]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:returnInfo]; - [result setKeepCallbackAsBool:keepCallback]; - } - if (result) { - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } -} - -- (void)returnLocationError:(NSUInteger)errorCode withMessage:(NSString*)message -{ - NSMutableDictionary* posError = [NSMutableDictionary dictionaryWithCapacity:2]; - - [posError setObject:[NSNumber numberWithInt:errorCode] forKey:@"code"]; - [posError setObject:message ? message:@"" forKey:@"message"]; - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:posError]; - - for (NSString* callbackId in self.locationData.locationCallbacks) { - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - - [self.locationData.locationCallbacks removeAllObjects]; - - for (NSString* callbackId in self.locationData.watchCallbacks) { - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } -} - -// called to get the current heading -// Will call location manager to startUpdatingHeading if necessary - -- (void)getHeading:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* options = [command.arguments objectAtIndex:0 withDefault:nil]; - NSNumber* filter = [options valueForKey:@"filter"]; - - if (filter) { - [self watchHeadingFilter:command]; - return; - } - if ([self hasHeadingSupport] == NO) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:20]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } else { - // heading retrieval does is not affected by disabling locationServices and authorization of app for location services - if (!self.headingData) { - self.headingData = [[CDVHeadingData alloc] init]; - } - CDVHeadingData* hData = self.headingData; - - if (!hData.headingCallbacks) { - hData.headingCallbacks = [NSMutableArray arrayWithCapacity:1]; - } - // add the callbackId into the array so we can call back when get data - [hData.headingCallbacks addObject:callbackId]; - - if ((hData.headingStatus != HEADINGRUNNING) && (hData.headingStatus != HEADINGERROR)) { - // Tell the location manager to start notifying us of heading updates - [self startHeadingWithFilter:0.2]; - } else { - [self returnHeadingInfo:callbackId keepCallback:NO]; - } - } -} - -// called to request heading updates when heading changes by a certain amount (filter) -- (void)watchHeadingFilter:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSDictionary* options = [command.arguments objectAtIndex:0 withDefault:nil]; - NSNumber* filter = [options valueForKey:@"filter"]; - CDVHeadingData* hData = self.headingData; - - if ([self hasHeadingSupport] == NO) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:20]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } else { - if (!hData) { - self.headingData = [[CDVHeadingData alloc] init]; - hData = self.headingData; - } - if (hData.headingStatus != HEADINGRUNNING) { - // Tell the location manager to start notifying us of heading updates - [self startHeadingWithFilter:[filter doubleValue]]; - } else { - // if already running check to see if due to existing watch filter - if (hData.headingFilter && ![hData.headingFilter isEqualToString:callbackId]) { - // new watch filter being specified - // send heading data one last time to clear old successCallback - [self returnHeadingInfo:hData.headingFilter keepCallback:NO]; - } - } - // save the new filter callback and update the headingFilter setting - hData.headingFilter = callbackId; - // check if need to stop and restart in order to change value??? - self.locationManager.headingFilter = [filter doubleValue]; - } -} - -- (void)returnHeadingInfo:(NSString*)callbackId keepCallback:(BOOL)bRetain -{ - CDVPluginResult* result = nil; - CDVHeadingData* hData = self.headingData; - - self.headingData.headingTimestamp = [NSDate date]; - - if (hData && (hData.headingStatus == HEADINGERROR)) { - // return error - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:0]; - } else if (hData && (hData.headingStatus == HEADINGRUNNING) && hData.headingInfo) { - // if there is heading info, return it - CLHeading* hInfo = hData.headingInfo; - NSMutableDictionary* returnInfo = [NSMutableDictionary dictionaryWithCapacity:4]; - NSNumber* timestamp = [NSNumber numberWithDouble:([hInfo.timestamp timeIntervalSince1970] * 1000)]; - [returnInfo setObject:timestamp forKey:@"timestamp"]; - [returnInfo setObject:[NSNumber numberWithDouble:hInfo.magneticHeading] forKey:@"magneticHeading"]; - id trueHeading = __locationStarted ? (id)[NSNumber numberWithDouble : hInfo.trueHeading] : (id)[NSNull null]; - [returnInfo setObject:trueHeading forKey:@"trueHeading"]; - [returnInfo setObject:[NSNumber numberWithDouble:hInfo.headingAccuracy] forKey:@"headingAccuracy"]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:returnInfo]; - [result setKeepCallbackAsBool:bRetain]; - } - if (result) { - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } -} - -- (void)stopHeading:(CDVInvokedUrlCommand*)command -{ - // CDVHeadingData* hData = self.headingData; - if (self.headingData && (self.headingData.headingStatus != HEADINGSTOPPED)) { - if (self.headingData.headingFilter) { - // callback one last time to clear callback - [self returnHeadingInfo:self.headingData.headingFilter keepCallback:NO]; - self.headingData.headingFilter = nil; - } - [self.locationManager stopUpdatingHeading]; - NSLog(@"heading STOPPED"); - self.headingData = nil; - } -} - -// helper method to check the orientation and start updating headings -- (void)startHeadingWithFilter:(CLLocationDegrees)filter -{ - // FYI UIDeviceOrientation and CLDeviceOrientation enums are currently the same - self.locationManager.headingOrientation = (CLDeviceOrientation)self.viewController.interfaceOrientation; - self.locationManager.headingFilter = filter; - [self.locationManager startUpdatingHeading]; - self.headingData.headingStatus = HEADINGSTARTING; -} - -- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager*)manager -{ - return YES; -} - -- (void)locationManager:(CLLocationManager*)manager - didUpdateHeading:(CLHeading*)heading -{ - CDVHeadingData* hData = self.headingData; - - // normally we would clear the delegate to stop getting these notifications, but - // we are sharing a CLLocationManager to get location data as well, so we do a nil check here - // ideally heading and location should use their own CLLocationManager instances - if (hData == nil) { - return; - } - - // save the data for next call into getHeadingData - hData.headingInfo = heading; - BOOL bTimeout = NO; - if (!hData.headingFilter && hData.headingTimestamp) { - bTimeout = fabs([hData.headingTimestamp timeIntervalSinceNow]) > hData.timeout; - } - - if (hData.headingStatus == HEADINGSTARTING) { - hData.headingStatus = HEADINGRUNNING; // so returnHeading info will work - - // this is the first update - for (NSString* callbackId in hData.headingCallbacks) { - [self returnHeadingInfo:callbackId keepCallback:NO]; - } - - [hData.headingCallbacks removeAllObjects]; - } - if (hData.headingFilter) { - [self returnHeadingInfo:hData.headingFilter keepCallback:YES]; - } else if (bTimeout) { - [self stopHeading:nil]; - } - hData.headingStatus = HEADINGRUNNING; // to clear any error -} - -- (void)locationManager:(CLLocationManager*)manager didFailWithError:(NSError*)error -{ - NSLog(@"locationManager::didFailWithError %@", [error localizedFailureReason]); - - // Compass Error - if ([error code] == kCLErrorHeadingFailure) { - CDVHeadingData* hData = self.headingData; - if (hData) { - if (hData.headingStatus == HEADINGSTARTING) { - // heading error during startup - report error - for (NSString* callbackId in hData.headingCallbacks) { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:0]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - - [hData.headingCallbacks removeAllObjects]; - } // else for frequency watches next call to getCurrentHeading will report error - if (hData.headingFilter) { - CDVPluginResult* resultFilter = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:0]; - [self.commandDelegate sendPluginResult:resultFilter callbackId:hData.headingFilter]; - } - hData.headingStatus = HEADINGERROR; - } - } - // Location Error - else { - CDVLocationData* lData = self.locationData; - if (lData && __locationStarted) { - // TODO: probably have to once over the various error codes and return one of: - // PositionError.PERMISSION_DENIED = 1; - // PositionError.POSITION_UNAVAILABLE = 2; - // PositionError.TIMEOUT = 3; - NSUInteger positionError = POSITIONUNAVAILABLE; - if (error.code == kCLErrorDenied) { - positionError = PERMISSIONDENIED; - } - [self returnLocationError:positionError withMessage:[error localizedDescription]]; - } - } - - [self.locationManager stopUpdatingLocation]; - __locationStarted = NO; -} - -- (void)dealloc -{ - self.locationManager.delegate = nil; -} - -- (void)onReset -{ - [self _stopLocation]; - [self.locationManager stopUpdatingHeading]; - self.headingData = nil; -} - -@end - -#pragma mark - -#pragma mark CLLocation(JSONMethods) - -@implementation CLLocation (JSONMethods) - -- (NSString*)JSONRepresentation -{ - return [NSString stringWithFormat: - @"{ timestamp: %.00f, \ - coords: { latitude: %f, longitude: %f, altitude: %.02f, heading: %.02f, speed: %.02f, accuracy: %.02f, altitudeAccuracy: %.02f } \ - }", - [self.timestamp timeIntervalSince1970] * 1000.0, - self.coordinate.latitude, - self.coordinate.longitude, - self.altitude, - self.course, - self.speed, - self.horizontalAccuracy, - self.verticalAccuracy - ]; -} - -@end - -#pragma mark NSError(JSONMethods) - -@implementation NSError (JSONMethods) - -- (NSString*)JSONRepresentation -{ - return [NSString stringWithFormat: - @"{ code: %d, message: '%@'}", - self.code, - [self localizedDescription] - ]; -} - -@end diff --git a/CordovaLib/Classes/CDVLogger.h b/CordovaLib/Classes/CDVLogger.h deleted file mode 100755 index eeba63c..0000000 --- a/CordovaLib/Classes/CDVLogger.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - 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" - -@interface CDVLogger : CDVPlugin - -- (void)logLevel:(CDVInvokedUrlCommand*)command; - -@end diff --git a/CordovaLib/Classes/CDVLogger.m b/CordovaLib/Classes/CDVLogger.m deleted file mode 100755 index a37cf8a..0000000 --- a/CordovaLib/Classes/CDVLogger.m +++ /dev/null @@ -1,38 +0,0 @@ -/* - 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 "CDVLogger.h" -#import "CDV.h" - -@implementation CDVLogger - -/* log a message */ -- (void)logLevel:(CDVInvokedUrlCommand*)command -{ - id level = [command.arguments objectAtIndex:0]; - id message = [command.arguments objectAtIndex:1]; - - if ([level isEqualToString:@"LOG"]) { - NSLog(@"%@", message); - } else { - NSLog(@"%@: %@", level, message); - } -} - -@end diff --git a/CordovaLib/Classes/CDVNotification.h b/CordovaLib/Classes/CDVNotification.h deleted file mode 100755 index 5b5b89f..0000000 --- a/CordovaLib/Classes/CDVNotification.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - 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 -#import -#import -#import "CDVPlugin.h" - -@interface CDVNotification : CDVPlugin {} - -- (void)alert:(CDVInvokedUrlCommand*)command; -- (void)confirm:(CDVInvokedUrlCommand*)command; -- (void)prompt:(CDVInvokedUrlCommand*)command; -- (void)vibrate:(CDVInvokedUrlCommand*)command; - -@end - -@interface CDVAlertView : UIAlertView {} -@property (nonatomic, copy) NSString* callbackId; - -@end diff --git a/CordovaLib/Classes/CDVNotification.m b/CordovaLib/Classes/CDVNotification.m deleted file mode 100755 index 821cb9f..0000000 --- a/CordovaLib/Classes/CDVNotification.m +++ /dev/null @@ -1,126 +0,0 @@ -/* - 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 "CDVNotification.h" -#import "NSDictionary+Extensions.h" - -#define DIALOG_TYPE_ALERT @"alert" -#define DIALOG_TYPE_PROMPT @"prompt" - -@implementation CDVNotification - -/* - * showDialogWithMessage - Common method to instantiate the alert view for alert, confirm, and prompt notifications. - * Parameters: - * message The alert view message. - * title The alert view title. - * buttons The array of customized strings for the buttons. - * callbackId The commmand callback id. - * dialogType The type of alert view [alert | prompt]. - */ -- (void)showDialogWithMessage:(NSString*)message title:(NSString*)title buttons:(NSArray*)buttons callbackId:(NSString*)callbackId dialogType:(NSString*)dialogType -{ - CDVAlertView* alertView = [[CDVAlertView alloc] - initWithTitle:title - message:message - delegate:self - cancelButtonTitle:nil - otherButtonTitles:nil]; - - alertView.callbackId = callbackId; - - int count = [buttons count]; - - for (int n = 0; n < count; n++) { - [alertView addButtonWithTitle:[buttons objectAtIndex:n]]; - } - - if ([dialogType isEqualToString:DIALOG_TYPE_PROMPT]) { - alertView.alertViewStyle = UIAlertViewStylePlainTextInput; - } - - [alertView show]; -} - -- (void)alert:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSString* message = [command argumentAtIndex:0]; - NSString* title = [command argumentAtIndex:1]; - NSString* buttons = [command argumentAtIndex:2]; - - [self showDialogWithMessage:message title:title buttons:@[buttons] callbackId:callbackId dialogType:DIALOG_TYPE_ALERT]; -} - -- (void)confirm:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSString* message = [command argumentAtIndex:0]; - NSString* title = [command argumentAtIndex:1]; - NSArray* buttons = [command argumentAtIndex:2]; - - [self showDialogWithMessage:message title:title buttons:buttons callbackId:callbackId dialogType:DIALOG_TYPE_ALERT]; -} - -- (void)prompt:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSString* message = [command argumentAtIndex:0]; - NSString* title = [command argumentAtIndex:1]; - NSArray* buttons = [command argumentAtIndex:2]; - - [self showDialogWithMessage:message title:title buttons:buttons callbackId:callbackId dialogType:DIALOG_TYPE_PROMPT]; -} - -/** - * Callback invoked when an alert dialog's buttons are clicked. - */ -- (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex -{ - CDVAlertView* cdvAlertView = (CDVAlertView*)alertView; - CDVPluginResult* result; - - // Determine what gets returned to JS based on the alert view type. - if (alertView.alertViewStyle == UIAlertViewStyleDefault) { - // For alert and confirm, return button index as int back to JS. - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:buttonIndex + 1]; - } else { - // For prompt, return button index and input text back to JS. - NSString* value0 = [[alertView textFieldAtIndex:0] text]; - NSDictionary* info = @{ - @"buttonIndex":@(buttonIndex + 1), - @"input1":(value0 ? value0 : [NSNull null]) - }; - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:info]; - } - [self.commandDelegate sendPluginResult:result callbackId:cdvAlertView.callbackId]; -} - -- (void)vibrate:(CDVInvokedUrlCommand*)command -{ - AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); -} - -@end - -@implementation CDVAlertView - -@synthesize callbackId; - -@end diff --git a/CordovaLib/Classes/CDVReachability.h b/CordovaLib/Classes/CDVReachability.h deleted file mode 100755 index 01a95c3..0000000 --- a/CordovaLib/Classes/CDVReachability.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - - File: Reachability.h - Abstract: Basic demonstration of how to use the SystemConfiguration Reachability APIs. - Version: 2.2 - - Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. - ("Apple") in consideration of your agreement to the following terms, and your - use, installation, modification or redistribution of this Apple software - constitutes acceptance of these terms. If you do not agree with these terms, - please do not use, install, modify or redistribute this Apple software. - - In consideration of your agreement to abide by the following terms, and subject - to these terms, Apple grants you a personal, non-exclusive license, under - Apple's copyrights in this original Apple software (the "Apple Software"), to - use, reproduce, modify and redistribute the Apple Software, with or without - modifications, in source and/or binary forms; provided that if you redistribute - the Apple Software in its entirety and without modifications, you must retain - this notice and the following text and disclaimers in all such redistributions - of the Apple Software. - Neither the name, trademarks, service marks or logos of Apple Inc. may be used - to endorse or promote products derived from the Apple Software without specific - prior written permission from Apple. Except as expressly stated in this notice, - no other rights or licenses, express or implied, are granted by Apple herein, - including but not limited to any patent rights that may be infringed by your - derivative works or by other works in which the Apple Software may be - incorporated. - - The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO - WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED - WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN - COMBINATION WITH YOUR PRODUCTS. - - IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR - DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF - CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF - APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Copyright (C) 2010 Apple Inc. All Rights Reserved. - -*/ - -#import -#import -#import - -typedef enum { - NotReachable = 0, - ReachableViaWWAN, // this value has been swapped with ReachableViaWiFi for Cordova backwards compat. reasons - ReachableViaWiFi // this value has been swapped with ReachableViaWWAN for Cordova backwards compat. reasons -} NetworkStatus; -#define kReachabilityChangedNotification @"kNetworkReachabilityChangedNotification" - -@interface CDVReachability : NSObject -{ - BOOL localWiFiRef; - SCNetworkReachabilityRef reachabilityRef; -} - -// reachabilityWithHostName- Use to check the reachability of a particular host name. -+ (CDVReachability*)reachabilityWithHostName:(NSString*)hostName; - -// reachabilityWithAddress- Use to check the reachability of a particular IP address. -+ (CDVReachability*)reachabilityWithAddress:(const struct sockaddr_in*)hostAddress; - -// reachabilityForInternetConnection- checks whether the default route is available. -// Should be used by applications that do not connect to a particular host -+ (CDVReachability*)reachabilityForInternetConnection; - -// reachabilityForLocalWiFi- checks whether a local wifi connection is available. -+ (CDVReachability*)reachabilityForLocalWiFi; - -// Start listening for reachability notifications on the current run loop -- (BOOL)startNotifier; -- (void)stopNotifier; - -- (NetworkStatus)currentReachabilityStatus; -// WWAN may be available, but not active until a connection has been established. -// WiFi may require a connection for VPN on Demand. -- (BOOL)connectionRequired; -@end diff --git a/CordovaLib/Classes/CDVReachability.m b/CordovaLib/Classes/CDVReachability.m deleted file mode 100755 index 89f4ec9..0000000 --- a/CordovaLib/Classes/CDVReachability.m +++ /dev/null @@ -1,260 +0,0 @@ -/* - - File: Reachability.m - Abstract: Basic demonstration of how to use the SystemConfiguration Reachability APIs. - Version: 2.2 - - Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. - ("Apple") in consideration of your agreement to the following terms, and your - use, installation, modification or redistribution of this Apple software - constitutes acceptance of these terms. If you do not agree with these terms, - please do not use, install, modify or redistribute this Apple software. - - In consideration of your agreement to abide by the following terms, and subject - to these terms, Apple grants you a personal, non-exclusive license, under - Apple's copyrights in this original Apple software (the "Apple Software"), to - use, reproduce, modify and redistribute the Apple Software, with or without - modifications, in source and/or binary forms; provided that if you redistribute - the Apple Software in its entirety and without modifications, you must retain - this notice and the following text and disclaimers in all such redistributions - of the Apple Software. - Neither the name, trademarks, service marks or logos of Apple Inc. may be used - to endorse or promote products derived from the Apple Software without specific - prior written permission from Apple. Except as expressly stated in this notice, - no other rights or licenses, express or implied, are granted by Apple herein, - including but not limited to any patent rights that may be infringed by your - derivative works or by other works in which the Apple Software may be - incorporated. - - The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO - WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED - WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN - COMBINATION WITH YOUR PRODUCTS. - - IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR - DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF - CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF - APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Copyright (C) 2010 Apple Inc. All Rights Reserved. - -*/ - -#import -#import -#import -#import -#import -#import - -#import - -#import "CDVReachability.h" - -#define kShouldPrintReachabilityFlags 0 - -static void CDVPrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment) -{ -#if kShouldPrintReachabilityFlags - NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n", - (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', - (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', - - (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', - (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', - (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', - (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', - (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', - (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', - (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-', - comment - ); -#endif -} - -@implementation CDVReachability - -static void CDVReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) -{ -#pragma unused (target, flags) - // NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback"); - // NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback"); - - // Converted the asserts above to conditionals, with safe return from the function - if (info == NULL) { - NSLog(@"info was NULL in ReachabilityCallback"); - return; - } - - if (![(__bridge NSObject*)info isKindOfClass :[CDVReachability class]]) { - NSLog(@"info was wrong class in ReachabilityCallback"); - return; - } - - // We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively - // in case someon uses the Reachability object in a different thread. - @autoreleasepool { - CDVReachability* noteObject = (__bridge CDVReachability*)info; - // Post a notification to notify the client that the network reachability changed. - [[NSNotificationCenter defaultCenter] postNotificationName:kReachabilityChangedNotification object:noteObject]; - } -} - -- (BOOL)startNotifier -{ - BOOL retVal = NO; - SCNetworkReachabilityContext context = {0, (__bridge void*)(self), NULL, NULL, NULL}; - - if (SCNetworkReachabilitySetCallback(reachabilityRef, CDVReachabilityCallback, &context)) { - if (SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) { - retVal = YES; - } - } - return retVal; -} - -- (void)stopNotifier -{ - if (reachabilityRef != NULL) { - SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - } -} - -- (void)dealloc -{ - [self stopNotifier]; - if (reachabilityRef != NULL) { - CFRelease(reachabilityRef); - } -} - -+ (CDVReachability*)reachabilityWithHostName:(NSString*)hostName; -{ - CDVReachability* retVal = NULL; - SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]); - if (reachability != NULL) { - retVal = [[self alloc] init]; - if (retVal != NULL) { - retVal->reachabilityRef = reachability; - retVal->localWiFiRef = NO; - } - } - return retVal; -} - -+ (CDVReachability*)reachabilityWithAddress:(const struct sockaddr_in*)hostAddress; -{ - SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress); - CDVReachability* retVal = NULL; - if (reachability != NULL) { - retVal = [[self alloc] init]; - if (retVal != NULL) { - retVal->reachabilityRef = reachability; - retVal->localWiFiRef = NO; - } - } - return retVal; -} - -+ (CDVReachability*)reachabilityForInternetConnection; -{ - struct sockaddr_in zeroAddress; - bzero(&zeroAddress, sizeof(zeroAddress)); - zeroAddress.sin_len = sizeof(zeroAddress); - zeroAddress.sin_family = AF_INET; - return [self reachabilityWithAddress:&zeroAddress]; -} - -+ (CDVReachability*)reachabilityForLocalWiFi; -{ - struct sockaddr_in localWifiAddress; - bzero(&localWifiAddress, sizeof(localWifiAddress)); - localWifiAddress.sin_len = sizeof(localWifiAddress); - localWifiAddress.sin_family = AF_INET; - // IN_LINKLOCALNETNUM is defined in as 169.254.0.0 - localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM); - CDVReachability* retVal = [self reachabilityWithAddress:&localWifiAddress]; - if (retVal != NULL) { - retVal->localWiFiRef = YES; - } - return retVal; -} - -#pragma mark Network Flag Handling - -- (NetworkStatus)localWiFiStatusForFlags:(SCNetworkReachabilityFlags)flags -{ - CDVPrintReachabilityFlags(flags, "localWiFiStatusForFlags"); - - BOOL retVal = NotReachable; - if ((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect)) { - retVal = ReachableViaWiFi; - } - return retVal; -} - -- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags -{ - CDVPrintReachabilityFlags(flags, "networkStatusForFlags"); - if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) { - // if target host is not reachable - return NotReachable; - } - - BOOL retVal = NotReachable; - - if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) { - // if target host is reachable and no connection is required - // then we'll assume (for now) that your on Wi-Fi - retVal = ReachableViaWiFi; - } - - if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand) != 0) || - ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))) { - // ... and the connection is on-demand (or on-traffic) if the - // calling application is using the CFSocketStream or higher APIs - - if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) { - // ... and no [user] intervention is needed - retVal = ReachableViaWiFi; - } - } - - if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) { - // ... but WWAN connections are OK if the calling application - // is using the CFNetwork (CFSocketStream?) APIs. - retVal = ReachableViaWWAN; - } - return retVal; -} - -- (BOOL)connectionRequired; -{ - NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef"); - SCNetworkReachabilityFlags flags; - if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { - return flags & kSCNetworkReachabilityFlagsConnectionRequired; - } - return NO; -} - -- (NetworkStatus)currentReachabilityStatus -{ - NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef"); - NetworkStatus retVal = NotReachable; - SCNetworkReachabilityFlags flags; - if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { - if (localWiFiRef) { - retVal = [self localWiFiStatusForFlags:flags]; - } else { - retVal = [self networkStatusForFlags:flags]; - } - } - return retVal; -} - -@end diff --git a/CordovaLib/Classes/CDVSound.h b/CordovaLib/Classes/CDVSound.h deleted file mode 100755 index 8dcf98e..0000000 --- a/CordovaLib/Classes/CDVSound.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - 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 -#import -#import - -#import "CDVPlugin.h" - -enum CDVMediaError { - MEDIA_ERR_ABORTED = 1, - MEDIA_ERR_NETWORK = 2, - MEDIA_ERR_DECODE = 3, - MEDIA_ERR_NONE_SUPPORTED = 4 -}; -typedef NSUInteger CDVMediaError; - -enum CDVMediaStates { - MEDIA_NONE = 0, - MEDIA_STARTING = 1, - MEDIA_RUNNING = 2, - MEDIA_PAUSED = 3, - MEDIA_STOPPED = 4 -}; -typedef NSUInteger CDVMediaStates; - -enum CDVMediaMsg { - MEDIA_STATE = 1, - MEDIA_DURATION = 2, - MEDIA_POSITION = 3, - MEDIA_ERROR = 9 -}; -typedef NSUInteger CDVMediaMsg; - -@interface CDVAudioPlayer : AVAudioPlayer -{ - NSString* mediaId; -} -@property (nonatomic, copy) NSString* mediaId; -@end - -@interface CDVAudioRecorder : AVAudioRecorder -{ - NSString* mediaId; -} -@property (nonatomic, copy) NSString* mediaId; -@end - -@interface CDVAudioFile : NSObject -{ - NSString* resourcePath; - NSURL* resourceURL; - CDVAudioPlayer* player; - CDVAudioRecorder* recorder; - NSNumber* volume; -} - -@property (nonatomic, strong) NSString* resourcePath; -@property (nonatomic, strong) NSURL* resourceURL; -@property (nonatomic, strong) CDVAudioPlayer* player; -@property (nonatomic, strong) NSNumber* volume; - -@property (nonatomic, strong) CDVAudioRecorder* recorder; - -@end - -@interface CDVSound : CDVPlugin -{ - NSMutableDictionary* soundCache; - AVAudioSession* avSession; -} -@property (nonatomic, strong) NSMutableDictionary* soundCache; -@property (nonatomic, strong) AVAudioSession* avSession; - -- (void)startPlayingAudio:(CDVInvokedUrlCommand*)command; -- (void)pausePlayingAudio:(CDVInvokedUrlCommand*)command; -- (void)stopPlayingAudio:(CDVInvokedUrlCommand*)command; -- (void)seekToAudio:(CDVInvokedUrlCommand*)command; -- (void)release:(CDVInvokedUrlCommand*)command; -- (void)getCurrentPositionAudio:(CDVInvokedUrlCommand*)command; - -- (BOOL)hasAudioSession; - -// helper methods -- (NSURL*)urlForRecording:(NSString*)resourcePath; -- (NSURL*)urlForPlaying:(NSString*)resourcePath; -- (NSURL*)urlForResource:(NSString*)resourcePath CDV_DEPRECATED(2.5, "Use specific api for playing or recording"); - -- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId CDV_DEPRECATED(2.5, "Use updated audioFileForResource api"); - -- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId doValidation:(BOOL)bValidate forRecording:(BOOL)bRecord; -- (BOOL)prepareToPlay:(CDVAudioFile*)audioFile withId:(NSString*)mediaId; -- (NSString*)createMediaErrorWithCode:(CDVMediaError)code message:(NSString*)message; - -- (void)startRecordingAudio:(CDVInvokedUrlCommand*)command; -- (void)stopRecordingAudio:(CDVInvokedUrlCommand*)command; - -- (void)setVolume:(CDVInvokedUrlCommand*)command; - -@end diff --git a/CordovaLib/Classes/CDVSound.m b/CordovaLib/Classes/CDVSound.m deleted file mode 100755 index 71eab59..0000000 --- a/CordovaLib/Classes/CDVSound.m +++ /dev/null @@ -1,702 +0,0 @@ -/* - 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 "CDVSound.h" -#import "NSArray+Comparisons.h" -#import "CDVJSON.h" - -#define DOCUMENTS_SCHEME_PREFIX @"documents://" -#define HTTP_SCHEME_PREFIX @"http://" -#define HTTPS_SCHEME_PREFIX @"https://" -#define RECORDING_WAV @"wav" - -@implementation CDVSound - -@synthesize soundCache, avSession; - -- (NSURL*)urlForResource:(NSString*)resourcePath -{ - NSURL* resourceURL = nil; - NSString* filePath = nil; - - // first try to find HTTP:// or Documents:// resources - - if ([resourcePath hasPrefix:HTTP_SCHEME_PREFIX] || [resourcePath hasPrefix:HTTPS_SCHEME_PREFIX]) { - // if it is a http url, use it - NSLog(@"Will use resource '%@' from the Internet.", resourcePath); - resourceURL = [NSURL URLWithString:resourcePath]; - } else if ([resourcePath hasPrefix:DOCUMENTS_SCHEME_PREFIX]) { - NSString* docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; - filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", docsPath]]; - NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath); - } else { - // attempt to find file path in www directory - filePath = [self.commandDelegate pathForResource:resourcePath]; - if (filePath != nil) { - NSLog(@"Found resource '%@' in the web folder.", filePath); - } else { - filePath = resourcePath; - NSLog(@"Will attempt to use file resource '%@'", filePath); - } - } - // check that file exists for all but HTTP_SHEME_PREFIX - if (filePath != nil) { - // try to access file - NSFileManager* fMgr = [[NSFileManager alloc] init]; - if (![fMgr fileExistsAtPath:filePath]) { - resourceURL = nil; - NSLog(@"Unknown resource '%@'", resourcePath); - } else { - // it's a valid file url, use it - resourceURL = [NSURL fileURLWithPath:filePath]; - } - } - return resourceURL; -} - -// Maps a url for a resource path for recording -- (NSURL*)urlForRecording:(NSString*)resourcePath -{ - NSURL* resourceURL = nil; - NSString* filePath = nil; - NSString* docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; - - // first check for correct extension - if ([[resourcePath pathExtension] caseInsensitiveCompare:RECORDING_WAV] != NSOrderedSame) { - resourceURL = nil; - NSLog(@"Resource for recording must have %@ extension", RECORDING_WAV); - } else if ([resourcePath hasPrefix:DOCUMENTS_SCHEME_PREFIX]) { - // try to find Documents:// resources - filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", docsPath]]; - NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath); - } else { - // if resourcePath is not from FileSystem put in tmp dir, else attempt to use provided resource path - NSString* tmpPath = [NSTemporaryDirectory()stringByStandardizingPath]; - BOOL isTmp = [resourcePath rangeOfString:tmpPath].location != NSNotFound; - BOOL isDoc = [resourcePath rangeOfString:docsPath].location != NSNotFound; - if (!isTmp && !isDoc) { - // put in temp dir - filePath = [NSString stringWithFormat:@"%@/%@", tmpPath, resourcePath]; - } else { - filePath = resourcePath; - } - } - - if (filePath != nil) { - // create resourceURL - resourceURL = [NSURL fileURLWithPath:filePath]; - } - return resourceURL; -} - -// Maps a url for a resource path for playing -// "Naked" resource paths are assumed to be from the www folder as its base -- (NSURL*)urlForPlaying:(NSString*)resourcePath -{ - NSURL* resourceURL = nil; - NSString* filePath = nil; - - // first try to find HTTP:// or Documents:// resources - - if ([resourcePath hasPrefix:HTTP_SCHEME_PREFIX] || [resourcePath hasPrefix:HTTPS_SCHEME_PREFIX]) { - // if it is a http url, use it - NSLog(@"Will use resource '%@' from the Internet.", resourcePath); - resourceURL = [NSURL URLWithString:resourcePath]; - } else if ([resourcePath hasPrefix:DOCUMENTS_SCHEME_PREFIX]) { - NSString* docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; - filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", docsPath]]; - NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath); - } else { - // attempt to find file path in www directory or LocalFileSystem.TEMPORARY directory - filePath = [self.commandDelegate pathForResource:resourcePath]; - if (filePath == nil) { - // see if this exists in the documents/temp directory from a previous recording - NSString* testPath = [NSString stringWithFormat:@"%@/%@", [NSTemporaryDirectory()stringByStandardizingPath], resourcePath]; - if ([[NSFileManager defaultManager] fileExistsAtPath:testPath]) { - // inefficient as existence will be checked again below but only way to determine if file exists from previous recording - filePath = testPath; - NSLog(@"Will attempt to use file resource from LocalFileSystem.TEMPORARY directory"); - } else { - // attempt to use path provided - filePath = resourcePath; - NSLog(@"Will attempt to use file resource '%@'", filePath); - } - } else { - NSLog(@"Found resource '%@' in the web folder.", filePath); - } - } - // check that file exists for all but HTTP_SHEME_PREFIX - if (filePath != nil) { - // create resourceURL - resourceURL = [NSURL fileURLWithPath:filePath]; - // try to access file - NSFileManager* fMgr = [NSFileManager defaultManager]; - if (![fMgr fileExistsAtPath:filePath]) { - resourceURL = nil; - NSLog(@"Unknown resource '%@'", resourcePath); - } - } - - return resourceURL; -} - -- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId -{ - // will maintain backwards compatibility with original implementation - return [self audioFileForResource:resourcePath withId:mediaId doValidation:YES forRecording:NO]; -} - -// Creates or gets the cached audio file resource object -- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId doValidation:(BOOL)bValidate forRecording:(BOOL)bRecord -{ - BOOL bError = NO; - CDVMediaError errcode = MEDIA_ERR_NONE_SUPPORTED; - NSString* errMsg = @""; - NSString* jsString = nil; - CDVAudioFile* audioFile = nil; - NSURL* resourceURL = nil; - - if ([self soundCache] == nil) { - [self setSoundCache:[NSMutableDictionary dictionaryWithCapacity:1]]; - } else { - audioFile = [[self soundCache] objectForKey:mediaId]; - } - if (audioFile == nil) { - // validate resourcePath and create - if ((resourcePath == nil) || ![resourcePath isKindOfClass:[NSString class]] || [resourcePath isEqualToString:@""]) { - bError = YES; - errcode = MEDIA_ERR_ABORTED; - errMsg = @"invalid media src argument"; - } else { - audioFile = [[CDVAudioFile alloc] init]; - audioFile.resourcePath = resourcePath; - audioFile.resourceURL = nil; // validate resourceURL when actually play or record - [[self soundCache] setObject:audioFile forKey:mediaId]; - } - } - if (bValidate && (audioFile.resourceURL == nil)) { - if (bRecord) { - resourceURL = [self urlForRecording:resourcePath]; - } else { - resourceURL = [self urlForPlaying:resourcePath]; - } - if (resourceURL == nil) { - bError = YES; - errcode = MEDIA_ERR_ABORTED; - errMsg = [NSString stringWithFormat:@"Cannot use audio file from resource '%@'", resourcePath]; - } else { - audioFile.resourceURL = resourceURL; - } - } - - if (bError) { - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:errcode message:errMsg]]; - [self.commandDelegate evalJs:jsString]; - } - - return audioFile; -} - -// returns whether or not audioSession is available - creates it if necessary -- (BOOL)hasAudioSession -{ - BOOL bSession = YES; - - if (!self.avSession) { - NSError* error = nil; - - self.avSession = [AVAudioSession sharedInstance]; - if (error) { - // is not fatal if can't get AVAudioSession , just log the error - NSLog(@"error creating audio session: %@", [[error userInfo] description]); - self.avSession = nil; - bSession = NO; - } - } - return bSession; -} - -// helper function to create a error object string -- (NSString*)createMediaErrorWithCode:(CDVMediaError)code message:(NSString*)message -{ - NSMutableDictionary* errorDict = [NSMutableDictionary dictionaryWithCapacity:2]; - - [errorDict setObject:[NSNumber numberWithUnsignedInt:code] forKey:@"code"]; - [errorDict setObject:message ? message:@"" forKey:@"message"]; - return [errorDict JSONString]; -} - -- (void)create:(CDVInvokedUrlCommand*)command -{ - NSString* mediaId = [command.arguments objectAtIndex:0]; - NSString* resourcePath = [command.arguments objectAtIndex:1]; - - CDVAudioFile* audioFile = [self audioFileForResource:resourcePath withId:mediaId doValidation:NO forRecording:NO]; - - if (audioFile == nil) { - NSString* errorMessage = [NSString stringWithFormat:@"Failed to initialize Media file with path %@", resourcePath]; - NSString* jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMessage]]; - [self.commandDelegate evalJs:jsString]; - } else { - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; - } -} - -- (void)setVolume:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - -#pragma unused(callbackId) - NSString* mediaId = [command.arguments objectAtIndex:0]; - NSNumber* volume = [command.arguments objectAtIndex:1 withDefault:[NSNumber numberWithFloat:1.0]]; - - CDVAudioFile* audioFile; - if ([self soundCache] == nil) { - [self setSoundCache:[NSMutableDictionary dictionaryWithCapacity:1]]; - } else { - audioFile = [[self soundCache] objectForKey:mediaId]; - audioFile.volume = volume; - if (audioFile.player) { - audioFile.player.volume = [volume floatValue]; - } - [[self soundCache] setObject:audioFile forKey:mediaId]; - } - - // don't care for any callbacks -} - -- (void)startPlayingAudio:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - -#pragma unused(callbackId) - NSString* mediaId = [command.arguments objectAtIndex:0]; - NSString* resourcePath = [command.arguments objectAtIndex:1]; - NSDictionary* options = [command.arguments objectAtIndex:2 withDefault:nil]; - - BOOL bError = NO; - NSString* jsString = nil; - - CDVAudioFile* audioFile = [self audioFileForResource:resourcePath withId:mediaId doValidation:YES forRecording:NO]; - if ((audioFile != nil) && (audioFile.resourceURL != nil)) { - if (audioFile.player == nil) { - bError = [self prepareToPlay:audioFile withId:mediaId]; - } - if (!bError) { - // audioFile.player != nil or player was successfully created - // get the audioSession and set the category to allow Playing when device is locked or ring/silent switch engaged - if ([self hasAudioSession]) { - NSError* __autoreleasing err = nil; - NSNumber* playAudioWhenScreenIsLocked = [options objectForKey:@"playAudioWhenScreenIsLocked"]; - BOOL bPlayAudioWhenScreenIsLocked = YES; - if (playAudioWhenScreenIsLocked != nil) { - bPlayAudioWhenScreenIsLocked = [playAudioWhenScreenIsLocked boolValue]; - } - - NSString* sessionCategory = bPlayAudioWhenScreenIsLocked ? AVAudioSessionCategoryPlayback : AVAudioSessionCategorySoloAmbient; - [self.avSession setCategory:sessionCategory error:&err]; - if (![self.avSession setActive:YES error:&err]) { - // other audio with higher priority that does not allow mixing could cause this to fail - NSLog(@"Unable to play audio: %@", [err localizedFailureReason]); - bError = YES; - } - } - if (!bError) { - NSLog(@"Playing audio sample '%@'", audioFile.resourcePath); - NSNumber* loopOption = [options objectForKey:@"numberOfLoops"]; - NSInteger numberOfLoops = 0; - if (loopOption != nil) { - numberOfLoops = [loopOption intValue] - 1; - } - audioFile.player.numberOfLoops = numberOfLoops; - if (audioFile.player.isPlaying) { - [audioFile.player stop]; - audioFile.player.currentTime = 0; - } - if (audioFile.volume != nil) { - audioFile.player.volume = [audioFile.volume floatValue]; - } - - [audioFile.player play]; - double position = round(audioFile.player.duration * 1000) / 1000; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%.3f);\n%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_DURATION, position, @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_RUNNING]; - [self.commandDelegate evalJs:jsString]; - } - } - if (bError) { - /* I don't see a problem playing previously recorded audio so removing this section - BG - NSError* error; - // try loading it one more time, in case the file was recorded previously - audioFile.player = [[ AVAudioPlayer alloc ] initWithContentsOfURL:audioFile.resourceURL error:&error]; - if (error != nil) { - NSLog(@"Failed to initialize AVAudioPlayer: %@\n", error); - audioFile.player = nil; - } else { - NSLog(@"Playing audio sample '%@'", audioFile.resourcePath); - audioFile.player.numberOfLoops = numberOfLoops; - [audioFile.player play]; - } */ - // error creating the session or player - // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, MEDIA_ERR_NONE_SUPPORTED]; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_NONE_SUPPORTED message:nil]]; - [self.commandDelegate evalJs:jsString]; - } - } - // else audioFile was nil - error already returned from audioFile for resource - return; -} - -- (BOOL)prepareToPlay:(CDVAudioFile*)audioFile withId:(NSString*)mediaId -{ - BOOL bError = NO; - NSError* __autoreleasing playerError = nil; - - // create the player - NSURL* resourceURL = audioFile.resourceURL; - - if ([resourceURL isFileURL]) { - audioFile.player = [[CDVAudioPlayer alloc] initWithContentsOfURL:resourceURL error:&playerError]; - } else { - NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:resourceURL]; - NSString* userAgent = [self.commandDelegate userAgent]; - if (userAgent) { - [request setValue:userAgent forHTTPHeaderField:@"User-Agent"]; - } - - NSURLResponse* __autoreleasing response = nil; - NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&playerError]; - if (playerError) { - NSLog(@"Unable to download audio from: %@", [resourceURL absoluteString]); - } else { - // 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:@"%@/%@", [NSTemporaryDirectory()stringByStandardizingPath], uuidString]; - CFRelease(uuidString); - CFRelease(uuidRef); - - [data writeToFile:filePath atomically:YES]; - NSURL* fileURL = [NSURL fileURLWithPath:filePath]; - audioFile.player = [[CDVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&playerError]; - } - } - - if (playerError != nil) { - NSLog(@"Failed to initialize AVAudioPlayer: %@\n", [playerError localizedDescription]); - audioFile.player = nil; - if (self.avSession) { - [self.avSession setActive:NO error:nil]; - } - bError = YES; - } else { - audioFile.player.mediaId = mediaId; - audioFile.player.delegate = self; - bError = ![audioFile.player prepareToPlay]; - } - return bError; -} - -- (void)stopPlayingAudio:(CDVInvokedUrlCommand*)command -{ - NSString* mediaId = [command.arguments objectAtIndex:0]; - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - NSString* jsString = nil; - - if ((audioFile != nil) && (audioFile.player != nil)) { - NSLog(@"Stopped playing audio sample '%@'", audioFile.resourcePath); - [audioFile.player stop]; - audioFile.player.currentTime = 0; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_STOPPED]; - } // ignore if no media playing - if (jsString) { - [self.commandDelegate evalJs:jsString]; - } -} - -- (void)pausePlayingAudio:(CDVInvokedUrlCommand*)command -{ - NSString* mediaId = [command.arguments objectAtIndex:0]; - NSString* jsString = nil; - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - - if ((audioFile != nil) && (audioFile.player != nil)) { - NSLog(@"Paused playing audio sample '%@'", audioFile.resourcePath); - [audioFile.player pause]; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_PAUSED]; - } - // ignore if no media playing - - if (jsString) { - [self.commandDelegate evalJs:jsString]; - } -} - -- (void)seekToAudio:(CDVInvokedUrlCommand*)command -{ - // args: - // 0 = Media id - // 1 = path to resource - // 2 = seek to location in milliseconds - - NSString* mediaId = [command.arguments objectAtIndex:0]; - - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - double position = [[command.arguments objectAtIndex:1] doubleValue]; - - if ((audioFile != nil) && (audioFile.player != nil)) { - NSString* jsString; - double posInSeconds = position / 1000; - if (posInSeconds >= audioFile.player.duration) { - // The seek is past the end of file. Stop media and reset to beginning instead of seeking past the end. - [audioFile.player stop]; - audioFile.player.currentTime = 0; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%.3f);\n%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_POSITION, 0.0, @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_STOPPED]; - // NSLog(@"seekToEndJsString=%@",jsString); - } else { - audioFile.player.currentTime = posInSeconds; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%f);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_POSITION, posInSeconds]; - // NSLog(@"seekJsString=%@",jsString); - } - - [self.commandDelegate evalJs:jsString]; - } -} - -- (void)release:(CDVInvokedUrlCommand*)command -{ - NSString* mediaId = [command.arguments objectAtIndex:0]; - - if (mediaId != nil) { - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - if (audioFile != nil) { - if (audioFile.player && [audioFile.player isPlaying]) { - [audioFile.player stop]; - } - if (audioFile.recorder && [audioFile.recorder isRecording]) { - [audioFile.recorder stop]; - } - if (self.avSession) { - [self.avSession setActive:NO error:nil]; - self.avSession = nil; - } - [[self soundCache] removeObjectForKey:mediaId]; - NSLog(@"Media with id %@ released", mediaId); - } - } -} - -- (void)getCurrentPositionAudio:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - NSString* mediaId = [command.arguments objectAtIndex:0]; - -#pragma unused(mediaId) - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - double position = -1; - - if ((audioFile != nil) && (audioFile.player != nil) && [audioFile.player isPlaying]) { - position = round(audioFile.player.currentTime * 1000) / 1000; - } - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:position]; - NSString* jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%.3f);\n%@", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_POSITION, position, [result toSuccessCallbackString:callbackId]]; - [self.commandDelegate evalJs:jsString]; -} - -- (void)startRecordingAudio:(CDVInvokedUrlCommand*)command -{ - NSString* callbackId = command.callbackId; - -#pragma unused(callbackId) - - NSString* mediaId = [command.arguments objectAtIndex:0]; - CDVAudioFile* audioFile = [self audioFileForResource:[command.arguments objectAtIndex:1] withId:mediaId doValidation:YES forRecording:YES]; - NSString* jsString = nil; - NSString* errorMsg = @""; - - if ((audioFile != nil) && (audioFile.resourceURL != nil)) { - NSError* __autoreleasing error = nil; - - if (audioFile.recorder != nil) { - [audioFile.recorder stop]; - audioFile.recorder = nil; - } - // get the audioSession and set the category to allow recording when device is locked or ring/silent switch engaged - if ([self hasAudioSession]) { - [self.avSession setCategory:AVAudioSessionCategoryRecord error:nil]; - if (![self.avSession setActive:YES error:&error]) { - // other audio with higher priority that does not allow mixing could cause this to fail - errorMsg = [NSString stringWithFormat:@"Unable to record audio: %@", [error localizedFailureReason]]; - // 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]]; - [self.commandDelegate evalJs:jsString]; - return; - } - } - - // create a new recorder for each start record - audioFile.recorder = [[CDVAudioRecorder alloc] initWithURL:audioFile.resourceURL settings:nil error:&error]; - - 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,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]]; - } - } else { - // file did not validate - NSString* errorMsg = [NSString stringWithFormat:@"Could not record audio at '%@'", audioFile.resourcePath]; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]]; - } - if (jsString) { - [self.commandDelegate evalJs:jsString]; - } - return; -} - -- (void)stopRecordingAudio:(CDVInvokedUrlCommand*)command -{ - NSString* mediaId = [command.arguments objectAtIndex:0]; - - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - NSString* jsString = nil; - - if ((audioFile != nil) && (audioFile.recorder != nil)) { - NSLog(@"Stopped recording audio sample '%@'", audioFile.resourcePath); - [audioFile.recorder stop]; - // no callback - that will happen in audioRecorderDidFinishRecording - } - // ignore if no media recording - if (jsString) { - [self.commandDelegate evalJs:jsString]; - } -} - -- (void)audioRecorderDidFinishRecording:(AVAudioRecorder*)recorder successfully:(BOOL)flag -{ - CDVAudioRecorder* aRecorder = (CDVAudioRecorder*)recorder; - NSString* mediaId = aRecorder.mediaId; - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - NSString* jsString = nil; - - if (audioFile != nil) { - NSLog(@"Finished recording audio sample '%@'", audioFile.resourcePath); - } - if (flag) { - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_STOPPED]; - } else { - // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, MEDIA_ERR_DECODE]; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_DECODE message:nil]]; - } - if (self.avSession) { - [self.avSession setActive:NO error:nil]; - } - [self.commandDelegate evalJs:jsString]; -} - -- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer*)player successfully:(BOOL)flag -{ - CDVAudioPlayer* aPlayer = (CDVAudioPlayer*)player; - NSString* mediaId = aPlayer.mediaId; - CDVAudioFile* audioFile = [[self soundCache] objectForKey:mediaId]; - NSString* jsString = nil; - - if (audioFile != nil) { - NSLog(@"Finished playing audio sample '%@'", audioFile.resourcePath); - } - if (flag) { - audioFile.player.currentTime = 0; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_STOPPED]; - } else { - // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, MEDIA_ERR_DECODE]; - jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_DECODE message:nil]]; - } - if (self.avSession) { - [self.avSession setActive:NO error:nil]; - } - [self.commandDelegate evalJs:jsString]; -} - -- (void)onMemoryWarning -{ - [[self soundCache] removeAllObjects]; - [self setSoundCache:nil]; - [self setAvSession:nil]; - - [super onMemoryWarning]; -} - -- (void)dealloc -{ - [[self soundCache] removeAllObjects]; -} - -- (void)onReset -{ - for (CDVAudioFile* audioFile in [[self soundCache] allValues]) { - if (audioFile != nil) { - if (audioFile.player != nil) { - [audioFile.player stop]; - audioFile.player.currentTime = 0; - } - if (audioFile.recorder != nil) { - [audioFile.recorder stop]; - } - } - } - - [[self soundCache] removeAllObjects]; -} - -@end - -@implementation CDVAudioFile - -@synthesize resourcePath; -@synthesize resourceURL; -@synthesize player, volume; -@synthesize recorder; - -@end -@implementation CDVAudioPlayer -@synthesize mediaId; - -@end - -@implementation CDVAudioRecorder -@synthesize mediaId; - -@end diff --git a/CordovaLib/Classes/CDVSplashScreen.h b/CordovaLib/Classes/CDVSplashScreen.h deleted file mode 100755 index 704ab43..0000000 --- a/CordovaLib/Classes/CDVSplashScreen.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - 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 -#import "CDVPlugin.h" - -@interface CDVSplashScreen : CDVPlugin { - UIActivityIndicatorView* _activityView; - UIImageView* _imageView; - NSString* _curImageName; - BOOL _visible; -} - -- (void)show:(CDVInvokedUrlCommand*)command; -- (void)hide:(CDVInvokedUrlCommand*)command; - -@end diff --git a/CordovaLib/Classes/CDVSplashScreen.m b/CordovaLib/Classes/CDVSplashScreen.m deleted file mode 100755 index 45889a0..0000000 --- a/CordovaLib/Classes/CDVSplashScreen.m +++ /dev/null @@ -1,225 +0,0 @@ -/* - 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 "CDVSplashScreen.h" - -#define kSplashScreenDurationDefault 0.25f - -@implementation CDVSplashScreen - -- (void)pluginInitialize -{ - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad) name:CDVPageDidLoadNotification object:self.webView]; - - [self setVisible:YES]; -} - -- (void)show:(CDVInvokedUrlCommand*)command -{ - [self setVisible:YES]; -} - -- (void)hide:(CDVInvokedUrlCommand*)command -{ - [self setVisible:NO]; -} - -- (void)pageDidLoad -{ - id autoHideSplashScreenValue = [self.commandDelegate.settings objectForKey:@"AutoHideSplashScreen"]; - - // if value is missing, default to yes - if ((autoHideSplashScreenValue == nil) || [autoHideSplashScreenValue boolValue]) { - [self setVisible:NO]; - } -} - -- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context -{ - [self updateImage]; -} - -- (void)createViews -{ - /* - * The Activity View is the top spinning throbber in the status/battery bar. We init it with the default Grey Style. - * - * whiteLarge = UIActivityIndicatorViewStyleWhiteLarge - * white = UIActivityIndicatorViewStyleWhite - * gray = UIActivityIndicatorViewStyleGray - * - */ - NSString* topActivityIndicator = [self.commandDelegate.settings objectForKey:@"TopActivityIndicator"]; - UIActivityIndicatorViewStyle topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray; - - if ([topActivityIndicator isEqualToString:@"whiteLarge"]) { - topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhiteLarge; - } else if ([topActivityIndicator isEqualToString:@"white"]) { - topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhite; - } else if ([topActivityIndicator isEqualToString:@"gray"]) { - topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray; - } - - UIView* parentView = self.viewController.view; - parentView.userInteractionEnabled = NO; // disable user interaction while splashscreen is shown - _activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:topActivityIndicatorStyle]; - _activityView.center = CGPointMake(parentView.bounds.size.width / 2, parentView.bounds.size.height / 2); - _activityView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin - | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin; - [_activityView startAnimating]; - - // Set the frame & image later. - _imageView = [[UIImageView alloc] init]; - [parentView addSubview:_imageView]; - - id showSplashScreenSpinnerValue = [self.commandDelegate.settings objectForKey:@"ShowSplashScreenSpinner"]; - // backwards compatibility - if key is missing, default to true - if ((showSplashScreenSpinnerValue == nil) || [showSplashScreenSpinnerValue boolValue]) { - [parentView addSubview:_activityView]; - } - - // Frame is required when launching in portrait mode. - // Bounds for landscape since it captures the rotation. - [parentView addObserver:self forKeyPath:@"frame" options:0 context:nil]; - [parentView addObserver:self forKeyPath:@"bounds" options:0 context:nil]; - - [self updateImage]; -} - -- (void)destroyViews -{ - [_imageView removeFromSuperview]; - [_activityView removeFromSuperview]; - _imageView = nil; - _activityView = nil; - _curImageName = nil; - - self.viewController.view.userInteractionEnabled = YES; // re-enable user interaction upon completion - [self.viewController.view removeObserver:self forKeyPath:@"frame"]; - [self.viewController.view removeObserver:self forKeyPath:@"bounds"]; -} - -// Sets the view's frame and image. -- (void)updateImage -{ - UIInterfaceOrientation orientation = self.viewController.interfaceOrientation; - - // Use UILaunchImageFile if specified in plist. Otherwise, use Default. - NSString* imageName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchImageFile"]; - - if (imageName) { - imageName = [imageName stringByDeletingPathExtension]; - } else { - imageName = @"Default"; - } - - if (CDV_IsIPhone5()) { - imageName = [imageName stringByAppendingString:@"-568h"]; - } else if (CDV_IsIPad()) { - switch (orientation) { - case UIInterfaceOrientationLandscapeLeft: - case UIInterfaceOrientationLandscapeRight: - imageName = [imageName stringByAppendingString:@"-Landscape"]; - break; - - case UIInterfaceOrientationPortrait: - case UIInterfaceOrientationPortraitUpsideDown: - default: - imageName = [imageName stringByAppendingString:@"-Portrait"]; - break; - } - } - - if (![imageName isEqualToString:_curImageName]) { - UIImage* img = [UIImage imageNamed:imageName]; - _imageView.image = img; - _curImageName = imageName; - } - - [self updateBounds]; -} - -- (void)updateBounds -{ - UIImage* img = _imageView.image; - CGRect imgBounds = CGRectMake(0, 0, img.size.width, img.size.height); - - CGSize screenSize = [self.viewController.view convertRect:[UIScreen mainScreen].bounds fromView:nil].size; - - // There's a special case when the image is the size of the screen. - if (CGSizeEqualToSize(screenSize, imgBounds.size)) { - CGRect statusFrame = [self.viewController.view convertRect:[UIApplication sharedApplication].statusBarFrame fromView:nil]; - imgBounds.origin.y -= statusFrame.size.height; - } else { - CGRect viewBounds = self.viewController.view.bounds; - CGFloat imgAspect = imgBounds.size.width / imgBounds.size.height; - CGFloat viewAspect = viewBounds.size.width / viewBounds.size.height; - // This matches the behaviour of the native splash screen. - CGFloat ratio; - if (viewAspect > imgAspect) { - ratio = viewBounds.size.width / imgBounds.size.width; - } else { - ratio = viewBounds.size.height / imgBounds.size.height; - } - imgBounds.size.height *= ratio; - imgBounds.size.width *= ratio; - } - - _imageView.frame = imgBounds; -} - -- (void)setVisible:(BOOL)visible -{ - if (visible == _visible) { - return; - } - _visible = visible; - - id fadeSplashScreenValue = [self.commandDelegate.settings objectForKey:@"FadeSplashScreen"]; - id fadeSplashScreenDuration = [self.commandDelegate.settings objectForKey:@"FadeSplashScreenDuration"]; - - float fadeDuration = fadeSplashScreenDuration == nil ? kSplashScreenDurationDefault : [fadeSplashScreenDuration floatValue]; - - if ((fadeSplashScreenValue == nil) || ![fadeSplashScreenValue boolValue]) { - fadeDuration = 0; - } - - // Never animate the showing of the splash screen. - if (visible) { - if (_imageView == nil) { - [self createViews]; - } - } else if (fadeDuration == 0) { - [self destroyViews]; - } else { - [UIView transitionWithView:self.viewController.view - duration:fadeDuration - options:UIViewAnimationOptionTransitionNone - animations:^(void) { - [_imageView setAlpha:0]; - [_activityView setAlpha:0]; - } - - completion:^(BOOL finished) { - [self destroyViews]; - }]; - } -} - -@end diff --git a/CordovaLib/Classes/CDVWhitelist.m b/CordovaLib/Classes/CDVWhitelist.m deleted file mode 100755 index db7aa32..0000000 --- a/CordovaLib/Classes/CDVWhitelist.m +++ /dev/null @@ -1,223 +0,0 @@ -/* - 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 "CDVWhitelist.h" - -NSString* const kCDVDefaultWhitelistRejectionString = @"ERROR whitelist rejection: url='%@'"; -NSString* const kCDVDefaultSchemeName = @"cdv-default-scheme"; - -@interface CDVWhitelist () - -@property (nonatomic, readwrite, strong) NSArray* whitelist; -@property (nonatomic, readwrite, strong) NSDictionary* expandedWhitelists; - -- (void)processWhitelist; - -@end - -@implementation CDVWhitelist - -@synthesize whitelist, expandedWhitelists, whitelistRejectionFormatString; - -- (id)initWithArray:(NSArray*)array -{ - self = [super init]; - if (self) { - self.whitelist = array; - self.expandedWhitelists = nil; - self.whitelistRejectionFormatString = kCDVDefaultWhitelistRejectionString; - [self processWhitelist]; - } - - return self; -} - -- (BOOL)isIPv4Address:(NSString*)externalHost -{ - // an IPv4 address has 4 octets b.b.b.b where b is a number between 0 and 255. - // for our purposes, b can also be the wildcard character '*' - - // we could use a regex to solve this problem but then I would have two problems - // anyways, this is much clearer and maintainable - NSArray* octets = [externalHost componentsSeparatedByString:@"."]; - NSUInteger num_octets = [octets count]; - - // quick check - if (num_octets != 4) { - return NO; - } - - // restrict number parsing to 0-255 - NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init]; - [numberFormatter setMinimum:[NSNumber numberWithUnsignedInteger:0]]; - [numberFormatter setMaximum:[NSNumber numberWithUnsignedInteger:255]]; - - // iterate through each octet, and test for a number between 0-255 or if it equals '*' - for (NSUInteger i = 0; i < num_octets; ++i) { - NSString* octet = [octets objectAtIndex:i]; - - if ([octet isEqualToString:@"*"]) { // passes - check next octet - continue; - } else if ([numberFormatter numberFromString:octet] == nil) { // fails - not a number and not within our range, return - return NO; - } - } - - return YES; -} - -- (NSString*)extractHostFromUrlString:(NSString*)url -{ - NSURL* aUrl = [NSURL URLWithString:url]; - - if ((aUrl != nil) && ([aUrl scheme] != nil)) { // found scheme - return [aUrl host]; - } else { - return url; - } -} - -- (NSString*)extractSchemeFromUrlString:(NSString*)url -{ - NSURL* aUrl = [NSURL URLWithString:url]; - - if ((aUrl != nil) && ([aUrl scheme] != nil)) { // found scheme - return [aUrl scheme]; - } else { - return kCDVDefaultSchemeName; - } -} - -- (void)processWhitelist -{ - if (self.whitelist == nil) { - NSLog(@"ERROR: CDVWhitelist was not initialized properly, all urls will be disallowed."); - return; - } - - NSMutableDictionary* _expandedWhitelists = [@{kCDVDefaultSchemeName: [NSMutableArray array]} mutableCopy]; - - // only allow known TLDs (since Aug 23rd 2011), and two character country codes - // does not match internationalized domain names with non-ASCII characters - NSString* tld_match = @"(aero|asia|arpa|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|xxx|[a-z][a-z])"; - - // iterate through settings ExternalHosts, check for equality - for (NSString* externalHost in self.whitelist) { - NSString* host = [self extractHostFromUrlString:externalHost]; - NSString* scheme = [self extractSchemeFromUrlString:externalHost]; - - // check for single wildcard '*', if found set allowAll to YES - if ([host isEqualToString:@"*"]) { - [_expandedWhitelists setObject:[NSArray arrayWithObject:host] forKey:scheme]; - continue; - } - - // if this is the first value for this scheme, create a new entry - if ([_expandedWhitelists objectForKey:scheme] == nil) { - [_expandedWhitelists setObject:[NSMutableArray array] forKey:scheme]; - } - - // starts with wildcard match - we make the first '.' optional (so '*.org.apache.cordova' will match 'org.apache.cordova') - NSString* prefix = @"*."; - if ([host hasPrefix:prefix]) { - // replace the first two characters '*.' with our regex - host = [host stringByReplacingCharactersInRange:NSMakeRange(0, [prefix length]) withString:@"(\\s{0}|*.)"]; // the '*' and '.' will be substituted later - } - - // ends with wildcard match for TLD - if (![self isIPv4Address:host] && [host hasSuffix:@".*"]) { - // replace * with tld_match - host = [host stringByReplacingCharactersInRange:NSMakeRange([host length] - 1, 1) withString:tld_match]; - } - // escape periods - since '.' means any character in regex - host = [host stringByReplacingOccurrencesOfString:@"." withString:@"\\."]; - // wildcard is match 1 or more characters (to make it simple, since we are not doing verification whether the hostname is valid) - host = [host stringByReplacingOccurrencesOfString:@"*" withString:@".*"]; - - [[_expandedWhitelists objectForKey:scheme] addObject:host]; - } - - self.expandedWhitelists = _expandedWhitelists; -} - -- (BOOL)schemeIsAllowed:(NSString*)scheme -{ - if ([scheme isEqualToString:@"http"] || - [scheme isEqualToString:@"https"] || - [scheme isEqualToString:@"ftp"] || - [scheme isEqualToString:@"ftps"]) { - return YES; - } - - return (self.expandedWhitelists != nil) && ([self.expandedWhitelists objectForKey:scheme] != nil); -} - -- (BOOL)URLIsAllowed:(NSURL*)url -{ - NSString* scheme = [url scheme]; - - // http[s] and ftp[s] should also validate against the common set in the kCDVDefaultSchemeName list - if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"] || [scheme isEqualToString:@"ftp"] || [scheme isEqualToString:@"ftps"]) { - NSURL* newUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@", kCDVDefaultSchemeName, [url host]]]; - // If it is allowed, we are done. If not, continue to check for the actual scheme-specific list - if ([self URLIsAllowed:newUrl]) { - return YES; - } - } - - // Check that the scheme is supported - if (![self schemeIsAllowed:scheme]) { - return NO; - } - - NSArray* expandedWhitelist = [self.expandedWhitelists objectForKey:scheme]; - - // Are we allowing everything for this scheme? - // TODO: consider just having a static sentinel value for the "allow all" list, so we can use object equality - if (([expandedWhitelist count] == 1) && [[expandedWhitelist objectAtIndex:0] isEqualToString:@"*"]) { - return YES; - } - - // iterate through settings ExternalHosts, check for equality - NSEnumerator* enumerator = [expandedWhitelist objectEnumerator]; - id regex = nil; - NSString* urlHost = [url host]; - - // if the url host IS found in the whitelist, load it in the app (however UIWebViewNavigationTypeOther kicks it out to Safari) - // if the url host IS NOT found in the whitelist, we do nothing - while (regex = [enumerator nextObject]) { - NSPredicate* regex_test = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; - - if ([regex_test evaluateWithObject:urlHost] == YES) { - // if it matches at least one rule, return - return YES; - } - } - - NSLog(@"%@", [self errorStringForURL:url]); - // if we got here, the url host is not in the white-list, do nothing - return NO; -} - -- (NSString*)errorStringForURL:(NSURL*)url -{ - return [NSString stringWithFormat:self.whitelistRejectionFormatString, [url absoluteString]]; -} - -@end diff --git a/CordovaLib/Classes/NSData+Base64.h b/CordovaLib/Classes/NSData+Base64.h deleted file mode 100755 index ffe9c83..0000000 --- a/CordovaLib/Classes/NSData+Base64.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// NSData+Base64.h -// base64 -// -// Created by Matt Gallagher on 2009/06/03. -// Copyright 2009 Matt Gallagher. All rights reserved. -// -// Permission is given to use this source code file, free of charge, in any -// project, commercial or otherwise, entirely at your risk, with the condition -// that any redistribution (in part or whole) of source code must retain -// this copyright and permission notice. Attribution in compiled projects is -// appreciated but not required. -// - -#import - -void *CDVNewBase64Decode( - const char* inputBuffer, - size_t length, - size_t * outputLength); - -char *CDVNewBase64Encode( - const void* inputBuffer, - size_t length, - bool separateLines, - size_t * outputLength); - -@interface NSData (CDVBase64) - -+ (NSData*)dataFromBase64String:(NSString*)aString; -- (NSString*)base64EncodedString; - -@end diff --git a/CordovaLib/Classes/compatibility/0.9.6/CDV.h b/CordovaLib/Classes/compatibility/0.9.6/CDV.h deleted file mode 100755 index 9794fa2..0000000 --- a/CordovaLib/Classes/compatibility/0.9.6/CDV.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - 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. - */ - -// Bridge implementation file for using Cordova plugins in PhoneGap 0.9.6. -// - -/* - Returns YES if it is at least version specified as NSString(X) - Usage: - if (IsAtLeastiOSVersion(@"5.1")) { - // do something for iOS 5.1 or greater - } - */ -#define IsAtLeastiOSVersion(X) ([[[UIDevice currentDevice] systemVersion] compare:X options:NSNumericSearch] != NSOrderedAscending) diff --git a/CordovaLib/Classes/compatibility/0.9.6/CDVPlugin.h b/CordovaLib/Classes/compatibility/0.9.6/CDVPlugin.h deleted file mode 100755 index 7a06e51..0000000 --- a/CordovaLib/Classes/compatibility/0.9.6/CDVPlugin.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - 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. - */ - -// Bridge implementation file for using Cordova plugins in PhoneGap 0.9.6. -// - -#ifdef PHONEGAP_FRAMEWORK - #import -#else - #import "PGPlugin.h" -#endif - -typedef enum { - CDVCommandStatus_NO_RESULT = 0, - CDVCommandStatus_OK, - CDVCommandStatus_CLASS_NOT_FOUND_EXCEPTION, - CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION, - CDVCommandStatus_INSTANTIATION_EXCEPTION, - CDVCommandStatus_MALFORMED_URL_EXCEPTION, - CDVCommandStatus_IO_EXCEPTION, - CDVCommandStatus_INVALID_ACTION, - CDVCommandStatus_JSON_EXCEPTION, - CDVCommandStatus_ERROR -} CDVCommandStatus; - -@interface CDVPlugin : PGPlugin -@end - -@interface CDVPluginResult : PluginResult -@end diff --git a/CordovaLib/Classes/compatibility/0.9.6/CDVPlugin.m b/CordovaLib/Classes/compatibility/0.9.6/CDVPlugin.m deleted file mode 100755 index 52ccd41..0000000 --- a/CordovaLib/Classes/compatibility/0.9.6/CDVPlugin.m +++ /dev/null @@ -1,29 +0,0 @@ -/* - 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. - */ - -// Bridge implementation file for using Cordova plugins in PhoneGap 0.9.6. -// - -#import "CDVPlugin.h" - -@implementation CDVPlugin -@end - -@implementation CDVPluginResult -@end diff --git a/CordovaLib/Classes/compatibility/1.5.0/CDV.h b/CordovaLib/Classes/compatibility/1.5.0/CDV.h deleted file mode 100755 index 1c76eaa..0000000 --- a/CordovaLib/Classes/compatibility/1.5.0/CDV.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - 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. - */ - -// Bridge implementation file for using Cordova > 1.5 plugins in 1.5.0. -// - -#import - -/* - Returns YES if it is at least version specified as NSString(X) - Usage: - if (IsAtLeastiOSVersion(@"5.1")) { - // do something for iOS 5.1 or greater - } - */ -#define IsAtLeastiOSVersion(X) ([[[UIDevice currentDevice] systemVersion] compare:X options:NSNumericSearch] != NSOrderedAscending) diff --git a/CordovaLib/VERSION b/CordovaLib/VERSION deleted file mode 100755 index 24ba9a3..0000000 --- a/CordovaLib/VERSION +++ /dev/null @@ -1 +0,0 @@ -2.7.0 diff --git a/Default-568h@2x.png b/Default-568h@2x.png deleted file mode 100644 index 4200c36..0000000 Binary files a/Default-568h@2x.png and /dev/null differ diff --git a/Default-Landscape@2x~ipad.png b/Default-Landscape@2x~ipad.png deleted file mode 100644 index 5a30f0c..0000000 Binary files a/Default-Landscape@2x~ipad.png and /dev/null differ diff --git a/Default-Landscape~ipad.png b/Default-Landscape~ipad.png deleted file mode 100644 index 60926e3..0000000 Binary files a/Default-Landscape~ipad.png and /dev/null differ diff --git a/Default-Portrait@2x~ipad.png b/Default-Portrait@2x~ipad.png deleted file mode 100644 index 5a30f0c..0000000 Binary files a/Default-Portrait@2x~ipad.png and /dev/null differ diff --git a/Default-Portrait~ipad.png b/Default-Portrait~ipad.png deleted file mode 100644 index 60926e3..0000000 Binary files a/Default-Portrait~ipad.png and /dev/null differ diff --git a/Default.png b/Default.png deleted file mode 100644 index db4a9f5..0000000 Binary files a/Default.png and /dev/null differ diff --git a/Default@2x.png b/Default@2x.png deleted file mode 100644 index bf2352b..0000000 Binary files a/Default@2x.png and /dev/null differ diff --git a/Icon-iPad.png b/Icon-iPad.png deleted file mode 100644 index 4d5087f..0000000 Binary files a/Icon-iPad.png and /dev/null differ diff --git a/Icon-iPad@2x.png b/Icon-iPad@2x.png deleted file mode 100644 index 33bf623..0000000 Binary files a/Icon-iPad@2x.png and /dev/null differ diff --git a/Icon.png b/Icon.png deleted file mode 100644 index 94796b8..0000000 Binary files a/Icon.png and /dev/null differ diff --git a/Icon@2x.png b/Icon@2x.png deleted file mode 100644 index 85929db..0000000 Binary files a/Icon@2x.png and /dev/null differ diff --git a/TDA-Enrichment.xcodeproj/project.pbxproj b/TDA-Enrichment.xcodeproj/project.pbxproj deleted file mode 100644 index 58e8789..0000000 --- a/TDA-Enrichment.xcodeproj/project.pbxproj +++ /dev/null @@ -1,704 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 171C1E6116B7057700976A21 /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 171C1E5E16B7057700976A21 /* Icon.png */; }; - 171C1E6216B7057700976A21 /* Icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 171C1E5F16B7057700976A21 /* Icon@2x.png */; }; - 171C1E6516B7057E00976A21 /* Icon-iPad.png in Resources */ = {isa = PBXBuildFile; fileRef = 171C1E6316B7057E00976A21 /* Icon-iPad.png */; }; - 171C1E6616B7057E00976A21 /* Icon-iPad@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 171C1E6416B7057E00976A21 /* Icon-iPad@2x.png */; }; - 17822C21170ADD210097D7C7 /* libTestFlight.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 17822C1F170ADD210097D7C7 /* libTestFlight.a */; }; - 179D056916B5B2CD00B2EDE5 /* Default-Portrait@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 179D056816B5B2CD00B2EDE5 /* Default-Portrait@2x~ipad.png */; }; - 179D056B16B5B2D900B2EDE5 /* Default-Portrait~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 179D056A16B5B2D900B2EDE5 /* Default-Portrait~ipad.png */; }; - 179D056D16B5B40A00B2EDE5 /* Default-Landscape~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 179D056C16B5B40A00B2EDE5 /* Default-Landscape~ipad.png */; }; - 179D056F16B5B40D00B2EDE5 /* Default-Landscape@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 179D056E16B5B40D00B2EDE5 /* Default-Landscape@2x~ipad.png */; }; - 179D057716B5B43A00B2EDE5 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 179D057616B5B43A00B2EDE5 /* Default-568h@2x.png */; }; - 179D057916B5B44700B2EDE5 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 179D057816B5B44700B2EDE5 /* Default@2x.png */; }; - 179D057B16B5B44A00B2EDE5 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 179D057A16B5B44A00B2EDE5 /* Default.png */; }; - 17AEC07F170F49F20082C85D /* ChildBrowser.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 17AEC078170F49F10082C85D /* ChildBrowser.bundle */; }; - 17AEC081170F49F20082C85D /* ChildBrowserCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 17AEC07B170F49F20082C85D /* ChildBrowserCommand.m */; }; - 17AEC082170F49F20082C85D /* ChildBrowserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 17AEC07D170F49F20082C85D /* ChildBrowserViewController.m */; }; - 17AEC083170F49F20082C85D /* ChildBrowserViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17AEC07E170F49F20082C85D /* ChildBrowserViewController.xib */; }; - 17E2DE2A1721B180006E3762 /* libCordova.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF535109A57CC0062928A /* libCordova.a */; }; - 17E2DE2C1721B1CD006E3762 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17E2DE2B1721B1CD006E3762 /* AssetsLibrary.framework */; }; - 17E9968A16A3F8CE003F3875 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 17E9968916A3F8CE003F3875 /* libz.dylib */; }; - 1D3623260D0F684500981E51 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* AppDelegate.m */; }; - 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; - 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; - 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; - 1F766FE113BBADB100FB74C0 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1F766FDC13BBADB100FB74C0 /* Localizable.strings */; }; - 288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765FC0DF74451002DB57D /* CoreGraphics.framework */; }; - 301BF570109A69640062928A /* www in Resources */ = {isa = PBXBuildFile; fileRef = 301BF56E109A69640062928A /* www */; }; - 301BF5B5109A6A2B0062928A /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF5B4109A6A2B0062928A /* AddressBook.framework */; }; - 301BF5B7109A6A2B0062928A /* AddressBookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF5B6109A6A2B0062928A /* AddressBookUI.framework */; }; - 301BF5B9109A6A2B0062928A /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF5B8109A6A2B0062928A /* AudioToolbox.framework */; }; - 301BF5BB109A6A2B0062928A /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF5BA109A6A2B0062928A /* AVFoundation.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; - 301BF5BD109A6A2B0062928A /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF5BC109A6A2B0062928A /* CFNetwork.framework */; }; - 301BF5BF109A6A2B0062928A /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF5BE109A6A2B0062928A /* CoreLocation.framework */; }; - 301BF5C1109A6A2B0062928A /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF5C0109A6A2B0062928A /* MediaPlayer.framework */; }; - 301BF5C3109A6A2B0062928A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF5C2109A6A2B0062928A /* QuartzCore.framework */; }; - 301BF5C5109A6A2B0062928A /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF5C4109A6A2B0062928A /* SystemConfiguration.framework */; }; - 302D95F114D2391D003F00A1 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 302D95EF14D2391D003F00A1 /* MainViewController.m */; }; - 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 /* 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 */ - -/* Begin PBXContainerItemProxy section */ - 301BF534109A57CC0062928A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = D2AAC07E0554694100DB518D; - remoteInfo = CordovaLib; - }; - 301BF550109A68C00062928A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = D2AAC07D0554694100DB518D; - remoteInfo = CordovaLib; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 1711157316A070A10023A5A9 /* TDA-Enrichment.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = "TDA-Enrichment.entitlements"; path = "TDA-Enrichment/TDA-Enrichment.entitlements"; sourceTree = ""; }; - 171C1E5E16B7057700976A21 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = ""; }; - 171C1E5F16B7057700976A21 /* Icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon@2x.png"; sourceTree = ""; }; - 171C1E6316B7057E00976A21 /* Icon-iPad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-iPad.png"; sourceTree = ""; }; - 171C1E6416B7057E00976A21 /* Icon-iPad@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-iPad@2x.png"; sourceTree = ""; }; - 17822C1F170ADD210097D7C7 /* libTestFlight.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libTestFlight.a; sourceTree = ""; }; - 17822C20170ADD210097D7C7 /* TestFlight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestFlight.h; sourceTree = ""; }; - 179D056816B5B2CD00B2EDE5 /* Default-Portrait@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Portrait@2x~ipad.png"; sourceTree = ""; }; - 179D056A16B5B2D900B2EDE5 /* Default-Portrait~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Portrait~ipad.png"; sourceTree = ""; }; - 179D056C16B5B40A00B2EDE5 /* Default-Landscape~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Landscape~ipad.png"; sourceTree = ""; }; - 179D056E16B5B40D00B2EDE5 /* Default-Landscape@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Landscape@2x~ipad.png"; sourceTree = ""; }; - 179D057616B5B43A00B2EDE5 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; - 179D057816B5B44700B2EDE5 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; - 179D057A16B5B44A00B2EDE5 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; - 17AEC078170F49F10082C85D /* ChildBrowser.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = ChildBrowser.bundle; sourceTree = ""; }; - 17AEC07A170F49F20082C85D /* ChildBrowserCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChildBrowserCommand.h; sourceTree = ""; }; - 17AEC07B170F49F20082C85D /* ChildBrowserCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChildBrowserCommand.m; sourceTree = ""; }; - 17AEC07C170F49F20082C85D /* ChildBrowserViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChildBrowserViewController.h; sourceTree = ""; }; - 17AEC07D170F49F20082C85D /* ChildBrowserViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChildBrowserViewController.m; sourceTree = ""; }; - 17AEC07E170F49F20082C85D /* ChildBrowserViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ChildBrowserViewController.xib; sourceTree = ""; }; - 17E2DE2B1721B1CD006E3762 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; }; - 17E9968916A3F8CE003F3875 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; - 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 1D3623240D0F684500981E51 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = AppDelegate.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 1D3623250D0F684500981E51 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = AppDelegate.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - 1D6058910D05DD3D006BFB54 /* TDA Enrich.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TDA Enrich.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - 1F766FDD13BBADB100FB74C0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Localizable.strings; sourceTree = ""; }; - 1F766FE013BBADB100FB74C0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = Localizable.strings; sourceTree = ""; }; - 288765FC0DF74451002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = main.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CordovaLib.xcodeproj; path = CordovaLib/CordovaLib.xcodeproj; sourceTree = ""; }; - 301BF56E109A69640062928A /* www */ = {isa = PBXFileReference; lastKnownFileType = folder; path = www; sourceTree = SOURCE_ROOT; }; - 301BF5B4109A6A2B0062928A /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; }; - 301BF5B6109A6A2B0062928A /* AddressBookUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBookUI.framework; path = System/Library/Frameworks/AddressBookUI.framework; sourceTree = SDKROOT; }; - 301BF5B8109A6A2B0062928A /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; - 301BF5BA109A6A2B0062928A /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; - 301BF5BC109A6A2B0062928A /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; - 301BF5BE109A6A2B0062928A /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; - 301BF5C0109A6A2B0062928A /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; }; - 301BF5C2109A6A2B0062928A /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; - 301BF5C4109A6A2B0062928A /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; - 302D95EE14D2391D003F00A1 /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = MainViewController.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 302D95EF14D2391D003F00A1 /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = MainViewController.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - 302D95F014D2391D003F00A1 /* MainViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainViewController.xib; sourceTree = ""; }; - 305D5FD0115AB8F900A74A75 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; - 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 /* 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 = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 17E9968A16A3F8CE003F3875 /* libz.dylib in Frameworks */, - 17E2DE2A1721B180006E3762 /* libCordova.a in Frameworks */, - 17E2DE2C1721B1CD006E3762 /* AssetsLibrary.framework in Frameworks */, - 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, - 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, - 288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */, - 301BF5B5109A6A2B0062928A /* AddressBook.framework in Frameworks */, - 301BF5B7109A6A2B0062928A /* AddressBookUI.framework in Frameworks */, - 301BF5B9109A6A2B0062928A /* AudioToolbox.framework in Frameworks */, - 301BF5BB109A6A2B0062928A /* AVFoundation.framework in Frameworks */, - 301BF5BD109A6A2B0062928A /* CFNetwork.framework in Frameworks */, - 301BF5BF109A6A2B0062928A /* CoreLocation.framework in Frameworks */, - 301BF5C1109A6A2B0062928A /* MediaPlayer.framework in Frameworks */, - 301BF5C3109A6A2B0062928A /* QuartzCore.framework in Frameworks */, - 301BF5C5109A6A2B0062928A /* SystemConfiguration.framework in Frameworks */, - 305D5FD1115AB8F900A74A75 /* MobileCoreServices.framework in Frameworks */, - 30E5649213A7FCAF007403D8 /* CoreMedia.framework in Frameworks */, - 17822C21170ADD210097D7C7 /* libTestFlight.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 080E96DDFE201D6D7F000001 /* Classes */ = { - isa = PBXGroup; - children = ( - 302D95EE14D2391D003F00A1 /* MainViewController.h */, - 302D95EF14D2391D003F00A1 /* MainViewController.m */, - 302D95F014D2391D003F00A1 /* MainViewController.xib */, - 1D3623240D0F684500981E51 /* AppDelegate.h */, - 1D3623250D0F684500981E51 /* AppDelegate.m */, - ); - name = Classes; - path = "TDA-Enrichment/Classes"; - sourceTree = SOURCE_ROOT; - }; - 17822C1E170ADD210097D7C7 /* TestFlightSDK1.3.0-beta.2 */ = { - isa = PBXGroup; - children = ( - 17822C1F170ADD210097D7C7 /* libTestFlight.a */, - 17822C20170ADD210097D7C7 /* TestFlight.h */, - ); - path = "TestFlightSDK1.3.0-beta.2"; - sourceTree = ""; - }; - 179D057016B5B41100B2EDE5 /* iPad Launch Images */ = { - isa = PBXGroup; - children = ( - 179D056E16B5B40D00B2EDE5 /* Default-Landscape@2x~ipad.png */, - 179D056C16B5B40A00B2EDE5 /* Default-Landscape~ipad.png */, - 179D056A16B5B2D900B2EDE5 /* Default-Portrait~ipad.png */, - 179D056816B5B2CD00B2EDE5 /* Default-Portrait@2x~ipad.png */, - ); - name = "iPad Launch Images"; - sourceTree = ""; - }; - 179D057116B5B41A00B2EDE5 /* Launch Images */ = { - isa = PBXGroup; - children = ( - 179D058016B5B45F00B2EDE5 /* iPhone Launch Images */, - 179D057016B5B41100B2EDE5 /* iPad Launch Images */, - ); - name = "Launch Images"; - sourceTree = ""; - }; - 179D058016B5B45F00B2EDE5 /* iPhone Launch Images */ = { - isa = PBXGroup; - children = ( - 179D057A16B5B44A00B2EDE5 /* Default.png */, - 179D057816B5B44700B2EDE5 /* Default@2x.png */, - 179D057616B5B43A00B2EDE5 /* Default-568h@2x.png */, - ); - name = "iPhone Launch Images"; - sourceTree = ""; - }; - 179D058116B5B46C00B2EDE5 /* iPhone Icons */ = { - isa = PBXGroup; - children = ( - 171C1E5E16B7057700976A21 /* Icon.png */, - 171C1E5F16B7057700976A21 /* Icon@2x.png */, - ); - name = "iPhone Icons"; - sourceTree = ""; - }; - 179D058216B5B47400B2EDE5 /* iPad Icons */ = { - isa = PBXGroup; - children = ( - 171C1E6316B7057E00976A21 /* Icon-iPad.png */, - 171C1E6416B7057E00976A21 /* Icon-iPad@2x.png */, - ); - name = "iPad Icons"; - sourceTree = ""; - }; - 179D058316B5B47A00B2EDE5 /* Icons */ = { - isa = PBXGroup; - children = ( - 179D058216B5B47400B2EDE5 /* iPad Icons */, - 179D058116B5B46C00B2EDE5 /* iPhone Icons */, - ); - name = Icons; - sourceTree = ""; - }; - 17AEC077170F49F10082C85D /* ChildBrowser */ = { - isa = PBXGroup; - children = ( - 17AEC078170F49F10082C85D /* ChildBrowser.bundle */, - 17AEC07A170F49F20082C85D /* ChildBrowserCommand.h */, - 17AEC07B170F49F20082C85D /* ChildBrowserCommand.m */, - 17AEC07C170F49F20082C85D /* ChildBrowserViewController.h */, - 17AEC07D170F49F20082C85D /* ChildBrowserViewController.m */, - 17AEC07E170F49F20082C85D /* ChildBrowserViewController.xib */, - ); - path = ChildBrowser; - sourceTree = ""; - }; - 19C28FACFE9D520D11CA2CBB /* Products */ = { - isa = PBXGroup; - children = ( - 1D6058910D05DD3D006BFB54 /* TDA Enrich.app */, - ); - name = Products; - sourceTree = ""; - }; - 1F766FDB13BBADB100FB74C0 /* en.lproj */ = { - isa = PBXGroup; - children = ( - 1F766FDC13BBADB100FB74C0 /* Localizable.strings */, - ); - path = en.lproj; - sourceTree = ""; - }; - 1F766FDE13BBADB100FB74C0 /* es.lproj */ = { - isa = PBXGroup; - children = ( - 1F766FDF13BBADB100FB74C0 /* Localizable.strings */, - ); - path = es.lproj; - sourceTree = ""; - }; - 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { - isa = PBXGroup; - children = ( - 179D058316B5B47A00B2EDE5 /* Icons */, - 179D057116B5B41A00B2EDE5 /* Launch Images */, - 17E9968916A3F8CE003F3875 /* libz.dylib */, - 17822C1E170ADD210097D7C7 /* TestFlightSDK1.3.0-beta.2 */, - 1711157316A070A10023A5A9 /* TDA-Enrichment.entitlements */, - 301BF56E109A69640062928A /* www */, - 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */, - 080E96DDFE201D6D7F000001 /* Classes */, - 307C750510C5A3420062BCA9 /* Plugins */, - 29B97315FDCFA39411CA2CEA /* Other Sources */, - 29B97317FDCFA39411CA2CEA /* Resources */, - 29B97323FDCFA39411CA2CEA /* Frameworks */, - 19C28FACFE9D520D11CA2CBB /* Products */, - ); - name = CustomTemplate; - sourceTree = ""; - }; - 29B97315FDCFA39411CA2CEA /* Other Sources */ = { - isa = PBXGroup; - children = ( - 32CA4F630368D1EE00C91783 /* TDA-Enrichment-Prefix.pch */, - 29B97316FDCFA39411CA2CEA /* main.m */, - ); - name = "Other Sources"; - path = "TDA-Enrichment"; - sourceTree = ""; - }; - 29B97317FDCFA39411CA2CEA /* Resources */ = { - isa = PBXGroup; - children = ( - 30A0434214DC770100060A13 /* de.lproj */, - 30A0434514DC770100060A13 /* se.lproj */, - 1F766FDB13BBADB100FB74C0 /* en.lproj */, - 1F766FDE13BBADB100FB74C0 /* es.lproj */, - 3072F99613A8081B00425683 /* Capture.bundle */, - 30E1352610E2C1420031B30D /* config.xml */, - 8D1107310486CEB800E47090 /* TDA-Enrichment-Info.plist */, - ); - name = Resources; - path = "TDA-Enrichment/Resources"; - sourceTree = ""; - }; - 29B97323FDCFA39411CA2CEA /* Frameworks */ = { - isa = PBXGroup; - children = ( - 17E2DE2B1721B1CD006E3762 /* AssetsLibrary.framework */, - 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, - 1D30AB110D05D00D00671497 /* Foundation.framework */, - 288765FC0DF74451002DB57D /* CoreGraphics.framework */, - 301BF5B4109A6A2B0062928A /* AddressBook.framework */, - 301BF5B6109A6A2B0062928A /* AddressBookUI.framework */, - 301BF5B8109A6A2B0062928A /* AudioToolbox.framework */, - 301BF5BA109A6A2B0062928A /* AVFoundation.framework */, - 301BF5BC109A6A2B0062928A /* CFNetwork.framework */, - 301BF5BE109A6A2B0062928A /* CoreLocation.framework */, - 301BF5C0109A6A2B0062928A /* MediaPlayer.framework */, - 301BF5C2109A6A2B0062928A /* QuartzCore.framework */, - 301BF5C4109A6A2B0062928A /* SystemConfiguration.framework */, - 305D5FD0115AB8F900A74A75 /* MobileCoreServices.framework */, - 30E5649113A7FCAF007403D8 /* CoreMedia.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 301BF52E109A57CC0062928A /* Products */ = { - isa = PBXGroup; - children = ( - 301BF535109A57CC0062928A /* libCordova.a */, - ); - name = Products; - sourceTree = ""; - }; - 307C750510C5A3420062BCA9 /* Plugins */ = { - isa = PBXGroup; - children = ( - 17AEC077170F49F10082C85D /* ChildBrowser */, - ); - name = Plugins; - path = "TDA-Enrichment/Plugins"; - sourceTree = SOURCE_ROOT; - }; - 30A0434214DC770100060A13 /* de.lproj */ = { - isa = PBXGroup; - children = ( - 30A0434314DC770100060A13 /* Localizable.strings */, - ); - path = de.lproj; - sourceTree = ""; - }; - 30A0434514DC770100060A13 /* se.lproj */ = { - isa = PBXGroup; - children = ( - 30A0434614DC770100060A13 /* Localizable.strings */, - ); - path = se.lproj; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 1D6058900D05DD3D006BFB54 /* TDA-Enrichment */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "TDA-Enrichment" */; - buildPhases = ( - 304B58A110DAC018002A0835 /* Touch www folder */, - 1D60588D0D05DD3D006BFB54 /* Resources */, - 1D60588E0D05DD3D006BFB54 /* Sources */, - 1D60588F0D05DD3D006BFB54 /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 301BF551109A68C00062928A /* PBXTargetDependency */, - ); - name = "TDA-Enrichment"; - productName = "TDA-Enrichment"; - productReference = 1D6058910D05DD3D006BFB54 /* TDA Enrich.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 29B97313FDCFA39411CA2CEA /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0460; - ORGANIZATIONNAME = "George Garside"; - }; - buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "TDA-Enrichment" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 1; - knownRegions = ( - English, - Japanese, - French, - German, - en, - es, - de, - se, - ); - mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; - projectDirPath = ""; - projectReferences = ( - { - ProductGroup = 301BF52E109A57CC0062928A /* Products */; - ProjectRef = 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */; - }, - ); - projectRoot = ""; - targets = ( - 1D6058900D05DD3D006BFB54 /* TDA-Enrichment */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXReferenceProxy section */ - 301BF535109A57CC0062928A /* libCordova.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libCordova.a; - remoteRef = 301BF534109A57CC0062928A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - -/* Begin PBXResourcesBuildPhase section */ - 1D60588D0D05DD3D006BFB54 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 301BF570109A69640062928A /* www in Resources */, - 30E1352710E2C1420031B30D /* config.xml in Resources */, - 3072F99713A8081B00425683 /* Capture.bundle in Resources */, - 1F766FE113BBADB100FB74C0 /* Localizable.strings in Resources */, - 302D95F214D2391D003F00A1 /* MainViewController.xib in Resources */, - 179D056916B5B2CD00B2EDE5 /* Default-Portrait@2x~ipad.png in Resources */, - 179D056B16B5B2D900B2EDE5 /* Default-Portrait~ipad.png in Resources */, - 179D056D16B5B40A00B2EDE5 /* Default-Landscape~ipad.png in Resources */, - 179D056F16B5B40D00B2EDE5 /* Default-Landscape@2x~ipad.png in Resources */, - 179D057716B5B43A00B2EDE5 /* Default-568h@2x.png in Resources */, - 179D057916B5B44700B2EDE5 /* Default@2x.png in Resources */, - 179D057B16B5B44A00B2EDE5 /* Default.png in Resources */, - 171C1E6116B7057700976A21 /* Icon.png in Resources */, - 171C1E6216B7057700976A21 /* Icon@2x.png in Resources */, - 171C1E6516B7057E00976A21 /* Icon-iPad.png in Resources */, - 171C1E6616B7057E00976A21 /* Icon-iPad@2x.png in Resources */, - 17AEC07F170F49F20082C85D /* ChildBrowser.bundle in Resources */, - 17AEC083170F49F20082C85D /* ChildBrowserViewController.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 304B58A110DAC018002A0835 /* Touch www folder */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Touch www folder"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "touch -cm ${PROJECT_DIR}/www"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 1D60588E0D05DD3D006BFB54 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 1D60589B0D05DD56006BFB54 /* main.m in Sources */, - 1D3623260D0F684500981E51 /* AppDelegate.m in Sources */, - 302D95F114D2391D003F00A1 /* MainViewController.m in Sources */, - 17AEC081170F49F20082C85D /* ChildBrowserCommand.m in Sources */, - 17AEC082170F49F20082C85D /* ChildBrowserViewController.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 301BF551109A68C00062928A /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = CordovaLib; - targetProxy = 301BF550109A68C00062928A /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 1F766FDC13BBADB100FB74C0 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 1F766FDD13BBADB100FB74C0 /* en */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - 1F766FDF13BBADB100FB74C0 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 1F766FE013BBADB100FB74C0 /* es */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - 30A0434314DC770100060A13 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 30A0434414DC770100060A13 /* de */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - 30A0434614DC770100060A13 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 30A0434714DC770100060A13 /* se */, - ); - name = Localizable.strings; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 1D6058940D05DD3E006BFB54 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ENABLE_OBJC_ARC = NO; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "TDA-Enrichment/TDA-Enrichment-Prefix.pch"; - GCC_THUMB_SUPPORT = NO; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - INFOPLIST_FILE = "TDA-Enrichment/TDA-Enrichment-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 4.3; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/TestFlightSDK1.3.0-beta.2\"", - ); - PRODUCT_NAME = "TDA Enrich"; - PROVISIONING_PROFILE = ""; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 1D6058950D05DD3E006BFB54 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ENABLE_OBJC_ARC = NO; - CODE_SIGN_IDENTITY = "iPhone Distribution"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - COPY_PHASE_STRIP = YES; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "TDA-Enrichment/TDA-Enrichment-Prefix.pch"; - GCC_THUMB_SUPPORT = NO; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - INFOPLIST_FILE = "TDA-Enrichment/TDA-Enrichment-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 4.3; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/TestFlightSDK1.3.0-beta.2\"", - ); - PRODUCT_NAME = "TDA Enrich"; - PROVISIONING_PROFILE = ""; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; - C01FCF4F08A954540054247B /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_C_LANGUAGE_STANDARD = c99; - 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; - HEADER_SEARCH_PATHS = ( - "\"$(TARGET_BUILD_DIR)/usr/local/lib/include\"", - "\"$(OBJROOT)/UninstalledProducts/include\"", - "\"$(BUILT_PRODUCTS_DIR)\"", - ); - IPHONEOS_DEPLOYMENT_TARGET = 4.3; - OTHER_LDFLAGS = ( - "-weak_framework", - CoreFoundation, - "-weak_framework", - UIKit, - "-weak_framework", - AVFoundation, - "-weak_framework", - CoreMedia, - "-weak-lSystem", - "-all_load", - "-Obj-C", - ); - PROVISIONING_PROFILE = ""; - SDKROOT = iphoneos; - SKIP_INSTALL = NO; - USER_HEADER_SEARCH_PATHS = ""; - }; - name = Debug; - }; - C01FCF5008A954540054247B /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Distribution"; - "CODE_SIGN_IDENTITY[sdk=*]" = "iPhone Distribution"; - GCC_C_LANGUAGE_STANDARD = c99; - 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; - HEADER_SEARCH_PATHS = ( - "\"$(TARGET_BUILD_DIR)/usr/local/lib/include\"", - "\"$(OBJROOT)/UninstalledProducts/include\"", - "\"$(BUILT_PRODUCTS_DIR)\"", - ); - IPHONEOS_DEPLOYMENT_TARGET = 4.3; - OTHER_LDFLAGS = ( - "-weak_framework", - CoreFoundation, - "-weak_framework", - UIKit, - "-weak_framework", - AVFoundation, - "-weak_framework", - CoreMedia, - "-weak-lSystem", - "-all_load", - "-Obj-C", - ); - PROVISIONING_PROFILE = ""; - "PROVISIONING_PROFILE[sdk=*]" = ""; - SDKROOT = iphoneos; - SKIP_INSTALL = NO; - USER_HEADER_SEARCH_PATHS = ""; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "TDA-Enrichment" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1D6058940D05DD3E006BFB54 /* Debug */, - 1D6058950D05DD3E006BFB54 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C01FCF4E08A954540054247B /* Build configuration list for PBXProject "TDA-Enrichment" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C01FCF4F08A954540054247B /* Debug */, - C01FCF5008A954540054247B /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; -} diff --git a/TDA-Enrichment/Cordova.plist b/TDA-Enrichment/Cordova.plist deleted file mode 100755 index 4a451fa..0000000 --- a/TDA-Enrichment/Cordova.plist +++ /dev/null @@ -1,76 +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 - - Plugins - - 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/Plugins/ChildBrowser/ChildBrowser.bundle/arrow_left.png b/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/arrow_left.png deleted file mode 100755 index 530e12b..0000000 Binary files a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/arrow_left.png and /dev/null differ diff --git a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/arrow_left@2x.png b/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/arrow_left@2x.png deleted file mode 100755 index 530e12b..0000000 Binary files a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/arrow_left@2x.png and /dev/null differ diff --git a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/arrow_right.png b/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/arrow_right.png deleted file mode 100755 index 8b3d855..0000000 Binary files a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/arrow_right.png and /dev/null differ diff --git a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/arrow_right@2x.png b/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/arrow_right@2x.png deleted file mode 100755 index 8b3d855..0000000 Binary files a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/arrow_right@2x.png and /dev/null differ diff --git a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/but_refresh.png b/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/but_refresh.png deleted file mode 100755 index 309b6bd..0000000 Binary files a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/but_refresh.png and /dev/null differ diff --git a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/but_refresh@2x.png b/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/but_refresh@2x.png deleted file mode 100755 index 309b6bd..0000000 Binary files a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/but_refresh@2x.png and /dev/null differ diff --git a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/compass.png b/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/compass.png deleted file mode 100755 index 46a8901..0000000 Binary files a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/compass.png and /dev/null differ diff --git a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/compass@2x.png b/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/compass@2x.png deleted file mode 100755 index 46a8901..0000000 Binary files a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowser.bundle/compass@2x.png and /dev/null differ diff --git a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowserCommand.h b/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowserCommand.h deleted file mode 100755 index 7f8e6ad..0000000 --- a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowserCommand.h +++ /dev/null @@ -1,15 +0,0 @@ -// Created by Jesse MacFadyen on 10-05-29. -// Copyright 2010 Nitobi. All rights reserved. -// Copyright 2012, Randy McMillan - -#import -#import "ChildBrowserViewController.h" - -@interface ChildBrowserCommand : CDVPlugin {} - -@property (nonatomic, strong) ChildBrowserViewController* childBrowser; - -- (void)showWebPage:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; -- (void)onChildLocationChange:(NSString*)newLoc; - -@end diff --git a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowserCommand.m b/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowserCommand.m deleted file mode 100755 index 43ec3b4..0000000 --- a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowserCommand.m +++ /dev/null @@ -1,87 +0,0 @@ -// Created by Jesse MacFadyen on 10-05-29. -// Copyright 2010 Nitobi. All rights reserved. -// Copyright 2012, Randy McMillan - -#import "ChildBrowserCommand.h" -#import -#import - -@implementation ChildBrowserCommand - -@synthesize childBrowser; - -- (void)showWebPage:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options // args: url -{ - /* setting audio session category to "Playback" (since iOS 6) */ - AVAudioSession *audioSession = [AVAudioSession sharedInstance]; - NSError *setCategoryError = nil; - BOOL ok = [audioSession setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError]; - if (!ok) { - NSLog(@"Error setting AVAudioSessionCategoryPlayback: %@", setCategoryError); - }; - - if (self.childBrowser == nil) { -#if __has_feature(objc_arc) - self.childBrowser = [[ChildBrowserViewController alloc] initWithScale:NO]; -#else - self.childBrowser = [[[ChildBrowserViewController alloc] initWithScale:NO] autorelease]; -#endif - self.childBrowser.delegate = self; - self.childBrowser.orientationDelegate = self.viewController; - } - - /* // TODO: Work in progress - NSString* strOrientations = [ options objectForKey:@"supportedOrientations"]; - NSArray* supportedOrientations = [strOrientations componentsSeparatedByString:@","]; - */ - - [self.viewController presentModalViewController:childBrowser animated:YES]; - - NSString* url = (NSString*)[arguments objectAtIndex:0]; - - [self.childBrowser loadURL:url]; -} - -- (void)getPage:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - NSString* url = (NSString*)[arguments objectAtIndex:0]; - - [self.childBrowser loadURL:url]; -} - -- (void)close:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options // args: url -{ - [self.childBrowser closeBrowser]; -} - -- (void)onClose -{ - [self.webView stringByEvaluatingJavaScriptFromString:@"window.plugins.childBrowser.onClose();"]; -} - -- (void)onOpenInSafari -{ - [self.webView stringByEvaluatingJavaScriptFromString:@"window.plugins.childBrowser.onOpenExternal();"]; -} - -- (void)onChildLocationChange:(NSString*)newLoc -{ - NSString* tempLoc = [NSString stringWithFormat:@"%@", newLoc]; - NSString* encUrl = [tempLoc stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - - NSString* jsCallback = [NSString stringWithFormat:@"window.plugins.childBrowser.onLocationChange('%@');", encUrl]; - - [self.webView stringByEvaluatingJavaScriptFromString:jsCallback]; -} - - -#if !__has_feature(objc_arc) -- (void)dealloc -{ - self.childBrowser = nil; - - [super dealloc]; -} -#endif - -@end diff --git a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowserViewController.h b/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowserViewController.h deleted file mode 100755 index 07f0183..0000000 --- a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowserViewController.h +++ /dev/null @@ -1,54 +0,0 @@ -// Created by Jesse MacFadyen on 10-05-29. -// Copyright 2010 Nitobi. All rights reserved. -// Copyright 2012, Randy McMillan - -#import - -@protocol ChildBrowserDelegate - -/* - * onChildLocationChanging:newLoc - * - * Discussion: - * Invoked when a new page has loaded - */ -- (void)onChildLocationChange:(NSString*)newLoc; -- (void)onOpenInSafari; -- (void)onClose; - -@end - -@protocol CDVOrientationDelegate - -- (NSUInteger)supportedInterfaceOrientations; -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; -- (BOOL)shouldAutorotate; - -@end - -@interface ChildBrowserViewController : UIViewController {} - -@property (nonatomic, strong) IBOutlet UIWebView* webView; -@property (nonatomic, strong) IBOutlet UIBarButtonItem* closeBtn; -@property (nonatomic, strong) IBOutlet UIBarButtonItem* refreshBtn; -@property (nonatomic, strong) IBOutlet UILabel* addressLabel; -@property (nonatomic, strong) IBOutlet UIBarButtonItem* backBtn; -@property (nonatomic, strong) IBOutlet UIBarButtonItem* fwdBtn; -@property (nonatomic, strong) IBOutlet UIBarButtonItem* safariBtn; -@property (nonatomic, strong) IBOutlet UIActivityIndicatorView* spinner; - -// unsafe_unretained is equivalent to assign - used to prevent retain cycles in the two properties below -@property (nonatomic, unsafe_unretained) id delegate; -@property (nonatomic, unsafe_unretained) id orientationDelegate; - -@property (copy) NSString* imageURL; -@property (assign) BOOL isImage; -@property (assign) BOOL scaleEnabled; - -- (ChildBrowserViewController*)initWithScale:(BOOL)enabled; -- (IBAction)onDoneButtonPress:(id)sender; -- (IBAction)onSafariButtonPress:(id)sender; -- (void)loadURL:(NSString*)url; -- (void)closeBrowser; - -@end diff --git a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowserViewController.m b/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowserViewController.m deleted file mode 100755 index 8160bd5..0000000 --- a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowserViewController.m +++ /dev/null @@ -1,228 +0,0 @@ -// / Created by Jesse MacFadyen on 10-05-29. -// Copyright 2010 Nitobi. All rights reserved. -// Copyright 2012, Randy McMillan - -#import "ChildBrowserViewController.h" - -@implementation ChildBrowserViewController - -@synthesize imageURL, isImage; -@synthesize delegate, orientationDelegate; -@synthesize spinner, webView, addressLabel; -@synthesize closeBtn, refreshBtn, backBtn, fwdBtn, safariBtn; - -/* - // The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad. -- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { - if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) { - // Custom initialization - } - return self; -} -*/ - -+ (NSString*)resolveImageResource:(NSString*)resource -{ - NSString* systemVersion = [[UIDevice currentDevice] systemVersion]; - BOOL isLessThaniOS4 = ([systemVersion compare:@"4.0" options:NSNumericSearch] == NSOrderedAscending); - - if (isLessThaniOS4) { - return [NSString stringWithFormat:@"%@.png", resource]; - } else { - if (([[UIScreen mainScreen] respondsToSelector:@selector(scale)] == YES) && ([[UIScreen mainScreen] scale] == 2.00)) { - return [NSString stringWithFormat:@"%@@2x.png", resource]; - } - } - - return resource; // if all else fails -} - -- (ChildBrowserViewController*)initWithScale:(BOOL)enabled -{ - self = [super init]; - self.scaleEnabled = enabled; - return self; -} - -// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. -- (void)viewDidLoad -{ - [super viewDidLoad]; - - self.refreshBtn.image = [UIImage imageNamed:[[self class] resolveImageResource:@"ChildBrowser.bundle/but_refresh"]]; - self.backBtn.image = [UIImage imageNamed:[[self class] resolveImageResource:@"ChildBrowser.bundle/arrow_left"]]; - self.fwdBtn.image = [UIImage imageNamed:[[self class] resolveImageResource:@"ChildBrowser.bundle/arrow_right"]]; - self.safariBtn.image = [UIImage imageNamed:[[self class] resolveImageResource:@"ChildBrowser.bundle/compass"]]; - - self.webView.delegate = self; - self.webView.scalesPageToFit = TRUE; - self.webView.backgroundColor = [UIColor whiteColor]; - NSLog(@"View did load"); -} - -- (void)didReceiveMemoryWarning -{ - // Releases the view if it doesn't have a superview. - [super didReceiveMemoryWarning]; - - // Release any cached data, images, etc that aren't in use. -} - -- (void)viewDidUnload -{ - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; - NSLog(@"View did UN-load"); -} - -- (void)dealloc -{ - self.webView.delegate = nil; - self.delegate = nil; - self.orientationDelegate = nil; - -#if !__has_feature(objc_arc) - self.webView = nil; - self.closeBtn = nil; - self.refreshBtn = nil; - self.addressLabel = nil; - self.backBtn = nil; - self.fwdBtn = nil; - self.safariBtn = nil; - self.spinner = nil; - - [super dealloc]; -#endif -} - -- (void)closeBrowser -{ - if (self.delegate != nil) { - [self.delegate onClose]; - } - if ([self respondsToSelector:@selector(presentingViewController)]) { - // Reference UIViewController.h Line:179 for update to iOS 5 difference - @RandyMcMillan - [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[self parentViewController] dismissModalViewControllerAnimated:YES]; - } -} - -- (IBAction)onDoneButtonPress:(id)sender -{ - [self closeBrowser]; - NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]; - [self.webView loadRequest:request]; -} - -- (IBAction)onSafariButtonPress:(id)sender -{ - if (self.delegate != nil) { - [self.delegate onOpenInSafari]; - } - - if (self.isImage) { - NSURL* pURL = [NSURL URLWithString:self.imageURL]; - [[UIApplication sharedApplication] openURL:pURL]; - } else { - NSURLRequest* request = self.webView.request; - [[UIApplication sharedApplication] openURL:request.URL]; - } -} - -- (void)loadURL:(NSString*)url -{ - NSLog(@"Opening Url : %@", url); - - if ([url hasSuffix:@".png"] || - [url hasSuffix:@".jpg"] || - [url hasSuffix:@".jpeg"] || - [url hasSuffix:@".bmp"] || - [url hasSuffix:@".gif"]) { - self.imageURL = nil; - self.imageURL = url; - self.isImage = YES; - NSString* htmlText = @""; - htmlText = [htmlText stringByReplacingOccurrencesOfString:@"IMGSRC" withString:url]; - - [self.webView loadHTMLString:htmlText baseURL:[NSURL URLWithString:@""]]; - } else { - self.imageURL = @""; - self.isImage = NO; - NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]]; - [self.webView loadRequest:request]; - } - self.webView.hidden = NO; -} - -- (void)webViewDidStartLoad:(UIWebView*)sender -{ - self.addressLabel.text = @"Loading..."; - self.backBtn.enabled = self.webView.canGoBack; - self.fwdBtn.enabled = self.webView.canGoForward; - - [self.spinner startAnimating]; -} - -- (void)webViewDidFinishLoad:(UIWebView*)sender -{ - NSURLRequest* request = self.webView.request; - - NSLog(@"New Address is : %@", request.URL.absoluteString); - self.addressLabel.text = request.URL.absoluteString; - self.backBtn.enabled = self.webView.canGoBack; - self.fwdBtn.enabled = self.webView.canGoForward; - [self.spinner stopAnimating]; - - if (self.delegate != NULL) { - [self.delegate onChildLocationChange:request.URL.absoluteString]; - } -} - -/*- (void)webView:(UIWebView *)wv didFailLoadWithError:(NSError *)error { - NSLog (@"webView:didFailLoadWithError"); - [spinner stopAnimating]; - addressLabel.text = @"Failed"; - if (error != NULL) { - UIAlertView *errorAlert = [[UIAlertView alloc] - initWithTitle: [error localizedDescription] - message: [error localizedFailureReason] - delegate:nil - cancelButtonTitle:@"OK" - otherButtonTitles:nil]; - [errorAlert show]; - [errorAlert release]; - } -} -*/ - -#pragma mark CDVOrientationDelegate - -- (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 UIInterfaceOrientationMaskPortrait; -} - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) { - return [self.orientationDelegate shouldAutorotateToInterfaceOrientation:interfaceOrientation]; - } - - return YES; -} - -@end diff --git a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowserViewController.xib b/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowserViewController.xib deleted file mode 100755 index cc8dd65..0000000 --- a/TDA-Enrichment/Plugins/ChildBrowser/ChildBrowserViewController.xib +++ /dev/null @@ -1,875 +0,0 @@ - - - - 768 - 10K540 - 851 - 1038.36 - 461.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 141 - - - YES - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - YES - - - - YES - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 292 - - YES - - - -2147483374 - {480, 229} - - - - 1 - MCAwIDAAA - - YES - YES - IBCocoaTouchFramework - 1 - YES - - - - 266 - {{0, 256}, {480, 44}} - - - NO - NO - IBCocoaTouchFramework - 1 - - YES - - IBCocoaTouchFramework - 1 - - 0 - - - IBCocoaTouchFramework - - 5 - - - IBCocoaTouchFramework - - - - IBCocoaTouchFramework - - 5 - - - IBCocoaTouchFramework - 32 - - - - IBCocoaTouchFramework - - 5 - - - IBCocoaTouchFramework - 32 - - - - IBCocoaTouchFramework - - 5 - - - IBCocoaTouchFramework - 32 - - - - IBCocoaTouchFramework - - 5 - - - - - - 270 - {{5, 230}, {418, 21}} - - - - 4 - MC42NjY2NjY2OSAwAA - - NO - YES - NO - IBCocoaTouchFramework - Loading... - - Helvetica - 13 - 16 - - - 3 - MQA - - - 1 - NO - 10 - - - - -2147483383 - {{454, 231}, {20, 20}} - - NO - NO - NO - IBCocoaTouchFramework - - - {{0, 20}, {480, 300}} - - - 3 - MC41AA - - 2 - - - - - 3 - - IBCocoaTouchFramework - - - - - YES - - - webView - - - - 17 - - - - addressLabel - - - - 18 - - - - backBtn - - - - 19 - - - - fwdBtn - - - - 22 - - - - refreshBtn - - - - 23 - - - - onDoneButtonPress: - - - - 26 - - - - reload - - - - 27 - - - - goBack - - - - 28 - - - - goForward - - - - 29 - - - - onSafariButtonPress: - - - - 31 - - - - view - - - - 35 - - - - spinner - - - - 36 - - - - safariBtn - - - - 40 - - - - - YES - - 0 - - - - - - 1 - - - YES - - - - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - - - 6 - - - YES - - - - - - - - - - - - - - - 7 - - - - - 8 - - - Bar Button Item (Reload) - - - 9 - - - Bar Button Item (Go Back) - - - 10 - - - Bar Button Item (Go Forward) - - - 11 - - - Bar Button Item (Safari) - - - 13 - - - - - 14 - - - - - 15 - - - - - 32 - - - - - 37 - - - - - 38 - - - - - 39 - - - - - - - YES - - YES - -1.CustomClassName - -2.CustomClassName - 1.IBEditorWindowLastContentRect - 1.IBPluginDependency - 10.IBPluginDependency - 11.IBPluginDependency - 13.IBPluginDependency - 13.IBViewBoundsToFrameTransform - 14.IBPluginDependency - 15.IBPluginDependency - 32.IBPluginDependency - 32.IBViewBoundsToFrameTransform - 37.IBPluginDependency - 38.IBPluginDependency - 39.IBPluginDependency - 4.IBPluginDependency - 4.IBViewBoundsToFrameTransform - 6.IBPluginDependency - 6.IBViewBoundsToFrameTransform - 7.IBPluginDependency - 8.IBPluginDependency - 9.IBPluginDependency - - - YES - ChildBrowserViewController - UIResponder - {{250, 643}, {480, 320}} - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - P4AAAL+AAABCoAAAwygAAA - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - P4AAAL+AAABD5gAAw3kAAA - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - P4AAAL+AAABB8AAAwwUAAA - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - P4AAAL+AAAAAAAAAw10AAA - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - YES - - - - - YES - - - YES - - - - 40 - - - - YES - - ChildBrowserViewController - UIViewController - - YES - - YES - onDoneButtonPress: - onSafariButtonPress: - - - YES - id - id - - - - YES - - YES - onDoneButtonPress: - onSafariButtonPress: - - - YES - - onDoneButtonPress: - id - - - onSafariButtonPress: - id - - - - - YES - - YES - addressLabel - backBtn - closeBtn - delegate - fwdBtn - refreshBtn - safariBtn - spinner - webView - - - YES - UILabel - UIBarButtonItem - UIBarButtonItem - id - UIBarButtonItem - UIBarButtonItem - UIBarButtonItem - UIActivityIndicatorView - UIWebView - - - - YES - - YES - addressLabel - backBtn - closeBtn - delegate - fwdBtn - refreshBtn - safariBtn - spinner - webView - - - YES - - addressLabel - UILabel - - - backBtn - UIBarButtonItem - - - closeBtn - UIBarButtonItem - - - delegate - id - - - fwdBtn - UIBarButtonItem - - - refreshBtn - UIBarButtonItem - - - safariBtn - UIBarButtonItem - - - spinner - UIActivityIndicatorView - - - webView - UIWebView - - - - - IBProjectSource - Plugins/ChildBrowser/ChildBrowserViewController.h - - - - - YES - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSError.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSFileManager.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyValueCoding.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyValueObserving.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyedArchiver.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSObject.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSRunLoop.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSThread.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURL.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURLConnection.h - - - - NSObject - - IBFrameworkSource - QuartzCore.framework/Headers/CAAnimation.h - - - - NSObject - - IBFrameworkSource - QuartzCore.framework/Headers/CALayer.h - - - - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UIAccessibility.h - - - - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UINibLoading.h - - - - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UIResponder.h - - - - UIActivityIndicatorView - UIView - - IBFrameworkSource - UIKit.framework/Headers/UIActivityIndicatorView.h - - - - UIBarButtonItem - UIBarItem - - IBFrameworkSource - UIKit.framework/Headers/UIBarButtonItem.h - - - - UIBarItem - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UIBarItem.h - - - - UILabel - UIView - - IBFrameworkSource - UIKit.framework/Headers/UILabel.h - - - - UIResponder - NSObject - - - - UISearchBar - UIView - - IBFrameworkSource - UIKit.framework/Headers/UISearchBar.h - - - - UISearchDisplayController - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UISearchDisplayController.h - - - - UIToolbar - UIView - - IBFrameworkSource - UIKit.framework/Headers/UIToolbar.h - - - - UIView - - IBFrameworkSource - UIKit.framework/Headers/UIPrintFormatter.h - - - - UIView - - IBFrameworkSource - UIKit.framework/Headers/UITextField.h - - - - UIView - UIResponder - - IBFrameworkSource - UIKit.framework/Headers/UIView.h - - - - UIViewController - - IBFrameworkSource - MediaPlayer.framework/Headers/MPMoviePlayerViewController.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UINavigationController.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UIPopoverController.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UISplitViewController.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UITabBarController.h - - - - UIViewController - UIResponder - - IBFrameworkSource - UIKit.framework/Headers/UIViewController.h - - - - UIWebView - UIView - - IBFrameworkSource - UIKit.framework/Headers/UIWebView.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - - 3 - 141 - - diff --git a/TDA-Enrichment/Resources/Capture.bundle/controls_bg.png b/TDA-Enrichment/Resources/Capture.bundle/controls_bg.png deleted file mode 100755 index 784e9c7..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/controls_bg.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/controls_bg@2x.png b/TDA-Enrichment/Resources/Capture.bundle/controls_bg@2x.png deleted file mode 100755 index 1e28c6d..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/controls_bg@2x.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/controls_bg@2x~ipad.png b/TDA-Enrichment/Resources/Capture.bundle/controls_bg@2x~ipad.png deleted file mode 100755 index d4e3483..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/controls_bg@2x~ipad.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/controls_bg~ipad.png b/TDA-Enrichment/Resources/Capture.bundle/controls_bg~ipad.png deleted file mode 100755 index efbef8a..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/controls_bg~ipad.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/microphone-568h@2x~iphone.png b/TDA-Enrichment/Resources/Capture.bundle/microphone-568h@2x~iphone.png deleted file mode 100755 index 8e80f73..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/microphone-568h@2x~iphone.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/microphone.png b/TDA-Enrichment/Resources/Capture.bundle/microphone.png deleted file mode 100755 index 155b88c..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/microphone.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/microphone@2x.png b/TDA-Enrichment/Resources/Capture.bundle/microphone@2x.png deleted file mode 100755 index 79ef16b..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/microphone@2x.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/microphone@2x~ipad.png b/TDA-Enrichment/Resources/Capture.bundle/microphone@2x~ipad.png deleted file mode 100755 index af1bbb2..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/microphone@2x~ipad.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/microphone~ipad.png b/TDA-Enrichment/Resources/Capture.bundle/microphone~ipad.png deleted file mode 100755 index ef1c472..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/microphone~ipad.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/record_button.png b/TDA-Enrichment/Resources/Capture.bundle/record_button.png deleted file mode 100755 index ceb9589..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/record_button.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/record_button@2x.png b/TDA-Enrichment/Resources/Capture.bundle/record_button@2x.png deleted file mode 100755 index d6ce302..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/record_button@2x.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/record_button@2x~ipad.png b/TDA-Enrichment/Resources/Capture.bundle/record_button@2x~ipad.png deleted file mode 100755 index 0ac2e67..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/record_button@2x~ipad.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/record_button~ipad.png b/TDA-Enrichment/Resources/Capture.bundle/record_button~ipad.png deleted file mode 100755 index d8e24a4..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/record_button~ipad.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/recording_bg.png b/TDA-Enrichment/Resources/Capture.bundle/recording_bg.png deleted file mode 100755 index bafc087..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/recording_bg.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/recording_bg@2x.png b/TDA-Enrichment/Resources/Capture.bundle/recording_bg@2x.png deleted file mode 100755 index 798490b..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/recording_bg@2x.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/recording_bg@2x~ipad.png b/TDA-Enrichment/Resources/Capture.bundle/recording_bg@2x~ipad.png deleted file mode 100755 index a1b7208..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/recording_bg@2x~ipad.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/recording_bg~ipad.png b/TDA-Enrichment/Resources/Capture.bundle/recording_bg~ipad.png deleted file mode 100755 index 3b467f6..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/recording_bg~ipad.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/stop_button.png b/TDA-Enrichment/Resources/Capture.bundle/stop_button.png deleted file mode 100755 index 9c31838..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/stop_button.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/stop_button@2x.png b/TDA-Enrichment/Resources/Capture.bundle/stop_button@2x.png deleted file mode 100755 index 8cf657e..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/stop_button@2x.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/stop_button@2x~ipad.png b/TDA-Enrichment/Resources/Capture.bundle/stop_button@2x~ipad.png deleted file mode 100755 index 88b606c..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/stop_button@2x~ipad.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/Capture.bundle/stop_button~ipad.png b/TDA-Enrichment/Resources/Capture.bundle/stop_button~ipad.png deleted file mode 100755 index 59bb7a5..0000000 Binary files a/TDA-Enrichment/Resources/Capture.bundle/stop_button~ipad.png and /dev/null differ diff --git a/TDA-Enrichment/Resources/de.lproj/Localizable.strings b/TDA-Enrichment/Resources/de.lproj/Localizable.strings deleted file mode 100755 index f1cdb42..0000000 --- a/TDA-Enrichment/Resources/de.lproj/Localizable.strings +++ /dev/null @@ -1,26 +0,0 @@ -/* - 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. - */ - - -// accessibility label for recording button -"toggle audio recording" = "starten/beenden der Tonaufnahme"; -// notification spoken by VoiceOver when timed recording finishes -"timed recording complete" = "programmierte Aufnahme beendet"; -// accessibility hint for display of recorded elapsed time -"recorded time in minutes and seconds" = "aufgenommene Zeit in Minuten und Sekunden"; \ No newline at end of file diff --git a/TDA-Enrichment/Resources/en.lproj/Localizable.strings b/TDA-Enrichment/Resources/en.lproj/Localizable.strings deleted file mode 100755 index 8972684..0000000 --- a/TDA-Enrichment/Resources/en.lproj/Localizable.strings +++ /dev/null @@ -1,25 +0,0 @@ -/* - 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. - */ - -// accessibility label for recording button -"toggle audio recording" = "toggle audio recording"; -// notification spoken by VoiceOver when timed recording finishes -"timed recording complete" = "timed recording complete"; -// accessibility hint for display of recorded elapsed time -"recorded time in minutes and seconds" = "recorded time in minutes and seconds"; \ No newline at end of file diff --git a/TDA-Enrichment/Resources/es.lproj/Localizable.strings b/TDA-Enrichment/Resources/es.lproj/Localizable.strings deleted file mode 100755 index 23831e6..0000000 --- a/TDA-Enrichment/Resources/es.lproj/Localizable.strings +++ /dev/null @@ -1,25 +0,0 @@ -/* - 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. - */ - -// accessibility label for recording button -"toggle audio recording" = "grabación de audio cambiar"; -// notification spoken by VoiceOver when timed recording finishes -"timed recording complete" = "tiempo de grabación completo"; -// accessibility hint for display of recorded elapsed time -"recorded time in minutes and seconds" = "tiempo registrado en minutos y segundos"; \ No newline at end of file diff --git a/TDA-Enrichment/Resources/se.lproj/Localizable.strings b/TDA-Enrichment/Resources/se.lproj/Localizable.strings deleted file mode 100755 index 0af9646..0000000 --- a/TDA-Enrichment/Resources/se.lproj/Localizable.strings +++ /dev/null @@ -1,26 +0,0 @@ -/* - 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. - */ - - -// accessibility label for recording button -"toggle audio recording" = "börja/avsluta inspelning"; -// notification spoken by VoiceOver when timed recording finishes -"timed recording complete" = "inspelning har avslutad"; -// accessibility hint for display of recorded elapsed time -"recorded time in minutes and seconds" = "inspelad tid in minuter och sekund"; \ No newline at end of file diff --git a/TDA-Enrichment/TDA-Enrichment.entitlements b/TDA-Enrichment/TDA-Enrichment.entitlements deleted file mode 100644 index ae7fe68..0000000 --- a/TDA-Enrichment/TDA-Enrichment.entitlements +++ /dev/null @@ -1,12 +0,0 @@ - - - - - com.apple.developer.ubiquity-kvstore-identifier - $(TeamIdentifierPrefix)$(CFBundleIdentifier) - keychain-access-groups - - $(AppIdentifierPrefix)com.georgegarside.tda-enrichment - - - diff --git a/TDA-Enrichment/config.xml b/TDA-Enrichment/config.xml deleted file mode 100644 index ed3a2f3..0000000 --- a/TDA-Enrichment/config.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/TestFlightSDK1.3.0-beta.2/TestFlight.h b/TestFlightSDK1.3.0-beta.2/TestFlight.h deleted file mode 100644 index d35345a..0000000 --- a/TestFlightSDK1.3.0-beta.2/TestFlight.h +++ /dev/null @@ -1,119 +0,0 @@ -// -// TestFlight.h -// libTestFlight -// -// Created by Jonathan Janzen on 06/11/11. -// Copyright 2011 TestFlight. All rights reserved. - -#import -#define TESTFLIGHT_SDK_VERSION @"1.3.0-beta.2" -#undef TFLog - -#if __cplusplus -extern "C" { -#endif - /* - * Remote Logging - * Note: All Logging is synchronous, see the README for more information. - */ - void TFLog(NSString *format, ...); - void TFLogv(NSString *format, va_list arg_list); -#if __cplusplus -} -#endif - -/** - * TestFlight object - * All methods are class level - */ -@interface TestFlight : NSObject - -/** - * Add custom environment information - * If you want to track custom information such as a user name from your application you can add it here - * - * @param information A string containing the environment you are storing - * @param key The key to store the information with - */ -+ (void)addCustomEnvironmentInformation:(NSString *)information forKey:(NSString*)key; - - -/** - * Starts a TestFlight session using the Application Token for this Application - * - * @param applicationToken Will be the application token for the current application. - * The token for this application can be retrieved by going to https://testflightapp.com/dashboard/applications/ - * selecting this application from the list then selecting SDK. - */ -+ (void)takeOff:(NSString *)applicationToken; - -/** - * Sets custom options - * - * @param options NSDictionary containing the options you want to set. Available options are described below at "TestFlight Option Keys" - * - */ -+ (void)setOptions:(NSDictionary*)options; - -/** - * Track when a user has passed a checkpoint after the flight has taken off. Eg. passed level 1, posted high score. - * Checkpoints are sent in the background. - * Note: The checkpoint is logged synchronously (See TFLog and TFOptionLogOnCheckpoint for more information). - * - * @param checkpointName The name of the checkpoint, this should be a static string - */ -+ (void)passCheckpoint:(NSString *)checkpointName; - -/** - * Use to manually flush data to TestFlight. - * TestFlight automatically flushes at the end of a session and every `TFOptionFlushSecondsInterval`. - */ -+ (void)flush; - -/** - * Submits custom feedback to the site. Sends the data in feedback to the site. This is to be used as the method to submit - * feedback from custom feedback forms. - * - * @param feedback Your users feedback, method does nothing if feedback is nil - */ -+ (void)submitFeedback:(NSString*)feedback; - -/** - * Sets the Device Identifier. - * - * !! DO NOT CALL IN SUBMITTED APP STORE APP. - * - * !! MUST BE CALLED BEFORE +takeOff: - * - * This method should only be used during testing so that you can identify a testers test data with them. - * If you do not provide the identifier you will still see all session data, with checkpoints - * and logs, but the data will be anonymized. - * - * It is recommended that you only use this method during testing. - * Apple may reject your app if left in a submitted app. - * - * Use: - * Only use this with the Apple device UDID. DO NOT use Open ID or your own identifier. - * [TestFlight setDeviceIdentifier:[[UIDevice currentDevice] uniqueIdentifier]]; - * - * @param deviceIdentifer The current devices device identifier - */ -+ (void)setDeviceIdentifier:(NSString*)deviceIdentifer; - -@end - - -/** - * TestFlight Option Keys - * - * Pass these as keys to the dictionary you pass to +`[TestFlight setOptions:]`. - * The values should be NSNumber BOOLs (`[NSNumber numberWithBool:YES]` or `@YES`) - */ -extern NSString *const TFOptionDisableInAppUpdates; // Defaults to @NO. Setting to @YES, disables the in app update screen shown in BETA apps when there is a new version available on TestFlight. -extern NSString *const TFOptionFlushSecondsInterval; // Defaults to @60. Set to a number. @0 turns off the flush timer. -extern NSString *const TFOptionLogOnCheckpoint; // Defaults to @YES. Because logging is synchronous, if you have a high preformance app, you might want to turn this off. -extern NSString *const TFOptionLogToConsole; // Defaults to @YES. Prints remote logs to Apple System Log. -extern NSString *const TFOptionLogToSTDERR; // Defaults to @YES. Sends remote logs to STDERR when debugger is attached. -extern NSString *const TFOptionReinstallCrashHandlers; // If set to @YES: Reinstalls crash handlers, to be used if a third party library installs crash handlers overtop of the TestFlight Crash Handlers. -extern NSString *const TFOptionSendLogOnlyOnCrash; // Defaults to @NO. Setting to @YES stops remote logs from being sent when sessions end. They would only be sent in the event of a crash. - diff --git a/TestFlightSDK1.3.0-beta.2/libTestFlight.a b/TestFlightSDK1.3.0-beta.2/libTestFlight.a deleted file mode 100644 index 5eb8812..0000000 Binary files a/TestFlightSDK1.3.0-beta.2/libTestFlight.a and /dev/null differ diff --git a/androidicons/hdpi.png b/androidicons/hdpi.png deleted file mode 100644 index 2e42a8e..0000000 Binary files a/androidicons/hdpi.png and /dev/null differ diff --git a/androidicons/ldpi.png b/androidicons/ldpi.png deleted file mode 100644 index 622dcc4..0000000 Binary files a/androidicons/ldpi.png and /dev/null differ diff --git a/androidicons/mdpi.png b/androidicons/mdpi.png deleted file mode 100644 index 18fabb3..0000000 Binary files a/androidicons/mdpi.png and /dev/null differ diff --git a/androidicons/xhidpi.png b/androidicons/xhidpi.png deleted file mode 100644 index 8459498..0000000 Binary files a/androidicons/xhidpi.png and /dev/null differ diff --git a/config.xml b/config.xml new file mode 100644 index 0000000..3051b49 --- /dev/null +++ b/config.xml @@ -0,0 +1,12 @@ + + + TDA-Enrichment + + Always have access to Thomas Deacon Academy's Sports Enrichment with the official TDA Enrichment app. + + + George Garside + + + + diff --git a/cordova/emulate b/cordova/emulate deleted file mode 100755 index f26cb3a..0000000 --- a/cordova/emulate +++ /dev/null @@ -1,55 +0,0 @@ -#! /bin/bash -# -# 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:-$PROJECT_PATH/build/$PROJECT_NAME.app} -DEVICE_FAMILY=${2:-${DEVICE_FAMILY:-iphone}} - -if [ ! -d "$APP_PATH" ]; then - echo "Project '$APP_PATH' is not built. Building." - $CORDOVA_PATH/build || 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" --family "$DEVICE_FAMILY" --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 - diff --git a/cordova/run b/cordova/run deleted file mode 100755 index ef7198e..0000000 --- a/cordova/run +++ /dev/null @@ -1,58 +0,0 @@ -#! /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/build || 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 - diff --git a/hooks/README.md b/hooks/README.md new file mode 100644 index 0000000..66f2873 --- /dev/null +++ b/hooks/README.md @@ -0,0 +1,196 @@ + +# Cordova Hooks + +Cordova Hooks represent special scripts which could be added by application and plugin developers or even by your own build system to customize cordova commands. Hook scripts could be defined by adding them to the special predefined folder (`/hooks`) or via configuration files (`config.xml` and `plugin.xml`) and run serially in the following order: +* Application hooks from `/hooks`; +* Application hooks from `config.xml`; +* Plugin hooks from `plugins/.../plugin.xml`. + +__Remember__: Make your scripts executable. + +__Note__: `.cordova/hooks` directory is also supported for backward compatibility, but we don't recommend using it as it is deprecated. + +## Supported hook types +The following hook types are supported: + + after_build/ + after_compile/ + after_docs/ + after_emulate/ + after_platform_add/ + after_platform_rm/ + after_platform_ls/ + after_plugin_add/ + after_plugin_ls/ + after_plugin_rm/ + after_plugin_search/ + after_plugin_install/ <-- Plugin hooks defined in plugin.xml are executed exclusively for a plugin being installed + after_prepare/ + after_run/ + after_serve/ + before_build/ + before_compile/ + before_docs/ + before_emulate/ + before_platform_add/ + before_platform_rm/ + before_platform_ls/ + before_plugin_add/ + before_plugin_ls/ + before_plugin_rm/ + before_plugin_search/ + before_plugin_install/ <-- Plugin hooks defined in plugin.xml are executed exclusively for a plugin being installed + before_plugin_uninstall/ <-- Plugin hooks defined in plugin.xml are executed exclusively for a plugin being uninstalled + before_prepare/ + before_run/ + before_serve/ + pre_package/ <-- Windows 8 and Windows Phone only. + +## Ways to define hooks +### Via '/hooks' directory +To execute custom action when corresponding hook type is fired, use hook type as a name for a subfolder inside 'hooks' directory and place you script file here, for example: + + # script file will be automatically executed after each build + hooks/after_build/after_build_custom_action.js + + +### Config.xml + +Hooks can be defined in project's `config.xml` using `` elements, for example: + + + + + + + + + + ... + + + + + + + ... + + +### Plugin hooks (plugin.xml) + +As a plugin developer you can define hook scripts using `` elements in a `plugin.xml` like that: + + + + + + + + ... + + +`before_plugin_install`, `after_plugin_install`, `before_plugin_uninstall` plugin hooks will be fired exclusively for the plugin being installed/uninstalled. + +## Script Interface + +### Javascript + +If you are writing hooks in Javascript you should use the following module definition: +```javascript +module.exports = function(context) { + ... +} +``` + +You can make your scipts async using Q: +```javascript +module.exports = function(context) { + var Q = context.requireCordovaModule('q'); + var deferral = new Q.defer(); + + setTimeout(function(){ + console.log('hook.js>> end'); + deferral.resolve(); + }, 1000); + + return deferral.promise; +} +``` + +`context` object contains hook type, executed script full path, hook options, command-line arguments passed to Cordova and top-level "cordova" object: +```json +{ + "hook": "before_plugin_install", + "scriptLocation": "c:\\script\\full\\path\\appBeforePluginInstall.js", + "cmdLine": "The\\exact\\command\\cordova\\run\\with arguments", + "opts": { + "projectRoot":"C:\\path\\to\\the\\project", + "cordova": { + "platforms": ["wp8"], + "plugins": ["com.plugin.withhooks"], + "version": "0.21.7-dev" + }, + "plugin": { + "id": "com.plugin.withhooks", + "pluginInfo": { + ... + }, + "platform": "wp8", + "dir": "C:\\path\\to\\the\\project\\plugins\\com.plugin.withhooks" + } + }, + "cordova": {...} +} + +``` +`context.opts.plugin` object will only be passed to plugin hooks scripts. + +You can also require additional Cordova modules in your script using `context.requireCordovaModule` in the following way: +```javascript +var Q = context.requireCordovaModule('q'); +``` + +__Note__: new module loader script interface is used for the `.js` files defined via `config.xml` or `plugin.xml` only. +For compatibility reasons hook files specified via `/hooks` folders are run via Node child_process spawn, see 'Non-javascript' section below. + +### Non-javascript + +Non-javascript scripts are run via Node child_process spawn from the project's root directory and have the root directory passes as the first argument. All other options are passed to the script using environment variables: + +* CORDOVA_VERSION - The version of the Cordova-CLI. +* CORDOVA_PLATFORMS - Comma separated list of platforms that the command applies to (e.g.: android, ios). +* CORDOVA_PLUGINS - Comma separated list of plugin IDs that the command applies to (e.g.: org.apache.cordova.file, org.apache.cordova.file-transfer) +* CORDOVA_HOOK - Path to the hook that is being executed. +* CORDOVA_CMDLINE - The exact command-line arguments passed to cordova (e.g.: cordova run ios --emulate) + +If a script returns a non-zero exit code, then the parent cordova command will be aborted. + +## Writing hooks + +We highly recommend writting your hooks using Node.js so that they are +cross-platform. Some good examples are shown here: + +[http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/](http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/) + +Also, note that even if you are working on Windows, and in case your hook scripts aren't bat files (which is recommended, if you want your scripts to work in non-Windows operating systems) Cordova CLI will expect a shebang line as the first line for it to know the interpreter it needs to use to launch the script. The shebang line should match the following example: + + #!/usr/bin/env [name_of_interpreter_executable] diff --git a/TDA-Enrichment/.gitignore b/platforms/ios/.gitignore old mode 100755 new mode 100644 similarity index 67% rename from TDA-Enrichment/.gitignore rename to platforms/ios/.gitignore index d30c0b0..cc76483 --- a/TDA-Enrichment/.gitignore +++ b/platforms/ios/.gitignore @@ -2,5 +2,4 @@ *.perspectivev3 *.pbxuser .DS_Store -build -www/phonegap.js +build/ diff --git a/CordovaLib/Classes/CDV.h b/platforms/ios/CordovaLib/Classes/CDV.h old mode 100755 new mode 100644 similarity index 76% rename from CordovaLib/Classes/CDV.h rename to platforms/ios/CordovaLib/Classes/CDV.h index 15d9316..6cf592a --- a/CordovaLib/Classes/CDV.h +++ b/platforms/ios/CordovaLib/Classes/CDV.h @@ -25,26 +25,10 @@ #import "CDVURLProtocol.h" #import "CDVInvokedUrlCommand.h" -#import "CDVAccelerometer.h" -#import "CDVBattery.h" -#import "CDVCamera.h" -#import "CDVCapture.h" -#import "CDVConnection.h" -#import "CDVContact.h" -#import "CDVContacts.h" #import "CDVDebug.h" -#import "CDVDevice.h" -#import "CDVFile.h" -#import "CDVFileTransfer.h" -#import "CDVLocation.h" -#import "CDVNotification.h" #import "CDVPluginResult.h" -#import "CDVReachability.h" -#import "CDVSound.h" -#import "CDVSplashScreen.h" #import "CDVWhitelist.h" #import "CDVLocalStorage.h" -#import "CDVInAppBrowser.h" #import "CDVScreenOrientationDelegate.h" #import "CDVTimer.h" diff --git a/CordovaLib/Classes/CDVAvailability.h b/platforms/ios/CordovaLib/Classes/CDVAvailability.h old mode 100755 new mode 100644 similarity index 81% rename from CordovaLib/Classes/CDVAvailability.h rename to platforms/ios/CordovaLib/Classes/CDVAvailability.h index b288522..1d37be0 --- a/CordovaLib/Classes/CDVAvailability.h +++ b/platforms/ios/CordovaLib/Classes/CDVAvailability.h @@ -17,6 +17,8 @@ under the License. */ +#import "CDVAvailabilityDeprecated.h" + #define __CORDOVA_IOS__ #define __CORDOVA_0_9_6 906 @@ -41,6 +43,17 @@ #define __CORDOVA_2_5_0 20500 #define __CORDOVA_2_6_0 20600 #define __CORDOVA_2_7_0 20700 +#define __CORDOVA_2_8_0 20800 +#define __CORDOVA_2_9_0 20900 +#define __CORDOVA_3_0_0 30000 +#define __CORDOVA_3_1_0 30100 +#define __CORDOVA_3_2_0 30200 +#define __CORDOVA_3_3_0 30300 +#define __CORDOVA_3_4_0 30400 +#define __CORDOVA_3_4_1 30401 +#define __CORDOVA_3_5_0 30500 +#define __CORDOVA_3_6_0 30600 +#define __CORDOVA_3_7_0 30700 #define __CORDOVA_NA 99999 /* not available */ /* @@ -51,7 +64,7 @@ #endif */ #ifndef CORDOVA_VERSION_MIN_REQUIRED - #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_7_0 + #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_3_7_0 #endif /* @@ -63,22 +76,12 @@ */ #define IsAtLeastiOSVersion(X) ([[[UIDevice currentDevice] systemVersion] compare:X options:NSNumericSearch] != NSOrderedAscending) -#define CDV_IsIPad() ([[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)] && ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)) - -#define CDV_IsIPhone5() ([[UIScreen mainScreen] bounds].size.height == 568 && [[UIScreen mainScreen] bounds].size.width == 320) - /* Return the string version of the decimal version */ #define CDV_VERSION [NSString stringWithFormat:@"%d.%d.%d", \ (CORDOVA_VERSION_MIN_REQUIRED / 10000), \ (CORDOVA_VERSION_MIN_REQUIRED % 10000) / 100, \ (CORDOVA_VERSION_MIN_REQUIRED % 10000) % 100] -#ifdef __clang__ - #define CDV_DEPRECATED(version, msg) __attribute__((deprecated("Deprecated in Cordova " #version ". " msg))) -#else - #define CDV_DEPRECATED(version, msg) __attribute__((deprecated())) -#endif - // Enable this to log all exec() calls. #define CDV_ENABLE_EXEC_LOGGING 0 #if CDV_ENABLE_EXEC_LOGGING diff --git a/platforms/ios/CordovaLib/Classes/CDVAvailabilityDeprecated.h b/platforms/ios/CordovaLib/Classes/CDVAvailabilityDeprecated.h new file mode 100644 index 0000000..216b4c1 --- /dev/null +++ b/platforms/ios/CordovaLib/Classes/CDVAvailabilityDeprecated.h @@ -0,0 +1,38 @@ +/* + 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 + +#ifdef __clang__ +#define CDV_DEPRECATED(version, msg) __attribute__((deprecated("Deprecated in Cordova " #version ". " msg))) +#else +#define CDV_DEPRECATED(version, msg) __attribute__((deprecated())) +#endif + +static inline BOOL CDV_IsIPad(void) CDV_DEPRECATED(3.7.0, "This will be removed in 4.0.0"); +static inline BOOL CDV_IsIPhone5(void) CDV_DEPRECATED(3.7.0, "This will be removed in 4.0.0"); + +static inline BOOL CDV_IsIPad(void) { + return [[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)] && [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad; +} + +static inline BOOL CDV_IsIPhone5(void) { + return ([[UIScreen mainScreen] bounds].size.width == 568 && [[UIScreen mainScreen] bounds].size.height == 320) || ([[UIScreen mainScreen] bounds].size.height == 568 && [[UIScreen mainScreen] bounds].size.width == 320); +} \ No newline at end of file diff --git a/CordovaLib/Classes/CDVCommandDelegate.h b/platforms/ios/CordovaLib/Classes/CDVCommandDelegate.h old mode 100755 new mode 100644 similarity index 89% rename from CordovaLib/Classes/CDVCommandDelegate.h rename to platforms/ios/CordovaLib/Classes/CDVCommandDelegate.h index 0401136..04df6bc --- a/CordovaLib/Classes/CDVCommandDelegate.h +++ b/platforms/ios/CordovaLib/Classes/CDVCommandDelegate.h @@ -31,10 +31,6 @@ - (NSString*)pathForResource:(NSString*)resourcepath; - (id)getCommandInstance:(NSString*)pluginName; -// Plugins should not be using this interface to call other plugins since it -// will result in bogus callbacks being made. -- (BOOL)execute:(CDVInvokedUrlCommand*)command CDV_DEPRECATED(2.2, "Use direct method calls instead."); - // Sends a plugin result to the JS. This is thread-safe. - (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callbackId; // Evaluates the given JS. This is thread-safe. diff --git a/CordovaLib/Classes/CDVCommandDelegateImpl.h b/platforms/ios/CordovaLib/Classes/CDVCommandDelegateImpl.h old mode 100755 new mode 100644 similarity index 91% rename from CordovaLib/Classes/CDVCommandDelegateImpl.h rename to platforms/ios/CordovaLib/Classes/CDVCommandDelegateImpl.h index 6735136..0531134 --- a/CordovaLib/Classes/CDVCommandDelegateImpl.h +++ b/platforms/ios/CordovaLib/Classes/CDVCommandDelegateImpl.h @@ -26,8 +26,11 @@ @interface CDVCommandDelegateImpl : NSObject { @private __weak CDVViewController* _viewController; + NSRegularExpression* _callbackIdPattern; @protected __weak CDVCommandQueue* _commandQueue; + BOOL _delayResponses; } - (id)initWithViewController:(CDVViewController*)viewController; +- (void)flushCommandQueueWithDelayedJs; @end diff --git a/CordovaLib/Classes/CDVCommandDelegateImpl.m b/platforms/ios/CordovaLib/Classes/CDVCommandDelegateImpl.m old mode 100755 new mode 100644 similarity index 68% rename from CordovaLib/Classes/CDVCommandDelegateImpl.m rename to platforms/ios/CordovaLib/Classes/CDVCommandDelegateImpl.m index fa0e5e0..fc3346d --- a/CordovaLib/Classes/CDVCommandDelegateImpl.m +++ b/platforms/ios/CordovaLib/Classes/CDVCommandDelegateImpl.m @@ -31,6 +31,14 @@ - (id)initWithViewController:(CDVViewController*)viewController if (self != nil) { _viewController = viewController; _commandQueue = _viewController.commandQueue; + + NSError* err = nil; + _callbackIdPattern = [NSRegularExpression regularExpressionWithPattern:@"[^A-Za-z0-9._-]" options:0 error:&err]; + if (err != nil) { + // Couldn't initialize Regex + NSLog(@"Error: Couldn't initialize regex"); + _callbackIdPattern = nil; + } } return self; } @@ -53,6 +61,13 @@ - (NSString*)pathForResource:(NSString*)resourcepath return [mainBundle pathForResource:filename ofType:@"" inDirectory:directoryStr]; } +- (void)flushCommandQueueWithDelayedJs +{ + _delayResponses = YES; + [_commandQueue executePending]; + _delayResponses = NO; +} + - (void)evalJsHelper2:(NSString*)js { CDV_EXEC_LOG(@"Exec: evalling: %@", [js substringToIndex:MIN([js length], 160)]); @@ -61,25 +76,46 @@ - (void)evalJsHelper2:(NSString*)js CDV_EXEC_LOG(@"Exec: Retrieved new exec messages by chaining."); } - [_commandQueue enqueCommandBatch:commandsJSON]; + [_commandQueue enqueueCommandBatch:commandsJSON]; + [_commandQueue executePending]; } - (void)evalJsHelper:(NSString*)js { // Cycle the run-loop before executing the JS. - // This works around a bug where sometimes alerts() within callbacks can cause - // dead-lock. - // If the commandQueue is currently executing, then we know that it is safe to - // execute the callback immediately. - // Using (dispatch_get_main_queue()) does *not* fix deadlocks for some reaon, + // For _delayResponses - + // This ensures that we don't eval JS during the middle of an existing JS + // function (possible since UIWebViewDelegate callbacks can be synchronous). + // For !isMainThread - + // It's a hard error to eval on the non-UI thread. + // For !_commandQueue.currentlyExecuting - + // This works around a bug where sometimes alerts() within callbacks can cause + // dead-lock. + // If the commandQueue is currently executing, then we know that it is safe to + // execute the callback immediately. + // Using (dispatch_get_main_queue()) does *not* fix deadlocks for some reason, // but performSelectorOnMainThread: does. - if (![NSThread isMainThread] || !_commandQueue.currentlyExecuting) { + if (_delayResponses || ![NSThread isMainThread] || !_commandQueue.currentlyExecuting) { [self performSelectorOnMainThread:@selector(evalJsHelper2:) withObject:js waitUntilDone:NO]; } else { [self evalJsHelper2:js]; } } +- (BOOL)isValidCallbackId:(NSString*)callbackId +{ + + if (callbackId == nil || _callbackIdPattern == nil) { + return NO; + } + + // Disallow if too long or if any invalid characters were found. + if (([callbackId length] > 100) || [_callbackIdPattern firstMatchInString:callbackId options:0 range:NSMakeRange(0, [callbackId length])]) { + return NO; + } + return YES; +} + - (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callbackId { CDV_EXEC_LOG(@"Exec(%@): Sending result. Status=%@", callbackId, result.status); @@ -87,6 +123,11 @@ - (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callback if ([@"INVALID" isEqualToString : callbackId]) { return; } + // This occurs when the callback id is malformed. + if (![self isValidCallbackId:callbackId]) { + NSLog(@"Invalid callback id received by sendPluginResult"); + return; + } int status = [result.status intValue]; BOOL keepCallback = [result.keepCallback boolValue]; NSString* argumentsAsJSON = [result argumentsAsJSON]; @@ -111,11 +152,6 @@ - (void)evalJs:(NSString*)js scheduledOnRunLoop:(BOOL)scheduledOnRunLoop } } -- (BOOL)execute:(CDVInvokedUrlCommand*)command -{ - return [_commandQueue execute:command]; -} - - (id)getCommandInstance:(NSString*)pluginName { return [_viewController getCommandInstance:pluginName]; @@ -134,7 +170,7 @@ - (NSString*)userAgent - (BOOL)URLIsWhitelisted:(NSURL*)url { return ![_viewController.whitelist schemeIsAllowed:[url scheme]] || - [_viewController.whitelist URLIsAllowed:url]; + [_viewController.whitelist URLIsAllowed:url logFailure:NO]; } - (NSDictionary*)settings diff --git a/CordovaLib/Classes/CDVCommandQueue.h b/platforms/ios/CordovaLib/Classes/CDVCommandQueue.h old mode 100755 new mode 100644 similarity index 91% rename from CordovaLib/Classes/CDVCommandQueue.h rename to platforms/ios/CordovaLib/Classes/CDVCommandQueue.h index 27c47b5..3329078 --- a/CordovaLib/Classes/CDVCommandQueue.h +++ b/platforms/ios/CordovaLib/Classes/CDVCommandQueue.h @@ -30,9 +30,9 @@ - (void)dispose; - (void)resetRequestId; -- (void)enqueCommandBatch:(NSString*)batchJSON; +- (void)enqueueCommandBatch:(NSString*)batchJSON; -- (void)maybeFetchCommandsFromJs:(NSNumber*)requestId; +- (void)processXhrExecBridgePoke:(NSNumber*)requestId; - (void)fetchCommandsFromJs; - (void)executePending; - (BOOL)execute:(CDVInvokedUrlCommand*)command; diff --git a/platforms/ios/CordovaLib/Classes/CDVCommandQueue.m b/platforms/ios/CordovaLib/Classes/CDVCommandQueue.m new file mode 100644 index 0000000..1eddfe3 --- /dev/null +++ b/platforms/ios/CordovaLib/Classes/CDVCommandQueue.m @@ -0,0 +1,210 @@ +/* + 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. + */ + +#include +#import "CDV.h" +#import "CDVCommandQueue.h" +#import "CDVViewController.h" +#import "CDVCommandDelegateImpl.h" + +// Parse JS on the main thread if it's shorter than this. +static const NSInteger JSON_SIZE_FOR_MAIN_THREAD = 4 * 1024; // Chosen arbitrarily. +// Execute multiple commands in one go until this many seconds have passed. +static const double MAX_EXECUTION_TIME = .008; // Half of a 60fps frame. + +@interface CDVCommandQueue () { + NSInteger _lastCommandQueueFlushRequestId; + __weak CDVViewController* _viewController; + NSMutableArray* _queue; + NSTimeInterval _startExecutionTime; +} +@end + +@implementation CDVCommandQueue + +- (BOOL)currentlyExecuting +{ + return _startExecutionTime > 0; +} + +- (id)initWithViewController:(CDVViewController*)viewController +{ + self = [super init]; + if (self != nil) { + _viewController = viewController; + _queue = [[NSMutableArray alloc] init]; + } + return self; +} + +- (void)dispose +{ + // TODO(agrieve): Make this a zeroing weak ref once we drop support for 4.3. + _viewController = nil; +} + +- (void)resetRequestId +{ + _lastCommandQueueFlushRequestId = 0; +} + +- (void)enqueueCommandBatch:(NSString*)batchJSON +{ + if ([batchJSON length] > 0) { + NSMutableArray* commandBatchHolder = [[NSMutableArray alloc] init]; + [_queue addObject:commandBatchHolder]; + if ([batchJSON length] < JSON_SIZE_FOR_MAIN_THREAD) { + [commandBatchHolder addObject:[batchJSON JSONObject]]; + } else { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^() { + NSMutableArray* result = [batchJSON JSONObject]; + @synchronized(commandBatchHolder) { + [commandBatchHolder addObject:result]; + } + [self performSelectorOnMainThread:@selector(executePending) withObject:nil waitUntilDone:NO]; + }); + } + } +} + +- (void)processXhrExecBridgePoke:(NSNumber*)requestId +{ + NSInteger rid = [requestId integerValue]; + + // An ID of 1 is a special case because that signifies the first request of + // the page. Since resetRequestId is called from webViewDidStartLoad, and the + // JS context at the time of webViewDidStartLoad is still that of the previous + // page, it's possible for requests from the previous page to come in after this + // point. We ignore these by enforcing that ID=1 be the first ID. + if ((_lastCommandQueueFlushRequestId == 0) && (rid != 1)) { + CDV_EXEC_LOG(@"Exec: Ignoring exec request from previous page."); + return; + } + + // Use the request ID to determine if we've already flushed for this request. + // This is required only because the NSURLProtocol enqueues the same request + // multiple times. + if (rid > _lastCommandQueueFlushRequestId) { + _lastCommandQueueFlushRequestId = [requestId integerValue]; + [self fetchCommandsFromJs]; + [self executePending]; + } +} + +- (void)fetchCommandsFromJs +{ + // Grab all the queued commands from the JS side. + NSString* queuedCommandsJSON = [_viewController.webView stringByEvaluatingJavaScriptFromString: + @"cordova.require('cordova/exec').nativeFetchMessages()"]; + + CDV_EXEC_LOG(@"Exec: Flushed JS->native queue (hadCommands=%d).", [queuedCommandsJSON length] > 0); + [self enqueueCommandBatch:queuedCommandsJSON]; +} + +- (void)executePending +{ + // Make us re-entrant-safe. + if (_startExecutionTime > 0) { + return; + } + @try { + _startExecutionTime = [NSDate timeIntervalSinceReferenceDate]; + + while ([_queue count] > 0) { + NSMutableArray* commandBatchHolder = _queue[0]; + NSMutableArray* commandBatch = nil; + @synchronized(commandBatchHolder) { + // If the next-up command is still being decoded, wait for it. + if ([commandBatchHolder count] == 0) { + break; + } + commandBatch = commandBatchHolder[0]; + } + + while ([commandBatch count] > 0) { + @autoreleasepool { + // Execute the commands one-at-a-time. + NSArray* jsonEntry = [commandBatch dequeue]; + if ([commandBatch count] == 0) { + [_queue removeObjectAtIndex:0]; + } + CDVInvokedUrlCommand* command = [CDVInvokedUrlCommand commandFromJson:jsonEntry]; + CDV_EXEC_LOG(@"Exec(%@): Calling %@.%@", command.callbackId, command.className, command.methodName); + + if (![self execute:command]) { +#ifdef DEBUG + NSString* commandJson = [jsonEntry JSONString]; + static NSUInteger maxLogLength = 1024; + NSString* commandString = ([commandJson length] > maxLogLength) ? + [NSString stringWithFormat:@"%@[...]", [commandJson substringToIndex:maxLogLength]] : + commandJson; + + DLog(@"FAILED pluginJSON = %@", commandString); +#endif + } + } + + // Yield if we're taking too long. + if (([_queue count] > 0) && ([NSDate timeIntervalSinceReferenceDate] - _startExecutionTime > MAX_EXECUTION_TIME)) { + [self performSelector:@selector(executePending) withObject:nil afterDelay:0]; + return; + } + } + } + } @finally + { + _startExecutionTime = 0; + } +} + +- (BOOL)execute:(CDVInvokedUrlCommand*)command +{ + if ((command.className == nil) || (command.methodName == nil)) { + NSLog(@"ERROR: Classname and/or methodName not found for command."); + return NO; + } + + // Fetch an instance of this class + 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 config.xml.", command.className); + return NO; + } + BOOL retVal = YES; + double started = [[NSDate date] timeIntervalSince1970] * 1000.0; + // Find the proper selector to call. + NSString* methodName = [NSString stringWithFormat:@"%@:", command.methodName]; + SEL normalSelector = NSSelectorFromString(methodName); + if ([obj respondsToSelector:normalSelector]) { + // [obj performSelector:normalSelector withObject:command]; + ((void (*)(id, SEL, id))objc_msgSend)(obj, normalSelector, command); + } else { + // There's no method to call, so throw an error. + NSLog(@"ERROR: Method '%@' not defined in Plugin '%@'", methodName, command.className); + retVal = NO; + } + double elapsed = [[NSDate date] timeIntervalSince1970] * 1000.0 - started; + if (elapsed > 10) { + NSLog(@"THREAD WARNING: ['%@'] took '%f' ms. Plugin should use a background thread.", command.className, elapsed); + } + return retVal; +} + +@end diff --git a/CordovaLib/Classes/CDVConfigParser.h b/platforms/ios/CordovaLib/Classes/CDVConfigParser.h old mode 100755 new mode 100644 similarity index 92% rename from CordovaLib/Classes/CDVConfigParser.h rename to platforms/ios/CordovaLib/Classes/CDVConfigParser.h index 7392580..2e06c88 --- a/CordovaLib/Classes/CDVConfigParser.h +++ b/platforms/ios/CordovaLib/Classes/CDVConfigParser.h @@ -17,7 +17,10 @@ under the License. */ -@interface CDVConfigParser : NSObject {} +@interface CDVConfigParser : NSObject +{ + NSString* featureName; +} @property (nonatomic, readonly, strong) NSMutableDictionary* pluginsDict; @property (nonatomic, readonly, strong) NSMutableDictionary* settings; diff --git a/CordovaLib/Classes/CDVConfigParser.m b/platforms/ios/CordovaLib/Classes/CDVConfigParser.m old mode 100755 new mode 100644 similarity index 60% rename from CordovaLib/Classes/CDVConfigParser.m rename to platforms/ios/CordovaLib/Classes/CDVConfigParser.m index ffc8ede..4b73b60 --- a/CordovaLib/Classes/CDVConfigParser.m +++ b/platforms/ios/CordovaLib/Classes/CDVConfigParser.m @@ -40,7 +40,11 @@ - (id)init self.pluginsDict = [[NSMutableDictionary alloc] initWithCapacity:30]; self.settings = [[NSMutableDictionary alloc] initWithCapacity:30]; self.whitelistHosts = [[NSMutableArray alloc] initWithCapacity:30]; + [self.whitelistHosts addObject:@"file:///*"]; + [self.whitelistHosts addObject:@"content:///*"]; + [self.whitelistHosts addObject:@"data:///*"]; self.startupPluginNames = [[NSMutableArray alloc] initWithCapacity:8]; + featureName = nil; } return self; } @@ -48,12 +52,19 @@ - (id)init - (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributeDict { if ([elementName isEqualToString:@"preference"]) { - settings[attributeDict[@"name"]] = attributeDict[@"value"]; - } else if ([elementName isEqualToString:@"plugin"]) { - NSString* name = [attributeDict[@"name"] lowercaseString]; - pluginsDict[name] = attributeDict[@"value"]; - if ([@"true" isEqualToString : attributeDict[@"onload"]]) { - [self.startupPluginNames addObject:name]; + settings[[attributeDict[@"name"] lowercaseString]] = attributeDict[@"value"]; + } else if ([elementName isEqualToString:@"feature"]) { // store feature name to use with correct parameter set + featureName = [attributeDict[@"name"] lowercaseString]; + } else if ((featureName != nil) && [elementName isEqualToString:@"param"]) { + NSString* paramName = [attributeDict[@"name"] lowercaseString]; + id value = attributeDict[@"value"]; + if ([paramName isEqualToString:@"ios-package"]) { + pluginsDict[featureName] = value; + } + BOOL paramIsOnload = ([paramName isEqualToString:@"onload"] && [@"true" isEqualToString : value]); + BOOL attribIsOnload = [@"true" isEqualToString :[attributeDict[@"onload"] lowercaseString]]; + if (paramIsOnload || attribIsOnload) { + [self.startupPluginNames addObject:featureName]; } } else if ([elementName isEqualToString:@"access"]) { [whitelistHosts addObject:attributeDict[@"origin"]]; @@ -62,9 +73,16 @@ - (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName names } } +- (void)parser:(NSXMLParser*)parser didEndElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName +{ + if ([elementName isEqualToString:@"feature"]) { // no longer handling a feature so release + featureName = nil; + } +} + - (void)parser:(NSXMLParser*)parser parseErrorOccurred:(NSError*)parseError { - NSAssert(NO, @"config.xml parse error line %d col %d", [parser lineNumber], [parser columnNumber]); + NSAssert(NO, @"config.xml parse error line %ld col %ld", (long)[parser lineNumber], (long)[parser columnNumber]); } @end diff --git a/CordovaLib/Classes/CDVDebug.h b/platforms/ios/CordovaLib/Classes/CDVDebug.h old mode 100755 new mode 100644 similarity index 100% rename from CordovaLib/Classes/CDVDebug.h rename to platforms/ios/CordovaLib/Classes/CDVDebug.h diff --git a/CordovaLib/Classes/CDVInvokedUrlCommand.h b/platforms/ios/CordovaLib/Classes/CDVInvokedUrlCommand.h old mode 100755 new mode 100644 similarity index 87% rename from CordovaLib/Classes/CDVInvokedUrlCommand.h rename to platforms/ios/CordovaLib/Classes/CDVInvokedUrlCommand.h index 7be8884..993e0a2 --- a/CordovaLib/Classes/CDVInvokedUrlCommand.h +++ b/platforms/ios/CordovaLib/Classes/CDVInvokedUrlCommand.h @@ -40,11 +40,6 @@ - (id)initFromJson:(NSArray*)jsonEntry; -// The first NSDictionary found in the arguments will be returned in legacyDict. -// The arguments array with be prepended with the callbackId and have the first -// dict removed from it. -- (void)legacyArguments:(NSMutableArray**)legacyArguments andDict:(NSMutableDictionary**)legacyDict; - // Returns the argument at the given index. // If index >= the number of arguments, returns nil. // If the argument at the given index is NSNull, returns nil. diff --git a/CordovaLib/Classes/CDVInvokedUrlCommand.m b/platforms/ios/CordovaLib/Classes/CDVInvokedUrlCommand.m old mode 100755 new mode 100644 similarity index 82% rename from CordovaLib/Classes/CDVInvokedUrlCommand.m rename to platforms/ios/CordovaLib/Classes/CDVInvokedUrlCommand.m index 6c7a856..ff5f647 --- a/CordovaLib/Classes/CDVInvokedUrlCommand.m +++ b/platforms/ios/CordovaLib/Classes/CDVInvokedUrlCommand.m @@ -89,29 +89,6 @@ - (void)massageArguments } } -- (void)legacyArguments:(NSMutableArray**)legacyArguments andDict:(NSMutableDictionary**)legacyDict -{ - NSMutableArray* newArguments = [NSMutableArray arrayWithArray:_arguments]; - - for (NSUInteger i = 0; i < [newArguments count]; ++i) { - if ([[newArguments objectAtIndex:i] isKindOfClass:[NSDictionary class]]) { - if (legacyDict != NULL) { - *legacyDict = [newArguments objectAtIndex:i]; - } - [newArguments removeObjectAtIndex:i]; - break; - } - } - - // Legacy (two versions back) has no callbackId. - if (_callbackId != nil) { - [newArguments insertObject:_callbackId atIndex:0]; - } - if (legacyArguments != NULL) { - *legacyArguments = newArguments; - } -} - - (id)argumentAtIndex:(NSUInteger)index { return [self argumentAtIndex:index withDefault:nil]; diff --git a/CordovaLib/Classes/CDVJSON.h b/platforms/ios/CordovaLib/Classes/CDVJSON.h old mode 100755 new mode 100644 similarity index 98% rename from CordovaLib/Classes/CDVJSON.h rename to platforms/ios/CordovaLib/Classes/CDVJSON.h index eaa895e..8ad85da --- a/CordovaLib/Classes/CDVJSON.h +++ b/platforms/ios/CordovaLib/Classes/CDVJSON.h @@ -27,4 +27,5 @@ @interface NSString (CDVJSONSerializing) - (id)JSONObject; +- (id)JSONFragment; @end diff --git a/CordovaLib/Classes/CDVJSON.m b/platforms/ios/CordovaLib/Classes/CDVJSON.m old mode 100755 new mode 100644 similarity index 82% rename from CordovaLib/Classes/CDVJSON.m rename to platforms/ios/CordovaLib/Classes/CDVJSON.m index 78267e5..4698bfe --- a/CordovaLib/Classes/CDVJSON.m +++ b/platforms/ios/CordovaLib/Classes/CDVJSON.m @@ -64,7 +64,21 @@ - (id)JSONObject { NSError* error = nil; id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding] - options:kNilOptions + options:NSJSONReadingMutableContainers + error:&error]; + + if (error != nil) { + NSLog(@"NSString JSONObject error: %@", [error localizedDescription]); + } + + return object; +} + +- (id)JSONFragment +{ + NSError* error = nil; + id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding] + options:NSJSONReadingAllowFragments error:&error]; if (error != nil) { diff --git a/CordovaLib/Classes/CDVLocalStorage.h b/platforms/ios/CordovaLib/Classes/CDVLocalStorage.h old mode 100755 new mode 100644 similarity index 100% rename from CordovaLib/Classes/CDVLocalStorage.h rename to platforms/ios/CordovaLib/Classes/CDVLocalStorage.h diff --git a/CordovaLib/Classes/CDVLocalStorage.m b/platforms/ios/CordovaLib/Classes/CDVLocalStorage.m old mode 100755 new mode 100644 similarity index 97% rename from CordovaLib/Classes/CDVLocalStorage.m rename to platforms/ios/CordovaLib/Classes/CDVLocalStorage.m index 238d680..8aec403 --- a/CordovaLib/Classes/CDVLocalStorage.m +++ b/platforms/ios/CordovaLib/Classes/CDVLocalStorage.m @@ -35,7 +35,7 @@ - (void)pluginInitialize { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResignActive) name:UIApplicationWillResignActiveNotification object:nil]; - BOOL cloudBackup = [@"cloud" isEqualToString : self.commandDelegate.settings[@"BackupWebStorage"]]; + BOOL cloudBackup = [@"cloud" isEqualToString : self.commandDelegate.settings[[@"BackupWebStorage" lowercaseString]]]; self.backupInfo = [[self class] createBackupInfoWithCloudBackup:cloudBackup]; } @@ -340,6 +340,13 @@ + (void)__restoreLegacyDatabaseLocationsWithBackupType:(NSString*)backupType NSMutableArray* backupInfo = [NSMutableArray arrayWithCapacity:0]; if ([backupType isEqualToString:@"cloud"]) { +#ifdef DEBUG + NSLog(@"\n\nStarted backup to iCloud! Please be careful." + "\nYour application might be rejected by Apple if you store too much data." + "\nFor more information please read \"iOS Data Storage Guidelines\" at:" + "\nhttps://developer.apple.com/icloud/documentation/data-storage/" + "\nTo disable web storage backup to iCloud, set the BackupWebStorage preference to \"local\" in the Cordova config.xml file\n\n"); +#endif // We would like to restore old backups/caches databases to the new destination (nested in lib folder) [backupInfo addObjectsFromArray:[self createBackupInfoWithTargetDir:appLibraryFolder backupDir:[appDocumentsFolder stringByAppendingPathComponent:@"Backups"] targetDirNests:YES backupDirNests:NO rename:YES]]; [backupInfo addObjectsFromArray:[self createBackupInfoWithTargetDir:appLibraryFolder backupDir:[appLibraryFolder stringByAppendingPathComponent:@"Caches"] targetDirNests:YES backupDirNests:NO rename:NO]]; diff --git a/CordovaLib/Classes/CDVPlugin.h b/platforms/ios/CordovaLib/Classes/CDVPlugin.h old mode 100755 new mode 100644 similarity index 78% rename from CordovaLib/Classes/CDVPlugin.h rename to platforms/ios/CordovaLib/Classes/CDVPlugin.h index 33ba1c4..5e8b283 --- a/CordovaLib/Classes/CDVPlugin.h +++ b/platforms/ios/CordovaLib/Classes/CDVPlugin.h @@ -27,6 +27,8 @@ extern NSString* const CDVPageDidLoadNotification; extern NSString* const CDVPluginHandleOpenURLNotification; extern NSString* const CDVPluginResetNotification; extern NSString* const CDVLocalNotification; +extern NSString* const CDVRemoteNotification; +extern NSString* const CDVRemoteNotificationError; @interface CDVPlugin : NSObject {} @@ -56,9 +58,10 @@ extern NSString* const CDVLocalNotification; - (id)appDelegate; -// TODO(agrieve): Deprecate these in favour of using CDVCommandDelegate directly. -- (NSString*)writeJavascript:(NSString*)javascript; -- (NSString*)success:(CDVPluginResult*)pluginResult callbackId:(NSString*)callbackId; -- (NSString*)error:(CDVPluginResult*)pluginResult callbackId:(NSString*)callbackId; +- (NSString*)writeJavascript:(NSString*)javascript CDV_DEPRECATED(3.6, "Use the CDVCommandDelegate equivalent of evalJs:. This will be removed in 4.0.0"); + +- (NSString*)success:(CDVPluginResult*)pluginResult callbackId:(NSString*)callbackId CDV_DEPRECATED(3.6, "Use the CDVCommandDelegate equivalent of sendPluginResult:callbackId. This will be removed in 4.0.0"); + +- (NSString*)error:(CDVPluginResult*)pluginResult callbackId:(NSString*)callbackId CDV_DEPRECATED(3.6, "Use the CDVCommandDelegate equivalent of sendPluginResult:callbackId. This will be removed in 4.0.0"); @end diff --git a/CordovaLib/Classes/CDVPlugin.m b/platforms/ios/CordovaLib/Classes/CDVPlugin.m old mode 100755 new mode 100644 similarity index 97% rename from CordovaLib/Classes/CDVPlugin.m rename to platforms/ios/CordovaLib/Classes/CDVPlugin.m index 8c932a0..ea81ddd --- a/CordovaLib/Classes/CDVPlugin.m +++ b/platforms/ios/CordovaLib/Classes/CDVPlugin.m @@ -23,6 +23,8 @@ Licensed to the Apache Software Foundation (ASF) under one NSString* const CDVPluginHandleOpenURLNotification = @"CDVPluginHandleOpenURLNotification"; NSString* const CDVPluginResetNotification = @"CDVPluginResetNotification"; NSString* const CDVLocalNotification = @"CDVLocalNotification"; +NSString* const CDVRemoteNotification = @"CDVRemoteNotification"; +NSString* const CDVRemoteNotificationError = @"CDVRemoteNotificationError"; @interface CDVPlugin () diff --git a/CordovaLib/Classes/CDVPluginResult.h b/platforms/ios/CordovaLib/Classes/CDVPluginResult.h old mode 100755 new mode 100644 similarity index 84% rename from CordovaLib/Classes/CDVPluginResult.h rename to platforms/ios/CordovaLib/Classes/CDVPluginResult.h index 11b5377..e624d4d --- a/CordovaLib/Classes/CDVPluginResult.h +++ b/platforms/ios/CordovaLib/Classes/CDVPluginResult.h @@ -18,6 +18,7 @@ */ #import +#import "CDVAvailability.h" typedef enum { CDVCommandStatus_NO_RESULT = 0, @@ -61,8 +62,10 @@ typedef enum { - (NSString*)argumentsAsJSON; // These methods are used by the legacy plugin return result method -- (NSString*)toJSONString; -- (NSString*)toSuccessCallbackString:(NSString*)callbackId; -- (NSString*)toErrorCallbackString:(NSString*)callbackId; +- (NSString*)toJSONString CDV_DEPRECATED(3.6, "Only used by toSuccessCallbackString and toErrorCallbackString which are deprecated. This will be removed in 4.0.0"); + +- (NSString*)toSuccessCallbackString:(NSString*)callbackId CDV_DEPRECATED(3.6, "Use the CDVCommandDelegate method sendPluginResult:callbackId instead. This will be removed in 4.0.0"); + +- (NSString*)toErrorCallbackString:(NSString*)callbackId CDV_DEPRECATED(3.6, "Use the CDVCommandDelegate method sendPluginResult:callbackId instead. This will be removed in 4.0.0"); @end diff --git a/CordovaLib/Classes/CDVPluginResult.m b/platforms/ios/CordovaLib/Classes/CDVPluginResult.m old mode 100755 new mode 100644 similarity index 98% rename from CordovaLib/Classes/CDVPluginResult.m rename to platforms/ios/CordovaLib/Classes/CDVPluginResult.m index af7c528..2eb46cd --- a/CordovaLib/Classes/CDVPluginResult.m +++ b/platforms/ios/CordovaLib/Classes/CDVPluginResult.m @@ -96,7 +96,7 @@ - (CDVPluginResult*)initWithStatus:(CDVCommandStatus)statusOrdinal message:(id)t + (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal { - return [[self alloc] initWithStatus:statusOrdinal message:[org_apache_cordova_CommandStatusMsgs objectAtIndex:statusOrdinal]]; + return [[self alloc] initWithStatus:statusOrdinal message:nil]; } + (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsString:(NSString*)theMessage diff --git a/CordovaLib/Classes/CDVScreenOrientationDelegate.h b/platforms/ios/CordovaLib/Classes/CDVScreenOrientationDelegate.h old mode 100755 new mode 100644 similarity index 100% rename from CordovaLib/Classes/CDVScreenOrientationDelegate.h rename to platforms/ios/CordovaLib/Classes/CDVScreenOrientationDelegate.h diff --git a/CordovaLib/Classes/compatibility/1.5.0/CDVPlugin.h b/platforms/ios/CordovaLib/Classes/CDVShared.h old mode 100755 new mode 100644 similarity index 84% rename from CordovaLib/Classes/compatibility/1.5.0/CDVPlugin.h rename to platforms/ios/CordovaLib/Classes/CDVShared.h index 6e2c4c3..68acc5c --- a/CordovaLib/Classes/compatibility/1.5.0/CDVPlugin.h +++ b/platforms/ios/CordovaLib/Classes/CDVShared.h @@ -17,7 +17,6 @@ under the License. */ -// Bridge implementation file for using Cordova > 1.5 plugins in 1.5.0. -// - -#import +// This file was emptied out in 3.6.0 release (July 2014). +// It will be deleted in a future release. +#import diff --git a/CordovaLib/Classes/CDVTimer.h b/platforms/ios/CordovaLib/Classes/CDVTimer.h old mode 100755 new mode 100644 similarity index 100% rename from CordovaLib/Classes/CDVTimer.h rename to platforms/ios/CordovaLib/Classes/CDVTimer.h diff --git a/CordovaLib/Classes/CDVTimer.m b/platforms/ios/CordovaLib/Classes/CDVTimer.m old mode 100755 new mode 100644 similarity index 100% rename from CordovaLib/Classes/CDVTimer.m rename to platforms/ios/CordovaLib/Classes/CDVTimer.m diff --git a/CordovaLib/Classes/CDVURLProtocol.h b/platforms/ios/CordovaLib/Classes/CDVURLProtocol.h old mode 100755 new mode 100644 similarity index 100% rename from CordovaLib/Classes/CDVURLProtocol.h rename to platforms/ios/CordovaLib/Classes/CDVURLProtocol.h diff --git a/CordovaLib/Classes/CDVURLProtocol.m b/platforms/ios/CordovaLib/Classes/CDVURLProtocol.m old mode 100755 new mode 100644 similarity index 90% rename from CordovaLib/Classes/CDVURLProtocol.m rename to platforms/ios/CordovaLib/Classes/CDVURLProtocol.m index afc10de..fce5783 --- a/CordovaLib/Classes/CDVURLProtocol.m +++ b/platforms/ios/CordovaLib/Classes/CDVURLProtocol.m @@ -25,17 +25,14 @@ Licensed to the Apache Software Foundation (ASF) under one #import "CDVCommandQueue.h" #import "CDVWhitelist.h" #import "CDVViewController.h" -#import "CDVFile.h" - -@interface CDVHTTPURLResponse : NSHTTPURLResponse -@property (nonatomic) NSInteger statusCode; -@end static CDVWhitelist* gWhitelist = nil; // Contains a set of NSNumbers of addresses of controllers. It doesn't store // the actual pointer to avoid retaining. static NSMutableSet* gRegisteredControllers = nil; +NSString* const kCDVAssetsLibraryPrefixes = @"assets-library://"; + // 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. @@ -109,7 +106,7 @@ + (BOOL)canInitWithRequest:(NSURLRequest*)theRequest NSURL* theUrl = [theRequest URL]; CDVViewController* viewController = viewControllerForRequest(theRequest); - if ([[theUrl absoluteString] hasPrefix:kCDVAssetsLibraryPrefix]) { + if ([[theUrl absoluteString] hasPrefix:kCDVAssetsLibraryPrefixes]) { return YES; } else if (viewController != nil) { if ([[theUrl path] isEqualToString:@"/!gap_exec"]) { @@ -121,10 +118,11 @@ + (BOOL)canInitWithRequest:(NSURLRequest*)theRequest } BOOL hasCmds = [queuedCommandsJSON length] > 0; if (hasCmds) { - SEL sel = @selector(enqueCommandBatch:); + SEL sel = @selector(enqueueCommandBatch:); [viewController.commandQueue performSelectorOnMainThread:sel withObject:queuedCommandsJSON waitUntilDone:NO]; + [viewController.commandQueue performSelectorOnMainThread:@selector(executePending) withObject:nil waitUntilDone:NO]; } else { - SEL sel = @selector(maybeFetchCommandsFromJs:); + SEL sel = @selector(processXhrExecBridgePoke:); [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. @@ -158,14 +156,14 @@ - (void)startLoading if ([[url path] isEqualToString:@"/!gap_exec"]) { [self sendResponseWithResponseCode:200 data:nil mimeType:nil]; return; - } else if ([[url absoluteString] hasPrefix:kCDVAssetsLibraryPrefix]) { + } else if ([[url absoluteString] hasPrefix:kCDVAssetsLibraryPrefixes]) { ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) { if (asset) { // We have the asset! Get the data and send it along. ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation]; NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType); - Byte* buffer = (Byte*)malloc([assetRepresentation size]); - NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil]; + Byte* buffer = (Byte*)malloc((unsigned long)[assetRepresentation size]); + NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:(NSUInteger)[assetRepresentation size] error:nil]; NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES]; [self sendResponseWithResponseCode:200 data:data mimeType:MIMEType]; } else { @@ -202,13 +200,8 @@ - (void)sendResponseWithResponseCode:(NSInteger)statusCode data:(NSData*)data mi if (mimeType == nil) { mimeType = @"text/plain"; } - NSString* encodingName = [@"text/plain" isEqualToString : mimeType] ? @"UTF-8" : nil; - CDVHTTPURLResponse* response = - [[CDVHTTPURLResponse alloc] initWithURL:[[self request] URL] - MIMEType:mimeType - expectedContentLength:[data length] - textEncodingName:encodingName]; - response.statusCode = statusCode; + + NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc] initWithURL:[[self request] URL] statusCode:statusCode HTTPVersion:@"HTTP/1.1" headerFields:@{@"Content-Type" : mimeType}]; [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; if (data != nil) { @@ -218,13 +211,3 @@ - (void)sendResponseWithResponseCode:(NSInteger)statusCode data:(NSData*)data mi } @end - -@implementation CDVHTTPURLResponse -@synthesize statusCode; - -- (NSDictionary*)allHeaderFields -{ - return nil; -} - -@end diff --git a/CordovaLib/Classes/CDVUserAgentUtil.h b/platforms/ios/CordovaLib/Classes/CDVUserAgentUtil.h old mode 100755 new mode 100644 similarity index 100% rename from CordovaLib/Classes/CDVUserAgentUtil.h rename to platforms/ios/CordovaLib/Classes/CDVUserAgentUtil.h diff --git a/CordovaLib/Classes/CDVUserAgentUtil.m b/platforms/ios/CordovaLib/Classes/CDVUserAgentUtil.m old mode 100755 new mode 100644 similarity index 90% rename from CordovaLib/Classes/CDVUserAgentUtil.m rename to platforms/ios/CordovaLib/Classes/CDVUserAgentUtil.m index 9923d47..c3402d0 --- a/CordovaLib/Classes/CDVUserAgentUtil.m +++ b/platforms/ios/CordovaLib/Classes/CDVUserAgentUtil.m @@ -43,7 +43,9 @@ + (NSString*)originalUserAgent NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; NSString* systemVersion = [[UIDevice currentDevice] systemVersion]; NSString* localeStr = [[NSLocale currentLocale] localeIdentifier]; - NSString* systemAndLocale = [NSString stringWithFormat:@"%@ %@", systemVersion, localeStr]; + // Record the model since simulator can change it without re-install (CB-5420). + NSString* model = [UIDevice currentDevice].model; + NSString* systemAndLocale = [NSString stringWithFormat:@"%@ %@ %@", model, systemVersion, localeStr]; NSString* cordovaUserAgentVersion = [userDefaults stringForKey:kCdvUserAgentVersionKey]; gOriginalUserAgent = [userDefaults stringForKey:kCdvUserAgentKey]; @@ -89,14 +91,14 @@ + (void)releaseLock:(NSInteger*)lockToken if (*lockToken == 0) { return; } - NSAssert(gCurrentLockToken == *lockToken, @"Got token %d, expected %d", *lockToken, gCurrentLockToken); + NSAssert(gCurrentLockToken == *lockToken, @"Got token %ld, expected %ld", (long)*lockToken, (long)gCurrentLockToken); VerboseLog(@"Released lock %d", *lockToken); if ([gPendingSetUserAgentBlocks count] > 0) { void (^block)() = [gPendingSetUserAgentBlocks objectAtIndex:0]; [gPendingSetUserAgentBlocks removeObjectAtIndex:0]; gCurrentLockToken = ++gNextLockToken; - NSLog(@"Gave lock %d", gCurrentLockToken); + NSLog(@"Gave lock %ld", (long)gCurrentLockToken); block(gCurrentLockToken); } else { gCurrentLockToken = 0; @@ -106,7 +108,7 @@ + (void)releaseLock:(NSInteger*)lockToken + (void)setUserAgent:(NSString*)value lockToken:(NSInteger)lockToken { - NSAssert(gCurrentLockToken == lockToken, @"Got token %d, expected %d", lockToken, gCurrentLockToken); + NSAssert(gCurrentLockToken == lockToken, @"Got token %ld, expected %ld", (long)lockToken, (long)gCurrentLockToken); VerboseLog(@"User-Agent set to: %@", value); // Setting the UserAgent must occur before a UIWebView is instantiated. diff --git a/CordovaLib/Classes/CDVViewController.h b/platforms/ios/CordovaLib/Classes/CDVViewController.h old mode 100755 new mode 100644 similarity index 88% rename from CordovaLib/Classes/CDVViewController.h rename to platforms/ios/CordovaLib/Classes/CDVViewController.h index 2338baf..51863a5 --- a/CordovaLib/Classes/CDVViewController.h +++ b/platforms/ios/CordovaLib/Classes/CDVViewController.h @@ -43,14 +43,24 @@ @property (nonatomic, readonly, strong) NSXMLParser* configParser; @property (nonatomic, readonly, strong) CDVWhitelist* whitelist; // readonly for public @property (nonatomic, readonly, assign) BOOL loadFromString; -@property (nonatomic, readwrite, assign) BOOL useSplashScreen CDV_DEPRECATED(2.5, "Add/Remove the SplashScreen plugin instead of setting this property."); @property (nonatomic, readwrite, copy) NSString* wwwFolderName; @property (nonatomic, readwrite, copy) NSString* startPage; @property (nonatomic, readonly, strong) CDVCommandQueue* commandQueue; @property (nonatomic, readonly, strong) id commandDelegate; + +/** + The complete user agent that Cordova will use when sending web requests. + */ @property (nonatomic, readonly) NSString* userAgent; +/** + The base user agent data that Cordova will use to build its user agent. If this + property isn't set, Cordova will use the standard web view user agent as its + base. + */ +@property (nonatomic, readwrite, copy) NSString* baseUserAgent; + + (NSDictionary*)getBundlePlist:(NSString*)plistName; + (NSString*)applicationDocumentsDirectory; @@ -69,5 +79,6 @@ - (void)registerPlugin:(CDVPlugin*)plugin withPluginName:(NSString*)pluginName; - (BOOL)URLisAllowed:(NSURL*)url; +- (void)processOpenUrl:(NSURL*)url; @end diff --git a/CordovaLib/Classes/CDVViewController.m b/platforms/ios/CordovaLib/Classes/CDVViewController.m old mode 100755 new mode 100644 similarity index 69% rename from CordovaLib/Classes/CDVViewController.m rename to platforms/ios/CordovaLib/Classes/CDVViewController.m index 94f4552..eb056ce --- a/CordovaLib/Classes/CDVViewController.m +++ b/platforms/ios/CordovaLib/Classes/CDVViewController.m @@ -23,6 +23,7 @@ Licensed to the Apache Software Foundation (ASF) under one #import "CDVConfigParser.h" #import "CDVUserAgentUtil.h" #import "CDVWebViewDelegate.h" +#import #define degreesToRadian(x) (M_PI * (x) / 180.0) @@ -51,8 +52,7 @@ @implementation CDVViewController @synthesize webView, supportedOrientations; @synthesize pluginObjects, pluginsMap, whitelist, startupPluginNames; @synthesize configParser, settings, loadFromString; -@synthesize useSplashScreen; -@synthesize wwwFolderName, startPage, initialized, openURL; +@synthesize wwwFolderName, startPage, initialized, openURL, baseUserAgent; @synthesize commandDelegate = _commandDelegate; @synthesize commandQueue = _commandQueue; @@ -72,19 +72,20 @@ - (void)__init name:UIApplicationWillEnterForegroundNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleOpenURL:) name:CDVPluginHandleOpenURLNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onPageDidLoad:) + name:CDVPageDidLoadNotification object:nil]; // read from UISupportedInterfaceOrientations (or UISupportedInterfaceOrientations~iPad, if its iPad) from -Info.plist self.supportedOrientations = [self parseInterfaceOrientations: [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UISupportedInterfaceOrientations"]]; + [self printVersion]; [self printMultitaskingInfo]; - [self printDeprecationNotice]; + [self printPlatformVersionWarning]; self.initialized = YES; // load config.xml settings [self loadSettings]; - useSplashScreen = YES; } } @@ -95,6 +96,13 @@ - (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil return self; } +- (id)initWithCoder:(NSCoder*)aDecoder +{ + self = [super initWithCoder:aDecoder]; + [self __init]; + return self; +} + - (id)init { self = [super init]; @@ -105,49 +113,22 @@ - (id)init - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; - - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; - [nc addObserver:self - selector:@selector(keyboardWillShowOrHide:) - name:UIKeyboardWillShowNotification - object:nil]; - [nc addObserver:self - selector:@selector(keyboardWillShowOrHide:) - name:UIKeyboardWillHideNotification - object:nil]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; - - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; - [nc removeObserver:self name:UIKeyboardWillShowNotification object:nil]; - [nc removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } -- (void)keyboardWillShowOrHide:(NSNotification*)notif +- (void)printVersion { - if (![@"true" isEqualToString : self.settings[@"KeyboardShrinksView"]]) { - return; - } - BOOL showEvent = [notif.name isEqualToString:UIKeyboardWillShowNotification]; - - CGRect keyboardFrame = [notif.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; - keyboardFrame = [self.view convertRect:keyboardFrame fromView:nil]; - - CGRect newFrame = self.view.bounds; - if (showEvent) { - newFrame.size.height -= keyboardFrame.size.height; - } - self.webView.frame = newFrame; - self.webView.scrollView.contentInset = UIEdgeInsetsMake(0, 0, -keyboardFrame.size.height, 0); + NSLog(@"Apache Cordova native platform version %@ is starting.", CDV_VERSION); } -- (void)printDeprecationNotice +- (void)printPlatformVersionWarning { - 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 %@.", + if (!IsAtLeastiOSVersion(@"6.0")) { + NSLog(@"CRITICAL: For Cordova 3.5.0 and above, you will need to upgrade to at least iOS 6.0 or greater. Your current version of iOS is %@.", [[UIDevice currentDevice] systemVersion] ); } @@ -218,39 +199,73 @@ - (void)loadSettings self.pluginObjects = [[NSMutableDictionary alloc] initWithCapacity:20]; } -// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. -- (void)viewDidLoad +- (NSURL*)appUrl { - [super viewDidLoad]; - NSURL* appURL = nil; - NSString* loadErr = 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 { - NSString* startFilePath = [self.commandDelegate pathForResource:self.startPage]; + // CB-3005 strip parameters from start page to check if page exists in resources + NSURL* startURL = [NSURL URLWithString:self.startPage]; + NSString* startFilePath = [self.commandDelegate pathForResource:[startURL path]]; + 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]; + // CB-3005 Add on the query params or fragment. + NSString* startPageNoParentDirs = self.startPage; + NSRange r = [startPageNoParentDirs rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"?#"] options:0]; + if (r.location != NSNotFound) { + NSString* queryAndOrFragment = [self.startPage substringFromIndex:r.location]; + appURL = [NSURL URLWithString:queryAndOrFragment relativeToURL:appURL]; + } + } + } + + return appURL; +} + +- (NSURL*)errorUrl +{ + NSURL* errorURL = nil; + + id setting = [self settingForKey:@"ErrorUrl"]; + + if (setting) { + NSString* errorUrlString = (NSString*)setting; + if ([errorUrlString rangeOfString:@"://"].location != NSNotFound) { + errorURL = [NSURL URLWithString:errorUrlString]; + } else { + NSURL* url = [NSURL URLWithString:(NSString*)setting]; + NSString* errorFilePath = [self.commandDelegate pathForResource:[url path]]; + if (errorFilePath) { + errorURL = [NSURL fileURLWithPath:errorFilePath]; + } } } + return errorURL; +} + +// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. +- (void)viewDidLoad +{ + [super viewDidLoad]; + // // Fix the iOS 5.1 SECURITY_ERR bug (CB-347), this must be before the webView is instantiated //// NSString* backupWebStorageType = @"cloud"; // default value - id backupWebStorage = self.settings[@"BackupWebStorage"]; + id backupWebStorage = [self settingForKey:@"BackupWebStorage"]; if ([backupWebStorage isKindOfClass:[NSString class]]) { backupWebStorageType = backupWebStorage; } - self.settings[@"BackupWebStorage"] = backupWebStorageType; + [self setSetting:backupWebStorageType forKey:@"BackupWebStorage"]; if (IsAtLeastiOSVersion(@"5.1")) { [CDVLocalStorage __fixupDatabaseLocationsWithBackupType:backupWebStorageType]; @@ -258,44 +273,28 @@ - (void)viewDidLoad // // Instantiate the WebView /////////////// - [self createGapView]; + if (!self.webView) { + [self createGapView]; + } + + // Configure WebView + _webViewDelegate = [[CDVWebViewDelegate alloc] initWithDelegate:self]; + self.webView.delegate = _webViewDelegate; + + // register this viewcontroller with the NSURLProtocol, only after the User-Agent is set + [CDVURLProtocol registerViewController:self]; // ///////////////// - NSNumber* enableLocation = [self.settings objectForKey:@"EnableLocation"]; - NSString* enableViewportScale = [self.settings objectForKey:@"EnableViewportScale"]; - NSNumber* allowInlineMediaPlayback = [self.settings objectForKey:@"AllowInlineMediaPlayback"]; + NSString* enableViewportScale = [self settingForKey:@"EnableViewportScale"]; + NSNumber* allowInlineMediaPlayback = [self settingForKey:@"AllowInlineMediaPlayback"]; BOOL mediaPlaybackRequiresUserAction = YES; // default value - if ([self.settings objectForKey:@"MediaPlaybackRequiresUserAction"]) { - mediaPlaybackRequiresUserAction = [(NSNumber*)[settings objectForKey:@"MediaPlaybackRequiresUserAction"] boolValue]; - } - BOOL hideKeyboardFormAccessoryBar = NO; // default value - if ([self.settings objectForKey:@"HideKeyboardFormAccessoryBar"]) { - hideKeyboardFormAccessoryBar = [(NSNumber*)[settings objectForKey:@"HideKeyboardFormAccessoryBar"] boolValue]; + if ([self settingForKey:@"MediaPlaybackRequiresUserAction"]) { + mediaPlaybackRequiresUserAction = [(NSNumber*)[self settingForKey:@"MediaPlaybackRequiresUserAction"] boolValue]; } self.webView.scalesPageToFit = [enableViewportScale boolValue]; - /* - * Fire up the GPS Service right away as it takes a moment for data to come back. - */ - - if ([enableLocation boolValue]) { - NSLog(@"Deprecated: The 'EnableLocation' boolean property is deprecated in 2.5.0, and will be removed in 3.0.0. Use the 'onload' boolean attribute (of the CDVLocation plugin."); - [[self.commandDelegate getCommandInstance:@"Geolocation"] getLocation:[CDVInvokedUrlCommand new]]; - } - - if (hideKeyboardFormAccessoryBar) { - __weak CDVViewController* weakSelf = self; - [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification - object:nil - queue:[NSOperationQueue mainQueue] - usingBlock:^(NSNotification* notification) { - // we can't hide it here because the accessory bar hasn't been created yet, so we delay on the queue - [weakSelf performSelector:@selector(hideKeyboardFormAccessoryBar) withObject:nil afterDelay:0]; - }]; - } - /* * 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. */ @@ -317,9 +316,9 @@ - (void)viewDidLoad // By default, overscroll bouncing is allowed. // UIWebViewBounce has been renamed to DisallowOverscroll, but both are checked. BOOL bounceAllowed = YES; - NSNumber* disallowOverscroll = [self.settings objectForKey:@"DisallowOverscroll"]; + NSNumber* disallowOverscroll = [self settingForKey:@"DisallowOverscroll"]; if (disallowOverscroll == nil) { - NSNumber* bouncePreference = [self.settings objectForKey:@"UIWebViewBounce"]; + NSNumber* bouncePreference = [self settingForKey:@"UIWebViewBounce"]; bounceAllowed = (bouncePreference == nil || [bouncePreference boolValue]); } else { bounceAllowed = ![disallowOverscroll boolValue]; @@ -339,14 +338,19 @@ - (void)viewDidLoad } } + NSString* decelerationSetting = [self settingForKey:@"UIWebViewDecelerationSpeed"]; + if (![@"fast" isEqualToString:decelerationSetting]) { + [self.webView.scrollView setDecelerationRate:UIScrollViewDecelerationRateNormal]; + } + /* * iOS 6.0 UIWebView properties */ if (IsAtLeastiOSVersion(@"6.0")) { BOOL keyboardDisplayRequiresUserAction = YES; // KeyboardDisplayRequiresUserAction - defaults to YES - if ([self.settings objectForKey:@"KeyboardDisplayRequiresUserAction"] != nil) { - if ([self.settings objectForKey:@"KeyboardDisplayRequiresUserAction"]) { - keyboardDisplayRequiresUserAction = [(NSNumber*)[self.settings objectForKey:@"KeyboardDisplayRequiresUserAction"] boolValue]; + if ([self settingForKey:@"KeyboardDisplayRequiresUserAction"] != nil) { + if ([self settingForKey:@"KeyboardDisplayRequiresUserAction"]) { + keyboardDisplayRequiresUserAction = [(NSNumber*)[self settingForKey:@"KeyboardDisplayRequiresUserAction"] boolValue]; } } @@ -356,9 +360,9 @@ - (void)viewDidLoad } BOOL suppressesIncrementalRendering = NO; // SuppressesIncrementalRendering - defaults to NO - if ([self.settings objectForKey:@"SuppressesIncrementalRendering"] != nil) { - if ([self.settings objectForKey:@"SuppressesIncrementalRendering"]) { - suppressesIncrementalRendering = [(NSNumber*)[self.settings objectForKey:@"SuppressesIncrementalRendering"] boolValue]; + if ([self settingForKey:@"SuppressesIncrementalRendering"] != nil) { + if ([self settingForKey:@"SuppressesIncrementalRendering"]) { + suppressesIncrementalRendering = [(NSNumber*)[self settingForKey:@"SuppressesIncrementalRendering"] boolValue]; } } @@ -368,6 +372,82 @@ - (void)viewDidLoad } } + /* + * iOS 7.0 UIWebView properties + */ + if (IsAtLeastiOSVersion(@"7.0")) { + SEL ios7sel = nil; + id prefObj = nil; + + CGFloat gapBetweenPages = 0.0; // default + prefObj = [self settingForKey:@"GapBetweenPages"]; + if (prefObj != nil) { + gapBetweenPages = [prefObj floatValue]; + } + + // property check for compiling under iOS < 7 + ios7sel = NSSelectorFromString(@"setGapBetweenPages:"); + if ([self.webView respondsToSelector:ios7sel]) { + [self.webView setValue:[NSNumber numberWithFloat:gapBetweenPages] forKey:@"gapBetweenPages"]; + } + + CGFloat pageLength = 0.0; // default + prefObj = [self settingForKey:@"PageLength"]; + if (prefObj != nil) { + pageLength = [[self settingForKey:@"PageLength"] floatValue]; + } + + // property check for compiling under iOS < 7 + ios7sel = NSSelectorFromString(@"setPageLength:"); + if ([self.webView respondsToSelector:ios7sel]) { + [self.webView setValue:[NSNumber numberWithBool:pageLength] forKey:@"pageLength"]; + } + + NSInteger paginationBreakingMode = 0; // default - UIWebPaginationBreakingModePage + prefObj = [self settingForKey:@"PaginationBreakingMode"]; + if (prefObj != nil) { + NSArray* validValues = @[@"page", @"column"]; + NSString* prefValue = [validValues objectAtIndex:0]; + + if ([prefObj isKindOfClass:[NSString class]]) { + prefValue = prefObj; + } + + paginationBreakingMode = [validValues indexOfObject:[prefValue lowercaseString]]; + if (paginationBreakingMode == NSNotFound) { + paginationBreakingMode = 0; + } + } + + // property check for compiling under iOS < 7 + ios7sel = NSSelectorFromString(@"setPaginationBreakingMode:"); + if ([self.webView respondsToSelector:ios7sel]) { + [self.webView setValue:[NSNumber numberWithInteger:paginationBreakingMode] forKey:@"paginationBreakingMode"]; + } + + NSInteger paginationMode = 0; // default - UIWebPaginationModeUnpaginated + prefObj = [self settingForKey:@"PaginationMode"]; + if (prefObj != nil) { + NSArray* validValues = @[@"unpaginated", @"lefttoright", @"toptobottom", @"bottomtotop", @"righttoleft"]; + NSString* prefValue = [validValues objectAtIndex:0]; + + if ([prefObj isKindOfClass:[NSString class]]) { + prefValue = prefObj; + } + + paginationMode = [validValues indexOfObject:[prefValue lowercaseString]]; + if (paginationMode == NSNotFound) { + paginationMode = 0; + } + } + + // property check for compiling under iOS < 7 + ios7sel = NSSelectorFromString(@"setPaginationMode:"); + if ([self.webView respondsToSelector:ios7sel]) { + [self.webView setValue:[NSNumber numberWithInteger:paginationMode] forKey:@"paginationMode"]; + } + } + if ([self.startupPluginNames count] > 0) { [CDVTimer start:@"TotalPluginStartup"]; @@ -380,51 +460,40 @@ - (void)viewDidLoad [CDVTimer stop:@"TotalPluginStartup"]; } - // TODO: Remove this explicit instantiation once we move to cordova-CLI. - if (useSplashScreen) { - [self getCommandInstance:@"splashscreen"]; - } - // ///////////////// + NSURL* appURL = [self appUrl]; + [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) { _userAgentLockToken = lockToken; [CDVUserAgentUtil setUserAgent:self.userAgent lockToken:lockToken]; - if (!loadErr) { + if (appURL) { NSURLRequest* appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0]; [self.webView loadRequest:appReq]; } else { - NSString* html = [NSString stringWithFormat:@" %@ ", loadErr]; - [self.webView loadHTMLString:html baseURL:nil]; + NSString* loadErr = [NSString stringWithFormat:@"ERROR: Start Page at '%@/%@' was not found.", self.wwwFolderName, self.startPage]; + NSLog(@"%@", loadErr); + + NSURL* errorUrl = [self errorUrl]; + if (errorUrl) { + errorUrl = [NSURL URLWithString:[NSString stringWithFormat:@"?error=%@", [loadErr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] relativeToURL:errorUrl]; + NSLog(@"%@", [errorUrl absoluteString]); + [self.webView loadRequest:[NSURLRequest requestWithURL:errorUrl]]; + } else { + NSString* html = [NSString stringWithFormat:@" %@ ", loadErr]; + [self.webView loadHTMLString:html baseURL:nil]; + } } }]; } -- (void)hideKeyboardFormAccessoryBar -{ - NSArray* windows = [[UIApplication sharedApplication] windows]; - - for (UIWindow* window in windows) { - for (UIView* view in window.subviews) { - if ([[view description] hasPrefix:@" 0) { @@ -530,9 +599,14 @@ - (UIWebView*)newCordovaViewWithFrame:(CGRect)bounds - (NSString*)userAgent { if (_userAgent == nil) { - NSString* originalUserAgent = [CDVUserAgentUtil originalUserAgent]; + NSString* localBaseUserAgent; + if (self.baseUserAgent != nil) { + localBaseUserAgent = self.baseUserAgent; + } else { + localBaseUserAgent = [CDVUserAgentUtil originalUserAgent]; + } // Use our address as a unique number to append to the User-Agent. - _userAgent = [NSString stringWithFormat:@"%@ (%lld)", originalUserAgent, (long long)self]; + _userAgent = [NSString stringWithFormat:@"%@ (%lld)", localBaseUserAgent, (long long)self]; } return _userAgent; } @@ -543,19 +617,11 @@ - (void)createGapView webViewBounds.origin = self.view.bounds.origin; - if (!self.webView) { - self.webView = [self newCordovaViewWithFrame:webViewBounds]; - self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); - - [self.view addSubview:self.webView]; - [self.view sendSubviewToBack:self.webView]; + self.webView = [self newCordovaViewWithFrame:webViewBounds]; + self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); - _webViewDelegate = [[CDVWebViewDelegate alloc] initWithDelegate:self]; - self.webView.delegate = _webViewDelegate; - - // register this viewcontroller with the NSURLProtocol, only after the User-Agent is set - [CDVURLProtocol registerViewController:self]; - } + [self.view addSubview:self.webView]; + [self.view sendSubviewToBack:self.webView]; } - (void)didReceiveMemoryWarning @@ -591,6 +657,8 @@ - (void)viewDidUnload self.webView.delegate = nil; self.webView = nil; [CDVUserAgentUtil releaseLock:&_userAgentLockToken]; + + [super viewDidUnload]; } #pragma mark UIWebViewDelegate @@ -620,8 +688,6 @@ - (void)webViewDidFinishLoad:(UIWebView*)theWebView */ [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; - [self processOpenUrl]; - [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:self.webView]]; } @@ -629,7 +695,15 @@ - (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error { [CDVUserAgentUtil releaseLock:&_userAgentLockToken]; - NSLog(@"Failed to load webpage with error: %@", [error localizedDescription]); + NSString* message = [NSString stringWithFormat:@"Failed to load webpage with error: %@", [error localizedDescription]]; + NSLog(@"%@", message); + + NSURL* errorUrl = [self errorUrl]; + if (errorUrl) { + errorUrl = [NSURL URLWithString:[NSString stringWithFormat:@"?error=%@", [message stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] relativeToURL:errorUrl]; + NSLog(@"%@", [errorUrl absoluteString]); + [theWebView loadRequest:[NSURLRequest requestWithURL:errorUrl]]; + } } - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType @@ -642,13 +716,53 @@ - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest* */ if ([[url scheme] isEqualToString:@"gap"]) { [_commandQueue fetchCommandsFromJs]; + // The delegate is called asynchronously in this case, so we don't have to use + // flushCommandQueueWithDelayedJs (setTimeout(0)) as we do with hash changes. + [_commandQueue executePending]; + return NO; + } + + if ([[url fragment] hasPrefix:@"%01"] || [[url fragment] hasPrefix:@"%02"]) { + // Delegate is called *immediately* for hash changes. This means that any + // calls to stringByEvaluatingJavascriptFromString will occur in the middle + // of an existing (paused) call stack. This doesn't cause errors, but may + // be unexpected to callers (exec callbacks will be called before exec() even + // returns). To avoid this, we do not do any synchronous JS evals by using + // flushCommandQueueWithDelayedJs. + NSString* inlineCommands = [[url fragment] substringFromIndex:3]; + if ([inlineCommands length] == 0) { + // Reach in right away since the WebCore / Main thread are already synchronized. + [_commandQueue fetchCommandsFromJs]; + } else { + inlineCommands = [inlineCommands stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + [_commandQueue enqueueCommandBatch:inlineCommands]; + } + // Switch these for minor performance improvements, and to really live on the wild side. + // Callbacks will occur in the middle of the location.hash = ... statement! + [(CDVCommandDelegateImpl*)_commandDelegate flushCommandQueueWithDelayedJs]; + // [_commandQueue executePending]; + + // Although we return NO, the hash change does end up taking effect. return NO; } + /* + * Give plugins the chance to handle the url + */ + for (NSString* pluginName in pluginObjects) { + CDVPlugin* plugin = [pluginObjects objectForKey:pluginName]; + SEL selector = NSSelectorFromString(@"shouldOverrideLoadWithRequest:navigationType:"); + if ([plugin respondsToSelector:selector]) { + if (((BOOL (*)(id, SEL, id, int))objc_msgSend)(plugin, selector, request, navigationType) == YES) { + return NO; + } + } + } + /* * If a URL is being loaded that's a file/http/https URL, just load it internally */ - else if ([url isFileURL]) { + if ([url isFileURL]) { return YES; } @@ -710,27 +824,10 @@ - (void)javascriptAlert:(NSString*)text [self.commandDelegate evalJs:jsString]; } -+ (NSString*)resolveImageResource:(NSString*)resource -{ - NSString* systemVersion = [[UIDevice currentDevice] systemVersion]; - BOOL isLessThaniOS4 = ([systemVersion compare:@"4.0" options:NSNumericSearch] == NSOrderedAscending); - - // the iPad image (nor retina) differentiation code was not in 3.x, and we have to explicitly set the path - if (isLessThaniOS4) { - if (CDV_IsIPad()) { - return [NSString stringWithFormat:@"%@~ipad.png", resource]; - } else { - return [NSString stringWithFormat:@"%@.png", resource]; - } - } - - return resource; -} - + (NSString*)applicationDocumentsDirectory { NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString* basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil; + NSString* basePath = (([paths count] > 0) ? ([paths objectAtIndex : 0]) : nil); return basePath; } @@ -901,21 +998,37 @@ - (void)onAppDidEnterBackground:(NSNotification*)notification // /////////////////////// -- (void)handleOpenURL:(NSNotification*)notification +- (void)onPageDidLoad:(NSNotification*)notification { - self.openURL = notification.object; + if (self.openURL) { + [self processOpenUrl:self.openURL pageLoaded:YES]; + self.openURL = nil; + } } -- (void)processOpenUrl +- (void)processOpenUrl:(NSURL*)url pageLoaded:(BOOL)pageLoaded { - if (self.openURL) { + if (!pageLoaded) { + // query the webview for readystate + NSString* readyState = [webView stringByEvaluatingJavaScriptFromString:@"document.readyState"]; + pageLoaded = [readyState isEqualToString:@"loaded"] || [readyState isEqualToString:@"complete"]; + } + + if (pageLoaded) { // calls into javascript global function 'handleOpenURL' - NSString* jsString = [NSString stringWithFormat:@"handleOpenURL(\"%@\");", [self.openURL description]]; + NSString* jsString = [NSString stringWithFormat:@"if (typeof handleOpenURL === 'function') { handleOpenURL(\"%@\");}", url]; [self.webView stringByEvaluatingJavaScriptFromString:jsString]; - self.openURL = nil; + } else { + // save for when page has loaded + self.openURL = url; } } +- (void)processOpenUrl:(NSURL*)url +{ + [self processOpenUrl:url pageLoaded:NO]; +} + // /////////////////////// - (void)dealloc diff --git a/CordovaLib/Classes/CDVWebViewDelegate.h b/platforms/ios/CordovaLib/Classes/CDVWebViewDelegate.h old mode 100755 new mode 100644 similarity index 80% rename from CordovaLib/Classes/CDVWebViewDelegate.h rename to platforms/ios/CordovaLib/Classes/CDVWebViewDelegate.h index a4d78bd..4b60bab --- a/CordovaLib/Classes/CDVWebViewDelegate.h +++ b/platforms/ios/CordovaLib/Classes/CDVWebViewDelegate.h @@ -18,6 +18,7 @@ */ #import +#import "CDVAvailability.h" /** * Distinguishes top-level navigations from sub-frame navigations. @@ -34,5 +35,8 @@ } - (id)initWithDelegate:(NSObject *)delegate; +- (BOOL)request:(NSURLRequest*)newRequest isFragmentIdentifierToRequest:(NSURLRequest*)originalRequest CDV_DEPRECATED(3.5, "Use request:isEqualToRequestAfterStrippingFragments: instead."); + +- (BOOL)request:(NSURLRequest*)newRequest isEqualToRequestAfterStrippingFragments:(NSURLRequest*)originalRequest; @end diff --git a/CordovaLib/Classes/CDVWebViewDelegate.m b/platforms/ios/CordovaLib/Classes/CDVWebViewDelegate.m old mode 100755 new mode 100644 similarity index 70% rename from CordovaLib/Classes/CDVWebViewDelegate.m rename to platforms/ios/CordovaLib/Classes/CDVWebViewDelegate.m index fd9c032..5a187f4 --- a/CordovaLib/Classes/CDVWebViewDelegate.m +++ b/platforms/ios/CordovaLib/Classes/CDVWebViewDelegate.m @@ -83,13 +83,24 @@ Licensed to the Apache Software Foundation (ASF) under one #define VerboseLog(...) do {} while (0) typedef enum { - STATE_IDLE, - STATE_WAITING_FOR_LOAD_START, - STATE_WAITING_FOR_LOAD_FINISH, - STATE_IOS5_POLLING_FOR_LOAD_START, - STATE_IOS5_POLLING_FOR_LOAD_FINISH + STATE_IDLE = 0, + STATE_WAITING_FOR_LOAD_START = 1, + STATE_WAITING_FOR_LOAD_FINISH = 2, + STATE_IOS5_POLLING_FOR_LOAD_START = 3, + STATE_IOS5_POLLING_FOR_LOAD_FINISH = 4, + STATE_CANCELLED = 5 } State; +static NSString *stripFragment(NSString* url) +{ + NSRange r = [url rangeOfString:@"#"]; + + if (r.location == NSNotFound) { + return url; + } + return [url substringToIndex:r.location]; +} + @implementation CDVWebViewDelegate - (id)initWithDelegate:(NSObject *)delegate @@ -103,6 +114,25 @@ - (id)initWithDelegate:(NSObject *)delegate return self; } +- (BOOL)request:(NSURLRequest*)newRequest isFragmentIdentifierToRequest:(NSURLRequest*)originalRequest +{ + return [self request:newRequest isEqualToRequestAfterStrippingFragments:originalRequest]; +} + +- (BOOL)request:(NSURLRequest*)newRequest isEqualToRequestAfterStrippingFragments:(NSURLRequest*)originalRequest +{ + if (originalRequest.URL && newRequest.URL) { + NSString* originalRequestUrl = [originalRequest.URL absoluteString]; + NSString* newRequestUrl = [newRequest.URL absoluteString]; + + NSString* baseOriginalRequestUrl = stripFragment(originalRequestUrl); + NSString* baseNewRequestUrl = stripFragment(newRequestUrl); + return [baseOriginalRequestUrl isEqualToString:baseNewRequestUrl]; + } + + return NO; +} + - (BOOL)isPageLoaded:(UIWebView*)webView { NSString* readyState = [webView stringByEvaluatingJavaScriptFromString:@"document.readyState"]; @@ -114,13 +144,18 @@ - (BOOL)isJsLoadTokenSet:(UIWebView*)webView { NSString* loadToken = [webView stringByEvaluatingJavaScriptFromString:@"window.__cordovaLoadToken"]; - return [[NSString stringWithFormat:@"%d", _curLoadToken] isEqualToString:loadToken]; + return [[NSString stringWithFormat:@"%ld", (long)_curLoadToken] isEqualToString:loadToken]; } - (void)setLoadToken:(UIWebView*)webView { _curLoadToken += 1; - [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.__cordovaLoadToken=%d", _curLoadToken]]; + [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.__cordovaLoadToken=%ld", (long)_curLoadToken]]; +} + +- (NSString*)evalForCurrentURL:(UIWebView*)webView +{ + return [webView stringByEvaluatingJavaScriptFromString:@"location.href"]; } - (void)pollForPageLoadStart:(UIWebView*)webView @@ -163,6 +198,17 @@ - (void)pollForPageLoadFinish:(UIWebView*)webView } } +- (BOOL)shouldLoadRequest:(NSURLRequest*)request +{ + NSString* scheme = [[request URL] scheme]; + + if ([scheme isEqualToString:@"mailto"] || [scheme isEqualToString:@"tel"]) { + return YES; + } + + return [NSURLConnection canHandleRequest:request]; +} + - (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType { BOOL shouldLoad = YES; @@ -174,36 +220,57 @@ - (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)re VerboseLog(@"webView shouldLoad=%d (before) state=%d loadCount=%d URL=%@", shouldLoad, _state, _loadCount, request.URL); if (shouldLoad) { - BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]]; + // When devtools refresh occurs, it blindly uses the same request object. If a history.replaceState() has occured, then + // mainDocumentURL != URL even though it's a top-level navigation. + BOOL isDevToolsRefresh = (request == webView.request); + BOOL isTopLevelNavigation = isDevToolsRefresh || [request.URL isEqual:[request mainDocumentURL]]; if (isTopLevelNavigation) { + // Ignore hash changes that don't navigate to a different page. + // webView.request does actually update when history.replaceState() gets called. + if ([self request:request isEqualToRequestAfterStrippingFragments:webView.request]) { + NSString* prevURL = [self evalForCurrentURL:webView]; + if ([prevURL isEqualToString:[request.URL absoluteString]]) { + VerboseLog(@"Page reload detected."); + } else { + VerboseLog(@"Detected hash change shouldLoad"); + return shouldLoad; + } + } + switch (_state) { case STATE_WAITING_FOR_LOAD_FINISH: // Redirect case. // We expect loadCount == 1. if (_loadCount != 1) { - NSLog(@"CDVWebViewDelegate: Detected redirect when loadCount=%d", _loadCount); + NSLog(@"CDVWebViewDelegate: Detected redirect when loadCount=%ld", (long)_loadCount); } break; case STATE_IDLE: case STATE_IOS5_POLLING_FOR_LOAD_START: + case STATE_CANCELLED: // Page navigation start. _loadCount = 0; _state = STATE_WAITING_FOR_LOAD_START; break; default: - NSLog(@"CDVWebViewDelegate: Navigation started when state=%d", _state); - _loadCount = 0; - _state = STATE_WAITING_FOR_LOAD_START; - if ([_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) { - [_delegate webView:webView didFailLoadWithError:nil]; + { + _loadCount = 0; + _state = STATE_WAITING_FOR_LOAD_START; + NSString* description = [NSString stringWithFormat:@"CDVWebViewDelegate: Navigation started when state=%ld", (long)_state]; + NSLog(@"%@", description); + if ([_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) { + NSDictionary* errorDictionary = @{NSLocalizedDescriptionKey : description}; + NSError* error = [[NSError alloc] initWithDomain:@"CDVWebViewDelegate" code:1 userInfo:errorDictionary]; + [_delegate webView:webView didFailLoadWithError:error]; + } } } } else { // Deny invalid URLs so that we don't get the case where we go straight from // webViewShouldLoad -> webViewDidFailLoad (messes up _loadCount). - shouldLoad = shouldLoad && [NSURLConnection canHandleRequest:request]; + shouldLoad = shouldLoad && [self shouldLoadRequest:request]; } VerboseLog(@"webView shouldLoad=%d (after) isTopLevelNavigation=%d state=%d loadCount=%d", shouldLoad, isTopLevelNavigation, _state, _loadCount); } @@ -224,16 +291,22 @@ - (void)webViewDidStartLoad:(UIWebView*)webView // We could try to distinguish using [UIWebView canGoForward], but that's too much complexity, // and would work only on the first time it was used. - // Our work-around is to set a JS variable and poll until it disappears (from a naviagtion). + // Our work-around is to set a JS variable and poll until it disappears (from a navigation). _state = STATE_IOS5_POLLING_FOR_LOAD_START; _loadStartPollCount = 0; [self setLoadToken:webView]; [self pollForPageLoadStart:webView]; break; + case STATE_CANCELLED: + fireCallback = YES; + _state = STATE_WAITING_FOR_LOAD_FINISH; + _loadCount += 1; + break; + case STATE_WAITING_FOR_LOAD_START: if (_loadCount != 0) { - NSLog(@"CDVWebViewDelegate: Unexpected loadCount in didStart. count=%d", _loadCount); + NSLog(@"CDVWebViewDelegate: Unexpected loadCount in didStart. count=%ld", (long)_loadCount); } fireCallback = YES; _state = STATE_WAITING_FOR_LOAD_FINISH; @@ -253,7 +326,7 @@ - (void)webViewDidStartLoad:(UIWebView*)webView break; default: - NSLog(@"CDVWebViewDelegate: Unexpected didStart with state=%d loadCount=%d", _state, _loadCount); + NSLog(@"CDVWebViewDelegate: Unexpected didStart with state=%ld loadCount=%ld", (long)_state, (long)_loadCount); } VerboseLog(@"webView didStartLoad (after). state=%d loadCount=%d fireCallback=%d", _state, _loadCount, fireCallback); if (fireCallback && [_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) { @@ -305,16 +378,26 @@ - (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error break; case STATE_WAITING_FOR_LOAD_START: - _state = STATE_IDLE; + if ([error code] == NSURLErrorCancelled) { + _state = STATE_CANCELLED; + } else { + _state = STATE_IDLE; + } fireCallback = YES; break; case STATE_WAITING_FOR_LOAD_FINISH: - if (_loadCount == 1) { - _state = STATE_IDLE; + if ([error code] != NSURLErrorCancelled) { + if (_loadCount == 1) { + _state = STATE_IDLE; + fireCallback = YES; + } + _loadCount = -1; + } else { fireCallback = YES; + _state = STATE_CANCELLED; + _loadCount -= 1; } - _loadCount = -1; break; case STATE_IOS5_POLLING_FOR_LOAD_START: diff --git a/CordovaLib/Classes/CDVWhitelist.h b/platforms/ios/CordovaLib/Classes/CDVWhitelist.h old mode 100755 new mode 100644 similarity index 94% rename from CordovaLib/Classes/CDVWhitelist.h rename to platforms/ios/CordovaLib/Classes/CDVWhitelist.h index e339dd0..9165097 --- a/CordovaLib/Classes/CDVWhitelist.h +++ b/platforms/ios/CordovaLib/Classes/CDVWhitelist.h @@ -28,6 +28,7 @@ extern NSString* const kCDVDefaultWhitelistRejectionString; - (id)initWithArray:(NSArray*)array; - (BOOL)schemeIsAllowed:(NSString*)scheme; - (BOOL)URLIsAllowed:(NSURL*)url; +- (BOOL)URLIsAllowed:(NSURL*)url logFailure:(BOOL)logFailure; - (NSString*)errorStringForURL:(NSURL*)url; @end diff --git a/platforms/ios/CordovaLib/Classes/CDVWhitelist.m b/platforms/ios/CordovaLib/Classes/CDVWhitelist.m new file mode 100644 index 0000000..8e3be75 --- /dev/null +++ b/platforms/ios/CordovaLib/Classes/CDVWhitelist.m @@ -0,0 +1,285 @@ +/* + 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 "CDVWhitelist.h" + +NSString* const kCDVDefaultWhitelistRejectionString = @"ERROR whitelist rejection: url='%@'"; +NSString* const kCDVDefaultSchemeName = @"cdv-default-scheme"; + +@interface CDVWhitelistPattern : NSObject { + @private + NSRegularExpression* _scheme; + NSRegularExpression* _host; + NSNumber* _port; + NSRegularExpression* _path; +} + ++ (NSString*)regexFromPattern:(NSString*)pattern allowWildcards:(bool)allowWildcards; +- (id)initWithScheme:(NSString*)scheme host:(NSString*)host port:(NSString*)port path:(NSString*)path; +- (bool)matches:(NSURL*)url; + +@end + +@implementation CDVWhitelistPattern + ++ (NSString*)regexFromPattern:(NSString*)pattern allowWildcards:(bool)allowWildcards +{ + NSString* regex = [NSRegularExpression escapedPatternForString:pattern]; + + if (allowWildcards) { + regex = [regex stringByReplacingOccurrencesOfString:@"\\*" withString:@".*"]; + + /* [NSURL path] has the peculiarity that a trailing slash at the end of a path + * will be omitted. This regex tweak compensates for that. + */ + if ([regex hasSuffix:@"\\/.*"]) { + regex = [NSString stringWithFormat:@"%@(\\/.*)?", [regex substringToIndex:([regex length] - 4)]]; + } + } + return [NSString stringWithFormat:@"%@$", regex]; +} + +- (id)initWithScheme:(NSString*)scheme host:(NSString*)host port:(NSString*)port path:(NSString*)path +{ + self = [super init]; // Potentially change "self" + if (self) { + if ((scheme == nil) || [scheme isEqualToString:@"*"]) { + _scheme = nil; + } else { + _scheme = [NSRegularExpression regularExpressionWithPattern:[CDVWhitelistPattern regexFromPattern:scheme allowWildcards:NO] options:NSRegularExpressionCaseInsensitive error:nil]; + } + if ([host isEqualToString:@"*"]) { + _host = nil; + } else if ([host hasPrefix:@"*."]) { + _host = [NSRegularExpression regularExpressionWithPattern:[NSString stringWithFormat:@"([a-z0-9.-]*\\.)?%@", [CDVWhitelistPattern regexFromPattern:[host substringFromIndex:2] allowWildcards:false]] options:NSRegularExpressionCaseInsensitive error:nil]; + } else { + _host = [NSRegularExpression regularExpressionWithPattern:[CDVWhitelistPattern regexFromPattern:host allowWildcards:NO] options:NSRegularExpressionCaseInsensitive error:nil]; + } + if ((port == nil) || [port isEqualToString:@"*"]) { + _port = nil; + } else { + _port = [[NSNumber alloc] initWithInteger:[port integerValue]]; + } + if ((path == nil) || [path isEqualToString:@"/*"]) { + _path = nil; + } else { + _path = [NSRegularExpression regularExpressionWithPattern:[CDVWhitelistPattern regexFromPattern:path allowWildcards:YES] options:0 error:nil]; + } + } + return self; +} + +- (bool)matches:(NSURL*)url +{ + return (_scheme == nil || [_scheme numberOfMatchesInString:[url scheme] options:NSMatchingAnchored range:NSMakeRange(0, [[url scheme] length])]) && + (_host == nil || [_host numberOfMatchesInString:[url host] options:NSMatchingAnchored range:NSMakeRange(0, [[url host] length])]) && + (_port == nil || [[url port] isEqualToNumber:_port]) && + (_path == nil || [_path numberOfMatchesInString:[url path] options:NSMatchingAnchored range:NSMakeRange(0, [[url path] length])]) + ; +} + +@end + +@interface CDVWhitelist () + +@property (nonatomic, readwrite, strong) NSMutableArray* whitelist; +@property (nonatomic, readwrite, strong) NSMutableSet* permittedSchemes; + +- (void)addWhiteListEntry:(NSString*)pattern; + +@end + +@implementation CDVWhitelist + +@synthesize whitelist, permittedSchemes, whitelistRejectionFormatString; + +- (id)initWithArray:(NSArray*)array +{ + self = [super init]; + if (self) { + self.whitelist = [[NSMutableArray alloc] init]; + self.permittedSchemes = [[NSMutableSet alloc] init]; + self.whitelistRejectionFormatString = kCDVDefaultWhitelistRejectionString; + + for (NSString* pattern in array) { + [self addWhiteListEntry:pattern]; + } + } + return self; +} + +- (BOOL)isIPv4Address:(NSString*)externalHost +{ + // an IPv4 address has 4 octets b.b.b.b where b is a number between 0 and 255. + // for our purposes, b can also be the wildcard character '*' + + // we could use a regex to solve this problem but then I would have two problems + // anyways, this is much clearer and maintainable + NSArray* octets = [externalHost componentsSeparatedByString:@"."]; + NSUInteger num_octets = [octets count]; + + // quick check + if (num_octets != 4) { + return NO; + } + + // restrict number parsing to 0-255 + NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init]; + [numberFormatter setMinimum:[NSNumber numberWithUnsignedInteger:0]]; + [numberFormatter setMaximum:[NSNumber numberWithUnsignedInteger:255]]; + + // iterate through each octet, and test for a number between 0-255 or if it equals '*' + for (NSUInteger i = 0; i < num_octets; ++i) { + NSString* octet = [octets objectAtIndex:i]; + + if ([octet isEqualToString:@"*"]) { // passes - check next octet + continue; + } else if ([numberFormatter numberFromString:octet] == nil) { // fails - not a number and not within our range, return + return NO; + } + } + + return YES; +} + +- (void)addWhiteListEntry:(NSString*)origin +{ + if (self.whitelist == nil) { + return; + } + + if ([origin isEqualToString:@"*"]) { + NSLog(@"Unlimited access to network resources"); + self.whitelist = nil; + self.permittedSchemes = nil; + } else { // specific access + NSRegularExpression* parts = [NSRegularExpression regularExpressionWithPattern:@"^((\\*|[A-Za-z-]+)://)?(((\\*\\.)?[^*/:]+)|\\*)?(:(\\d+))?(/.*)?" options:0 error:nil]; + NSTextCheckingResult* m = [parts firstMatchInString:origin options:NSMatchingAnchored range:NSMakeRange(0, [origin length])]; + if (m != nil) { + NSRange r; + NSString* scheme = nil; + r = [m rangeAtIndex:2]; + if (r.location != NSNotFound) { + scheme = [origin substringWithRange:r]; + } + + NSString* host = nil; + r = [m rangeAtIndex:3]; + if (r.location != NSNotFound) { + host = [origin substringWithRange:r]; + } + + // Special case for two urls which are allowed to have empty hosts + if (([scheme isEqualToString:@"file"] || [scheme isEqualToString:@"content"]) && (host == nil)) { + host = @"*"; + } + + NSString* port = nil; + r = [m rangeAtIndex:7]; + if (r.location != NSNotFound) { + port = [origin substringWithRange:r]; + } + + NSString* path = nil; + r = [m rangeAtIndex:8]; + if (r.location != NSNotFound) { + path = [origin substringWithRange:r]; + } + + if (scheme == nil) { + // XXX making it stupid friendly for people who forget to include protocol/SSL + [self.whitelist addObject:[[CDVWhitelistPattern alloc] initWithScheme:@"http" host:host port:port path:path]]; + [self.whitelist addObject:[[CDVWhitelistPattern alloc] initWithScheme:@"https" host:host port:port path:path]]; + } else { + [self.whitelist addObject:[[CDVWhitelistPattern alloc] initWithScheme:scheme host:host port:port path:path]]; + } + + if (self.permittedSchemes != nil) { + if ([scheme isEqualToString:@"*"]) { + self.permittedSchemes = nil; + } else if (scheme != nil) { + [self.permittedSchemes addObject:scheme]; + } + } + } + } +} + +- (BOOL)schemeIsAllowed:(NSString*)scheme +{ + if ([scheme isEqualToString:@"http"] || + [scheme isEqualToString:@"https"] || + [scheme isEqualToString:@"ftp"] || + [scheme isEqualToString:@"ftps"]) { + return YES; + } + + return (self.permittedSchemes == nil) || [self.permittedSchemes containsObject:scheme]; +} + +- (BOOL)URLIsAllowed:(NSURL*)url +{ + return [self URLIsAllowed:url logFailure:YES]; +} + +- (BOOL)URLIsAllowed:(NSURL*)url logFailure:(BOOL)logFailure +{ + // Shortcut acceptance: Are all urls whitelisted ("*" in whitelist)? + if (whitelist == nil) { + return YES; + } + + // Shortcut rejection: Check that the scheme is supported + NSString* scheme = [[url scheme] lowercaseString]; + if (![self schemeIsAllowed:scheme]) { + if (logFailure) { + NSLog(@"%@", [self errorStringForURL:url]); + } + return NO; + } + + // http[s] and ftp[s] should also validate against the common set in the kCDVDefaultSchemeName list + if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"] || [scheme isEqualToString:@"ftp"] || [scheme isEqualToString:@"ftps"]) { + NSURL* newUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@%@", kCDVDefaultSchemeName, [url host], [[url path] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; + // If it is allowed, we are done. If not, continue to check for the actual scheme-specific list + if ([self URLIsAllowed:newUrl logFailure:NO]) { + return YES; + } + } + + // Check the url against patterns in the whitelist + for (CDVWhitelistPattern* p in self.whitelist) { + if ([p matches:url]) { + return YES; + } + } + + if (logFailure) { + NSLog(@"%@", [self errorStringForURL:url]); + } + // if we got here, the url host is not in the white-list, do nothing + return NO; +} + +- (NSString*)errorStringForURL:(NSURL*)url +{ + return [NSString stringWithFormat:self.whitelistRejectionFormatString, [url absoluteString]]; +} + +@end diff --git a/CordovaLib/Classes/NSArray+Comparisons.h b/platforms/ios/CordovaLib/Classes/NSArray+Comparisons.h old mode 100755 new mode 100644 similarity index 100% rename from CordovaLib/Classes/NSArray+Comparisons.h rename to platforms/ios/CordovaLib/Classes/NSArray+Comparisons.h diff --git a/CordovaLib/Classes/NSArray+Comparisons.m b/platforms/ios/CordovaLib/Classes/NSArray+Comparisons.m old mode 100755 new mode 100644 similarity index 92% rename from CordovaLib/Classes/NSArray+Comparisons.m rename to platforms/ios/CordovaLib/Classes/NSArray+Comparisons.m index 485e3c8..e29c03d --- a/CordovaLib/Classes/NSArray+Comparisons.m +++ b/platforms/ios/CordovaLib/Classes/NSArray+Comparisons.m @@ -24,9 +24,11 @@ @implementation NSArray (Comparisons) - (id)objectAtIndex:(NSUInteger)index withDefault:(id)aDefault { id obj = nil; - + @try { - obj = [self objectAtIndex:index]; + if (index < [self count]) { + obj = [self objectAtIndex:index]; + } if ((obj == [NSNull null]) || (obj == nil)) { return aDefault; } @@ -34,7 +36,7 @@ - (id)objectAtIndex:(NSUInteger)index withDefault:(id)aDefault @catch(NSException* exception) { NSLog(@"Exception - Name: %@ Reason: %@", [exception name], [exception reason]); } - + return obj; } diff --git a/platforms/ios/CordovaLib/Classes/NSData+Base64.h b/platforms/ios/CordovaLib/Classes/NSData+Base64.h new file mode 100644 index 0000000..d5a9a6f --- /dev/null +++ b/platforms/ios/CordovaLib/Classes/NSData+Base64.h @@ -0,0 +1,42 @@ +// +// NSData+Base64.h +// base64 +// +// Created by Matt Gallagher on 2009/06/03. +// Copyright 2009 Matt Gallagher. All rights reserved. +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. Permission is granted to anyone to +// use this software for any purpose, including commercial applications, and to +// alter it and redistribute it freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. +// + +#import + +void *CDVNewBase64Decode( + const char* inputBuffer, + size_t length, + size_t * outputLength); + +char *CDVNewBase64Encode( + const void* inputBuffer, + size_t length, + bool separateLines, + size_t * outputLength); + +@interface NSData (CDVBase64) + ++ (NSData*)dataFromBase64String:(NSString*)aString; +- (NSString*)base64EncodedString; + +@end diff --git a/CordovaLib/Classes/NSData+Base64.m b/platforms/ios/CordovaLib/Classes/NSData+Base64.m old mode 100755 new mode 100644 similarity index 68% rename from CordovaLib/Classes/NSData+Base64.m rename to platforms/ios/CordovaLib/Classes/NSData+Base64.m index d0f2189..c9d67f9 --- a/CordovaLib/Classes/NSData+Base64.m +++ b/platforms/ios/CordovaLib/Classes/NSData+Base64.m @@ -5,11 +5,20 @@ // Created by Matt Gallagher on 2009/06/03. // Copyright 2009 Matt Gallagher. All rights reserved. // -// Permission is given to use this source code file, free of charge, in any -// project, commercial or otherwise, entirely at your risk, with the condition -// that any redistribution (in part or whole) of source code must retain -// this copyright and permission notice. Attribution in compiled projects is -// appreciated but not required. +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. Permission is granted to anyone to +// use this software for any purpose, including commercial applications, and to +// alter it and redistribute it freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. // #import "NSData+Base64.h" @@ -17,7 +26,7 @@ // // Mapping from 6 bit pattern to ASCII character. // -static unsigned char cdvbase64EncodeLookup[65] = +static unsigned char base64EncodeLookup[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; // @@ -28,7 +37,7 @@ // // Mapping from ASCII character to 6 bit pattern. // -static unsigned char cdvbase64DecodeLookup[256] = +static unsigned char base64DecodeLookup[256] = { xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, @@ -51,8 +60,8 @@ // // Fundamental sizes of the binary and base64 encode/decode units in bytes // -#define CDV_BINARY_UNIT_SIZE 3 -#define CDV_BASE64_UNIT_SIZE 4 +#define BINARY_UNIT_SIZE 3 +#define BASE64_UNIT_SIZE 4 // // NewBase64Decode @@ -64,7 +73,7 @@ // length - the length of the string or -1 (to specify strlen should be used) // outputLength - if not-NULL, on output will contain the decoded length // -// returns the decoded buffer. Must be freed by caller. Length is given by +// returns the decoded buffer. Must be free'd by caller. Length is given by // outputLength. // void *CDVNewBase64Decode( @@ -76,7 +85,8 @@ length = strlen(inputBuffer); } - size_t outputBufferSize = (length / CDV_BASE64_UNIT_SIZE) * CDV_BINARY_UNIT_SIZE; + size_t outputBufferSize = + ((length + BASE64_UNIT_SIZE - 1) / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE; unsigned char* outputBuffer = (unsigned char*)malloc(outputBufferSize); size_t i = 0; @@ -86,17 +96,16 @@ // // Accumulate 4 valid characters (ignore everything else) // - unsigned char accumulated[CDV_BASE64_UNIT_SIZE]; - bzero(accumulated, sizeof(unsigned char) * CDV_BASE64_UNIT_SIZE); + unsigned char accumulated[BASE64_UNIT_SIZE]; size_t accumulateIndex = 0; while (i < length) { - unsigned char decode = cdvbase64DecodeLookup[inputBuffer[i++]]; + unsigned char decode = base64DecodeLookup[inputBuffer[i++]]; if (decode != xx) { accumulated[accumulateIndex] = decode; accumulateIndex++; - if (accumulateIndex == CDV_BASE64_UNIT_SIZE) { + if (accumulateIndex == BASE64_UNIT_SIZE) { break; } } @@ -105,9 +114,17 @@ // // Store the 6 bits from each of the 4 characters as 3 bytes // - outputBuffer[j] = (accumulated[0] << 2) | (accumulated[1] >> 4); - outputBuffer[j + 1] = (accumulated[1] << 4) | (accumulated[2] >> 2); - outputBuffer[j + 2] = (accumulated[2] << 6) | accumulated[3]; + // (Uses improved bounds checking suggested by Alexandre Colucci) + // + if (accumulateIndex >= 2) { + outputBuffer[j] = (accumulated[0] << 2) | (accumulated[1] >> 4); + } + if (accumulateIndex >= 3) { + outputBuffer[j + 1] = (accumulated[1] << 4) | (accumulated[2] >> 2); + } + if (accumulateIndex >= 4) { + outputBuffer[j + 2] = (accumulated[2] << 6) | accumulated[3]; + } j += accumulateIndex - 1; } @@ -118,7 +135,7 @@ } // -// NewBase64Decode +// NewBase64Encode // // Encodes the arbitrary data in the inputBuffer as base64 into a newly malloced // output buffer. @@ -130,7 +147,7 @@ // outputLength - if not-NULL, on output will contain the encoded length // (not including terminating 0 char) // -// returns the encoded buffer. Must be freed by caller. Length is given by +// returns the encoded buffer. Must be free'd by caller. Length is given by // outputLength. // char *CDVNewBase64Encode( @@ -143,16 +160,16 @@ #define MAX_NUM_PADDING_CHARS 2 #define OUTPUT_LINE_LENGTH 64 -#define INPUT_LINE_LENGTH ((OUTPUT_LINE_LENGTH / CDV_BASE64_UNIT_SIZE) * CDV_BINARY_UNIT_SIZE) -#define CR_LF_SIZE 0 +#define INPUT_LINE_LENGTH ((OUTPUT_LINE_LENGTH / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE) +#define CR_LF_SIZE 2 // // Byte accurate calculation of final buffer size // size_t outputBufferSize = - ((length / CDV_BINARY_UNIT_SIZE) - + ((length % CDV_BINARY_UNIT_SIZE) ? 1 : 0)) - * CDV_BASE64_UNIT_SIZE; + ((length / BINARY_UNIT_SIZE) + + ((length % BINARY_UNIT_SIZE) ? 1 : 0)) + * BASE64_UNIT_SIZE; if (separateLines) { outputBufferSize += (outputBufferSize / OUTPUT_LINE_LENGTH) * CR_LF_SIZE; @@ -181,16 +198,16 @@ lineEnd = length; } - for (; i + CDV_BINARY_UNIT_SIZE - 1 < lineEnd; i += CDV_BINARY_UNIT_SIZE) { + for (; i + BINARY_UNIT_SIZE - 1 < lineEnd; i += BINARY_UNIT_SIZE) { // // Inner loop: turn 48 bytes into 64 base64 characters // - outputBuffer[j++] = cdvbase64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; - outputBuffer[j++] = cdvbase64EncodeLookup[((inputBuffer[i] & 0x03) << 4) + outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; + outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4) | ((inputBuffer[i + 1] & 0xF0) >> 4)]; - outputBuffer[j++] = cdvbase64EncodeLookup[((inputBuffer[i + 1] & 0x0F) << 2) + outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i + 1] & 0x0F) << 2) | ((inputBuffer[i + 2] & 0xC0) >> 6)]; - outputBuffer[j++] = cdvbase64EncodeLookup[inputBuffer[i + 2] & 0x3F]; + outputBuffer[j++] = base64EncodeLookup[inputBuffer[i + 2] & 0x3F]; } if (lineEnd == length) { @@ -209,17 +226,17 @@ // // Handle the single '=' case // - outputBuffer[j++] = cdvbase64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; - outputBuffer[j++] = cdvbase64EncodeLookup[((inputBuffer[i] & 0x03) << 4) + outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; + outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4) | ((inputBuffer[i + 1] & 0xF0) >> 4)]; - outputBuffer[j++] = cdvbase64EncodeLookup[(inputBuffer[i + 1] & 0x0F) << 2]; + outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i + 1] & 0x0F) << 2]; outputBuffer[j++] = '='; } else if (i < length) { // // Handle the double '=' case // - outputBuffer[j++] = cdvbase64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; - outputBuffer[j++] = cdvbase64EncodeLookup[(inputBuffer[i] & 0x03) << 4]; + outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; + outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0x03) << 4]; outputBuffer[j++] = '='; outputBuffer[j++] = '='; } diff --git a/CordovaLib/Classes/NSDictionary+Extensions.h b/platforms/ios/CordovaLib/Classes/NSDictionary+Extensions.h old mode 100755 new mode 100644 similarity index 100% rename from CordovaLib/Classes/NSDictionary+Extensions.h rename to platforms/ios/CordovaLib/Classes/NSDictionary+Extensions.h diff --git a/CordovaLib/Classes/NSDictionary+Extensions.m b/platforms/ios/CordovaLib/Classes/NSDictionary+Extensions.m old mode 100755 new mode 100644 similarity index 100% rename from CordovaLib/Classes/NSDictionary+Extensions.m rename to platforms/ios/CordovaLib/Classes/NSDictionary+Extensions.m diff --git a/CordovaLib/Classes/NSMutableArray+QueueAdditions.h b/platforms/ios/CordovaLib/Classes/NSMutableArray+QueueAdditions.h old mode 100755 new mode 100644 similarity index 100% rename from CordovaLib/Classes/NSMutableArray+QueueAdditions.h rename to platforms/ios/CordovaLib/Classes/NSMutableArray+QueueAdditions.h diff --git a/CordovaLib/Classes/NSMutableArray+QueueAdditions.m b/platforms/ios/CordovaLib/Classes/NSMutableArray+QueueAdditions.m old mode 100755 new mode 100644 similarity index 100% rename from CordovaLib/Classes/NSMutableArray+QueueAdditions.m rename to platforms/ios/CordovaLib/Classes/NSMutableArray+QueueAdditions.m diff --git a/CordovaLib/Classes/UIDevice+Extensions.h b/platforms/ios/CordovaLib/Classes/UIDevice+Extensions.h old mode 100755 new mode 100644 similarity index 100% rename from CordovaLib/Classes/UIDevice+Extensions.h rename to platforms/ios/CordovaLib/Classes/UIDevice+Extensions.h diff --git a/CordovaLib/Classes/UIDevice+Extensions.m b/platforms/ios/CordovaLib/Classes/UIDevice+Extensions.m old mode 100755 new mode 100644 similarity index 100% rename from CordovaLib/Classes/UIDevice+Extensions.m rename to platforms/ios/CordovaLib/Classes/UIDevice+Extensions.m diff --git a/CordovaLib/CordovaLib.xcodeproj/project.pbxproj b/platforms/ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj old mode 100755 new mode 100644 similarity index 61% rename from CordovaLib/CordovaLib.xcodeproj/project.pbxproj rename to platforms/ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj index c637d60..63c294c --- a/CordovaLib/CordovaLib.xcodeproj/project.pbxproj +++ b/platforms/ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj @@ -7,12 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 1F2BECC013F9785B00A93BF6 /* CDVBattery.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F2BECBE13F9785B00A93BF6 /* CDVBattery.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1F2BECC113F9785B00A93BF6 /* CDVBattery.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F2BECBF13F9785B00A93BF6 /* CDVBattery.m */; }; - 1F3C04CE12BC247D004F9E10 /* CDVContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F3C04CC12BC247D004F9E10 /* CDVContact.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1F3C04CF12BC247D004F9E10 /* CDVContact.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F3C04CD12BC247D004F9E10 /* CDVContact.m */; }; - 1F584B9B1385A28A00ED25E8 /* CDVCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F584B991385A28900ED25E8 /* CDVCapture.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1F584B9C1385A28A00ED25E8 /* CDVCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F584B9A1385A28900ED25E8 /* CDVCapture.m */; }; + 1B701028177A61CF00AE11F4 /* CDVShared.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B701026177A61CF00AE11F4 /* CDVShared.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F92F4A01314023E0046367C /* CDVPluginResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F92F49E1314023E0046367C /* CDVPluginResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F92F4A11314023E0046367C /* CDVPluginResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F92F49F1314023E0046367C /* CDVPluginResult.m */; }; 301F2F2A14F3C9CA003FE9FC /* CDV.h in Headers */ = {isa = PBXBuildFile; fileRef = 301F2F2914F3C9CA003FE9FC /* CDV.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -22,15 +17,7 @@ 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 */; }; - 30B39EBE13D0268B0009682A /* CDVSplashScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = 30B39EBC13D0268B0009682A /* CDVSplashScreen.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 30B39EBF13D0268B0009682A /* CDVSplashScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 30B39EBD13D0268B0009682A /* CDVSplashScreen.m */; }; - 30C5F1DF15AF9E950052A00D /* CDVDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 30C5F1DD15AF9E950052A00D /* CDVDevice.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 30C5F1E015AF9E950052A00D /* CDVDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 30C5F1DE15AF9E950052A00D /* CDVDevice.m */; }; 30C684801406CB38004C1A8E /* CDVWhitelist.h in Headers */ = {isa = PBXBuildFile; fileRef = 30C6847E1406CB38004C1A8E /* CDVWhitelist.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30C684821406CB38004C1A8E /* CDVWhitelist.m in Sources */ = {isa = PBXBuildFile; fileRef = 30C6847F1406CB38004C1A8E /* CDVWhitelist.m */; }; 30C684941407044B004C1A8E /* CDVURLProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 30C684921407044A004C1A8E /* CDVURLProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -42,47 +29,21 @@ 30F3930B169F839700B22307 /* CDVJSON.h in Headers */ = {isa = PBXBuildFile; fileRef = 30F39309169F839700B22307 /* CDVJSON.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30F3930C169F839700B22307 /* CDVJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 30F3930A169F839700B22307 /* CDVJSON.m */; }; 30F5EBAB14CA26E700987760 /* CDVCommandDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 30F5EBA914CA26E700987760 /* CDVCommandDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3E76876D156A90EE00EB6FA3 /* CDVLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E76876B156A90EE00EB6FA3 /* CDVLogger.m */; }; - 3E76876F156A90EE00EB6FA3 /* CDVLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 3E76876C156A90EE00EB6FA3 /* CDVLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 68B7516E16FD18190076A8B4 /* CDVJpegHeaderWriter.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B7516B16FD18190076A8B4 /* CDVJpegHeaderWriter.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 68B7516F16FD18190076A8B4 /* CDVJpegHeaderWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 68B7516C16FD18190076A8B4 /* CDVJpegHeaderWriter.m */; }; - 68B7517016FD19F80076A8B4 /* CDVExif.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B7516A16FD18190076A8B4 /* CDVExif.h */; settings = {ATTRIBUTES = (Public, ); }; }; 7E14B5A81705050A0032169E /* CDVTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E14B5A61705050A0032169E /* CDVTimer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 7E14B5A91705050A0032169E /* CDVTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E14B5A71705050A0032169E /* CDVTimer.m */; }; + 7E22B88519E4C0210026F95E /* CDVAvailabilityDeprecated.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E22B88419E4C0210026F95E /* CDVAvailabilityDeprecated.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8852C43A14B65FD800F0E735 /* CDVViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8852C43614B65FD800F0E735 /* CDVViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8852C43C14B65FD800F0E735 /* CDVViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8852C43714B65FD800F0E735 /* CDVViewController.m */; }; - 8887FD661090FBE7009987E8 /* CDVCamera.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD261090FBE7009987E8 /* CDVCamera.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8887FD671090FBE7009987E8 /* CDVCamera.m in Sources */ = {isa = PBXBuildFile; fileRef = 8887FD271090FBE7009987E8 /* CDVCamera.m */; }; 8887FD681090FBE7009987E8 /* NSDictionary+Extensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD281090FBE7009987E8 /* NSDictionary+Extensions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8887FD691090FBE7009987E8 /* NSDictionary+Extensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 8887FD291090FBE7009987E8 /* NSDictionary+Extensions.m */; }; - 8887FD6A1090FBE7009987E8 /* CDVContacts.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD2A1090FBE7009987E8 /* CDVContacts.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8887FD6B1090FBE7009987E8 /* CDVContacts.m in Sources */ = {isa = PBXBuildFile; fileRef = 8887FD2B1090FBE7009987E8 /* CDVContacts.m */; }; - 8887FD701090FBE7009987E8 /* CDVFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD301090FBE7009987E8 /* CDVFile.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8887FD711090FBE7009987E8 /* CDVFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 8887FD311090FBE7009987E8 /* CDVFile.m */; }; 8887FD741090FBE7009987E8 /* CDVInvokedUrlCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD341090FBE7009987E8 /* CDVInvokedUrlCommand.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8887FD751090FBE7009987E8 /* CDVInvokedUrlCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 8887FD351090FBE7009987E8 /* CDVInvokedUrlCommand.m */; }; - 8887FD851090FBE7009987E8 /* CDVLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD461090FBE7009987E8 /* CDVLocation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8887FD861090FBE7009987E8 /* CDVLocation.m in Sources */ = {isa = PBXBuildFile; fileRef = 8887FD471090FBE7009987E8 /* CDVLocation.m */; }; - 8887FD8D1090FBE7009987E8 /* CDVNotification.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD4E1090FBE7009987E8 /* CDVNotification.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8887FD8E1090FBE7009987E8 /* CDVNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = 8887FD4F1090FBE7009987E8 /* CDVNotification.m */; }; 8887FD8F1090FBE7009987E8 /* NSData+Base64.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD501090FBE7009987E8 /* NSData+Base64.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8887FD901090FBE7009987E8 /* NSData+Base64.m in Sources */ = {isa = PBXBuildFile; fileRef = 8887FD511090FBE7009987E8 /* NSData+Base64.m */; }; - 8887FD9D1090FBE7009987E8 /* CDVReachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD5E1090FBE7009987E8 /* CDVReachability.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8887FD9E1090FBE7009987E8 /* CDVReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 8887FD5F1090FBE7009987E8 /* CDVReachability.m */; }; - 8887FD9F1090FBE7009987E8 /* CDVSound.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD601090FBE7009987E8 /* CDVSound.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 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 */; 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 */; 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 */; 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 */; settings = {ATTRIBUTES = (Public, ); }; }; - EB80C2AD15DEA63D004D9E7B /* CDVEcho.m in Sources */ = {isa = PBXBuildFile; fileRef = EB80C2AB15DEA63D004D9E7B /* CDVEcho.m */; }; EB96673B16A8970A00D86CDF /* CDVUserAgentUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = EB96673916A8970900D86CDF /* CDVUserAgentUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; EB96673C16A8970A00D86CDF /* CDVUserAgentUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = EB96673A16A8970900D86CDF /* CDVUserAgentUtil.m */; }; EBA3557315ABD38C00F4DE24 /* NSArray+Comparisons.h in Headers */ = {isa = PBXBuildFile; fileRef = EBA3557115ABD38C00F4DE24 /* NSArray+Comparisons.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -94,12 +55,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 1F2BECBE13F9785B00A93BF6 /* CDVBattery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVBattery.h; path = Classes/CDVBattery.h; sourceTree = ""; }; - 1F2BECBF13F9785B00A93BF6 /* CDVBattery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVBattery.m; path = Classes/CDVBattery.m; sourceTree = ""; }; - 1F3C04CC12BC247D004F9E10 /* CDVContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVContact.h; path = Classes/CDVContact.h; sourceTree = ""; }; - 1F3C04CD12BC247D004F9E10 /* CDVContact.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVContact.m; path = Classes/CDVContact.m; sourceTree = ""; }; - 1F584B991385A28900ED25E8 /* CDVCapture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVCapture.h; path = Classes/CDVCapture.h; sourceTree = ""; }; - 1F584B9A1385A28900ED25E8 /* CDVCapture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVCapture.m; path = Classes/CDVCapture.m; sourceTree = ""; }; + 1B701026177A61CF00AE11F4 /* CDVShared.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVShared.h; path = Classes/CDVShared.h; sourceTree = ""; }; 1F92F49E1314023E0046367C /* CDVPluginResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVPluginResult.h; path = Classes/CDVPluginResult.h; sourceTree = ""; }; 1F92F49F1314023E0046367C /* CDVPluginResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVPluginResult.m; path = Classes/CDVPluginResult.m; sourceTree = ""; }; 301F2F2914F3C9CA003FE9FC /* CDV.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDV.h; path = Classes/CDV.h; sourceTree = ""; }; @@ -110,15 +66,7 @@ 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 = ""; }; - 30B39EBC13D0268B0009682A /* CDVSplashScreen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVSplashScreen.h; path = Classes/CDVSplashScreen.h; sourceTree = ""; }; - 30B39EBD13D0268B0009682A /* CDVSplashScreen.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVSplashScreen.m; path = Classes/CDVSplashScreen.m; sourceTree = ""; }; - 30C5F1DD15AF9E950052A00D /* CDVDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVDevice.h; path = Classes/CDVDevice.h; sourceTree = ""; }; - 30C5F1DE15AF9E950052A00D /* CDVDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVDevice.m; path = Classes/CDVDevice.m; sourceTree = ""; }; 30C6847E1406CB38004C1A8E /* CDVWhitelist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVWhitelist.h; path = Classes/CDVWhitelist.h; sourceTree = ""; }; 30C6847F1406CB38004C1A8E /* CDVWhitelist.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVWhitelist.m; path = Classes/CDVWhitelist.m; sourceTree = ""; }; 30C684921407044A004C1A8E /* CDVURLProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVURLProtocol.h; path = Classes/CDVURLProtocol.h; sourceTree = ""; }; @@ -130,8 +78,6 @@ 30F39309169F839700B22307 /* CDVJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVJSON.h; path = Classes/CDVJSON.h; sourceTree = ""; }; 30F3930A169F839700B22307 /* CDVJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVJSON.m; path = Classes/CDVJSON.m; sourceTree = ""; }; 30F5EBA914CA26E700987760 /* CDVCommandDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVCommandDelegate.h; path = Classes/CDVCommandDelegate.h; sourceTree = ""; }; - 3E76876B156A90EE00EB6FA3 /* CDVLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVLogger.m; path = Classes/CDVLogger.m; sourceTree = ""; }; - 3E76876C156A90EE00EB6FA3 /* CDVLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVLogger.h; path = Classes/CDVLogger.h; sourceTree = ""; }; 686357AA141002F100DF4CF2 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 686357AC141002F100DF4CF2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 686357AE141002F100DF4CF2 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; @@ -144,47 +90,23 @@ 686357DC14100B1600DF4CF2 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; 68A32D7114102E1C006B237C /* libCordova.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCordova.a; sourceTree = BUILT_PRODUCTS_DIR; }; 68A32D7414103017006B237C /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; }; - 68B7516A16FD18190076A8B4 /* CDVExif.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVExif.h; path = Classes/CDVExif.h; sourceTree = ""; }; - 68B7516B16FD18190076A8B4 /* CDVJpegHeaderWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVJpegHeaderWriter.h; path = Classes/CDVJpegHeaderWriter.h; sourceTree = ""; }; - 68B7516C16FD18190076A8B4 /* CDVJpegHeaderWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVJpegHeaderWriter.m; path = Classes/CDVJpegHeaderWriter.m; sourceTree = ""; }; 7E14B5A61705050A0032169E /* CDVTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVTimer.h; path = Classes/CDVTimer.h; sourceTree = ""; }; 7E14B5A71705050A0032169E /* CDVTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVTimer.m; path = Classes/CDVTimer.m; sourceTree = ""; }; + 7E22B88419E4C0210026F95E /* CDVAvailabilityDeprecated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVAvailabilityDeprecated.h; path = Classes/CDVAvailabilityDeprecated.h; sourceTree = ""; }; 8220B5C316D5427E00EC3921 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; }; 8852C43614B65FD800F0E735 /* CDVViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVViewController.h; path = Classes/CDVViewController.h; sourceTree = ""; }; 8852C43714B65FD800F0E735 /* CDVViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVViewController.m; path = Classes/CDVViewController.m; sourceTree = ""; }; - 8887FD261090FBE7009987E8 /* CDVCamera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVCamera.h; path = Classes/CDVCamera.h; sourceTree = ""; }; - 8887FD271090FBE7009987E8 /* CDVCamera.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVCamera.m; path = Classes/CDVCamera.m; sourceTree = ""; }; 8887FD281090FBE7009987E8 /* NSDictionary+Extensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+Extensions.h"; path = "Classes/NSDictionary+Extensions.h"; sourceTree = ""; }; 8887FD291090FBE7009987E8 /* NSDictionary+Extensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSDictionary+Extensions.m"; path = "Classes/NSDictionary+Extensions.m"; sourceTree = ""; }; - 8887FD2A1090FBE7009987E8 /* CDVContacts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVContacts.h; path = Classes/CDVContacts.h; sourceTree = ""; }; - 8887FD2B1090FBE7009987E8 /* CDVContacts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVContacts.m; path = Classes/CDVContacts.m; sourceTree = ""; }; - 8887FD301090FBE7009987E8 /* CDVFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVFile.h; path = Classes/CDVFile.h; sourceTree = ""; }; - 8887FD311090FBE7009987E8 /* CDVFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVFile.m; path = Classes/CDVFile.m; sourceTree = ""; }; 8887FD341090FBE7009987E8 /* CDVInvokedUrlCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVInvokedUrlCommand.h; path = Classes/CDVInvokedUrlCommand.h; sourceTree = ""; }; 8887FD351090FBE7009987E8 /* CDVInvokedUrlCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVInvokedUrlCommand.m; path = Classes/CDVInvokedUrlCommand.m; sourceTree = ""; }; - 8887FD461090FBE7009987E8 /* CDVLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVLocation.h; path = Classes/CDVLocation.h; sourceTree = ""; }; - 8887FD471090FBE7009987E8 /* CDVLocation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVLocation.m; path = Classes/CDVLocation.m; sourceTree = ""; }; - 8887FD4E1090FBE7009987E8 /* CDVNotification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVNotification.h; path = Classes/CDVNotification.h; sourceTree = ""; }; - 8887FD4F1090FBE7009987E8 /* CDVNotification.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVNotification.m; path = Classes/CDVNotification.m; sourceTree = ""; }; 8887FD501090FBE7009987E8 /* NSData+Base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSData+Base64.h"; path = "Classes/NSData+Base64.h"; sourceTree = ""; }; 8887FD511090FBE7009987E8 /* NSData+Base64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSData+Base64.m"; path = "Classes/NSData+Base64.m"; sourceTree = ""; }; - 8887FD5E1090FBE7009987E8 /* CDVReachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVReachability.h; path = Classes/CDVReachability.h; sourceTree = ""; }; - 8887FD5F1090FBE7009987E8 /* CDVReachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVReachability.m; path = Classes/CDVReachability.m; sourceTree = ""; }; - 8887FD601090FBE7009987E8 /* CDVSound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVSound.h; path = Classes/CDVSound.h; sourceTree = ""; }; - 8887FD611090FBE7009987E8 /* CDVSound.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVSound.m; path = Classes/CDVSound.m; sourceTree = ""; }; - 88BA573B109BB46F00FB5E78 /* CDVAccelerometer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVAccelerometer.h; path = Classes/CDVAccelerometer.h; sourceTree = ""; }; - 88BA573C109BB46F00FB5E78 /* CDVAccelerometer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVAccelerometer.m; path = Classes/CDVAccelerometer.m; sourceTree = ""; }; - 9D76CF3A1625A4C50008A0F6 /* CDVGlobalization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVGlobalization.h; path = Classes/CDVGlobalization.h; sourceTree = ""; }; - 9D76CF3B1625A4C50008A0F6 /* CDVGlobalization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVGlobalization.m; path = Classes/CDVGlobalization.m; sourceTree = ""; }; AA747D9E0F9514B9006C5449 /* CordovaLib_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CordovaLib_Prefix.pch; sourceTree = SOURCE_ROOT; }; - C937A4541337599E002C4C79 /* CDVFileTransfer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVFileTransfer.h; path = Classes/CDVFileTransfer.h; sourceTree = ""; }; - C937A4551337599E002C4C79 /* CDVFileTransfer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVFileTransfer.m; path = Classes/CDVFileTransfer.m; sourceTree = ""; }; EB3B3545161CB44D003DBE7D /* CDVCommandQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVCommandQueue.h; path = Classes/CDVCommandQueue.h; sourceTree = ""; }; EB3B3546161CB44D003DBE7D /* CDVCommandQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVCommandQueue.m; path = Classes/CDVCommandQueue.m; sourceTree = ""; }; EB3B357A161F2A44003DBE7D /* CDVCommandDelegateImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVCommandDelegateImpl.h; path = Classes/CDVCommandDelegateImpl.h; sourceTree = ""; }; EB3B357B161F2A45003DBE7D /* CDVCommandDelegateImpl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVCommandDelegateImpl.m; path = Classes/CDVCommandDelegateImpl.m; sourceTree = ""; }; - EB80C2AA15DEA63D004D9E7B /* CDVEcho.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVEcho.h; path = Classes/CDVEcho.h; sourceTree = ""; }; - EB80C2AB15DEA63D004D9E7B /* CDVEcho.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVEcho.m; path = Classes/CDVEcho.m; sourceTree = ""; }; EB96673916A8970900D86CDF /* CDVUserAgentUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVUserAgentUtil.h; path = Classes/CDVUserAgentUtil.h; sourceTree = ""; }; EB96673A16A8970900D86CDF /* CDVUserAgentUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVUserAgentUtil.m; path = Classes/CDVUserAgentUtil.m; sourceTree = ""; }; EBA3557115ABD38C00F4DE24 /* NSArray+Comparisons.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSArray+Comparisons.h"; path = "Classes/NSArray+Comparisons.h"; sourceTree = ""; }; @@ -269,10 +191,9 @@ 888700D710922F56009987E8 /* Commands */ = { isa = PBXGroup; children = ( + 7E22B88419E4C0210026F95E /* CDVAvailabilityDeprecated.h */, EBFF4DBA16D3FE2E008F452B /* CDVWebViewDelegate.m */, EBFF4DBB16D3FE2E008F452B /* CDVWebViewDelegate.h */, - 30C5F1DD15AF9E950052A00D /* CDVDevice.h */, - 30C5F1DE15AF9E950052A00D /* CDVDevice.m */, 301F2F2914F3C9CA003FE9FC /* CDV.h */, 3034979A1513D56A0090E688 /* CDVLocalStorage.h */, 3034979B1513D56A0090E688 /* CDVLocalStorage.m */, @@ -283,52 +204,14 @@ 30C684921407044A004C1A8E /* CDVURLProtocol.h */, 30C684931407044A004C1A8E /* CDVURLProtocol.m */, 30C6847E1406CB38004C1A8E /* CDVWhitelist.h */, + 1B701026177A61CF00AE11F4 /* CDVShared.h */, 30C6847F1406CB38004C1A8E /* CDVWhitelist.m */, - 1F2BECBE13F9785B00A93BF6 /* CDVBattery.h */, - 1F2BECBF13F9785B00A93BF6 /* CDVBattery.m */, - 30B39EBC13D0268B0009682A /* CDVSplashScreen.h */, - 30B39EBD13D0268B0009682A /* CDVSplashScreen.m */, 30E33AF013A7E24B00594D64 /* CDVPlugin.h */, 30E33AF113A7E24B00594D64 /* CDVPlugin.m */, - 307A8F9C1385A2EC00E43782 /* CDVConnection.h */, - 307A8F9D1385A2EC00E43782 /* CDVConnection.m */, 1F92F49E1314023E0046367C /* CDVPluginResult.h */, 1F92F49F1314023E0046367C /* CDVPluginResult.m */, - 88BA573B109BB46F00FB5E78 /* CDVAccelerometer.h */, - 88BA573C109BB46F00FB5E78 /* CDVAccelerometer.m */, - 8887FD261090FBE7009987E8 /* CDVCamera.h */, - 8887FD271090FBE7009987E8 /* CDVCamera.m */, - 1F584B991385A28900ED25E8 /* CDVCapture.h */, - 1F584B9A1385A28900ED25E8 /* CDVCapture.m */, - 68B7516A16FD18190076A8B4 /* CDVExif.h */, - 68B7516B16FD18190076A8B4 /* CDVJpegHeaderWriter.h */, - 68B7516C16FD18190076A8B4 /* CDVJpegHeaderWriter.m */, - 1F3C04CC12BC247D004F9E10 /* CDVContact.h */, - 1F3C04CD12BC247D004F9E10 /* CDVContact.m */, - 8887FD2A1090FBE7009987E8 /* CDVContacts.h */, - 8887FD2B1090FBE7009987E8 /* CDVContacts.m */, - EB80C2AA15DEA63D004D9E7B /* CDVEcho.h */, - EB80C2AB15DEA63D004D9E7B /* CDVEcho.m */, - 8887FD301090FBE7009987E8 /* CDVFile.h */, - 8887FD311090FBE7009987E8 /* CDVFile.m */, 8887FD341090FBE7009987E8 /* CDVInvokedUrlCommand.h */, 8887FD351090FBE7009987E8 /* CDVInvokedUrlCommand.m */, - C937A4541337599E002C4C79 /* CDVFileTransfer.h */, - C937A4551337599E002C4C79 /* CDVFileTransfer.m */, - 8887FD461090FBE7009987E8 /* CDVLocation.h */, - 8887FD471090FBE7009987E8 /* CDVLocation.m */, - 8887FD4E1090FBE7009987E8 /* CDVNotification.h */, - 8887FD4F1090FBE7009987E8 /* CDVNotification.m */, - 8887FD5E1090FBE7009987E8 /* CDVReachability.h */, - 8887FD5F1090FBE7009987E8 /* CDVReachability.m */, - 8887FD601090FBE7009987E8 /* CDVSound.h */, - 8887FD611090FBE7009987E8 /* CDVSound.m */, - 3E76876B156A90EE00EB6FA3 /* CDVLogger.m */, - 3E76876C156A90EE00EB6FA3 /* CDVLogger.h */, - 9D76CF3A1625A4C50008A0F6 /* CDVGlobalization.h */, - 9D76CF3B1625A4C50008A0F6 /* CDVGlobalization.m */, - 3073E9E71656D37700957977 /* CDVInAppBrowser.h */, - 3073E9E81656D37700957977 /* CDVInAppBrowser.m */, 3073E9EC1656D51200957977 /* CDVScreenOrientationDelegate.h */, 30F39309169F839700B22307 /* CDVJSON.h */, 30F3930A169F839700B22307 /* CDVJSON.m */, @@ -375,45 +258,26 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 68B7517016FD19F80076A8B4 /* CDVExif.h in Headers */, - 68B7516E16FD18190076A8B4 /* CDVJpegHeaderWriter.h in Headers */, - 8887FD661090FBE7009987E8 /* CDVCamera.h in Headers */, 8887FD681090FBE7009987E8 /* NSDictionary+Extensions.h in Headers */, - 8887FD6A1090FBE7009987E8 /* CDVContacts.h in Headers */, - 8887FD701090FBE7009987E8 /* CDVFile.h in Headers */, 8887FD741090FBE7009987E8 /* CDVInvokedUrlCommand.h in Headers */, - 8887FD851090FBE7009987E8 /* CDVLocation.h in Headers */, - 8887FD8D1090FBE7009987E8 /* CDVNotification.h in Headers */, 8887FD8F1090FBE7009987E8 /* NSData+Base64.h in Headers */, - 8887FD9D1090FBE7009987E8 /* CDVReachability.h in Headers */, - 8887FD9F1090FBE7009987E8 /* CDVSound.h in Headers */, - 88BA573D109BB46F00FB5E78 /* CDVAccelerometer.h in Headers */, - 1F3C04CE12BC247D004F9E10 /* CDVContact.h in Headers */, 1F92F4A01314023E0046367C /* CDVPluginResult.h in Headers */, - C937A4561337599E002C4C79 /* CDVFileTransfer.h in Headers */, - 307A8F9E1385A2EC00E43782 /* CDVConnection.h in Headers */, - 1F584B9B1385A28A00ED25E8 /* CDVCapture.h in Headers */, 30E33AF213A7E24B00594D64 /* CDVPlugin.h in Headers */, 302965BC13A94E9D007046C5 /* CDVDebug.h in Headers */, - 30B39EBE13D0268B0009682A /* CDVSplashScreen.h in Headers */, 30E563CF13E217EC00C949AA /* NSMutableArray+QueueAdditions.h in Headers */, - 1F2BECC013F9785B00A93BF6 /* CDVBattery.h in Headers */, 30C684801406CB38004C1A8E /* CDVWhitelist.h in Headers */, 30C684941407044B004C1A8E /* CDVURLProtocol.h in Headers */, 8852C43A14B65FD800F0E735 /* CDVViewController.h in Headers */, 30F5EBAB14CA26E700987760 /* CDVCommandDelegate.h in Headers */, 301F2F2A14F3C9CA003FE9FC /* CDV.h in Headers */, 30392E4E14F4FCAB00B9E0B8 /* CDVAvailability.h in Headers */, + 7E22B88519E4C0210026F95E /* CDVAvailabilityDeprecated.h in Headers */, 3034979C1513D56A0090E688 /* CDVLocalStorage.h in Headers */, 3062D120151D0EDB000D9128 /* UIDevice+Extensions.h in Headers */, - 3E76876F156A90EE00EB6FA3 /* CDVLogger.h in Headers */, EBA3557315ABD38C00F4DE24 /* NSArray+Comparisons.h in Headers */, - 30C5F1DF15AF9E950052A00D /* CDVDevice.h in Headers */, - EB80C2AC15DEA63D004D9E7B /* CDVEcho.h in Headers */, EB3B3547161CB44D003DBE7D /* CDVCommandQueue.h in Headers */, EB3B357C161F2A45003DBE7D /* CDVCommandDelegateImpl.h in Headers */, - 9D76CF3C1625A4C50008A0F6 /* CDVGlobalization.h in Headers */, - 3073E9E91656D37700957977 /* CDVInAppBrowser.h in Headers */, + 1B701028177A61CF00AE11F4 /* CDVShared.h in Headers */, 3073E9ED1656D51200957977 /* CDVScreenOrientationDelegate.h in Headers */, F858FBC6166009A8007DA594 /* CDVConfigParser.h in Headers */, 30F3930B169F839700B22307 /* CDVJSON.h in Headers */, @@ -449,7 +313,7 @@ 0867D690FE84028FC02AAC07 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0460; + LastUpgradeCheck = 0510; }; buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "CordovaLib" */; compatibilityVersion = "Xcode 3.2"; @@ -477,44 +341,24 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8887FD671090FBE7009987E8 /* CDVCamera.m in Sources */, 8887FD691090FBE7009987E8 /* NSDictionary+Extensions.m in Sources */, - 8887FD6B1090FBE7009987E8 /* CDVContacts.m in Sources */, - 8887FD711090FBE7009987E8 /* CDVFile.m in Sources */, 8887FD751090FBE7009987E8 /* CDVInvokedUrlCommand.m in Sources */, - 8887FD861090FBE7009987E8 /* CDVLocation.m in Sources */, - 8887FD8E1090FBE7009987E8 /* CDVNotification.m in Sources */, 8887FD901090FBE7009987E8 /* NSData+Base64.m in Sources */, - 8887FD9E1090FBE7009987E8 /* CDVReachability.m in Sources */, - 8887FDA01090FBE7009987E8 /* CDVSound.m in Sources */, - 88BA573E109BB46F00FB5E78 /* CDVAccelerometer.m in Sources */, - 1F3C04CF12BC247D004F9E10 /* CDVContact.m in Sources */, 1F92F4A11314023E0046367C /* CDVPluginResult.m in Sources */, - C937A4571337599E002C4C79 /* CDVFileTransfer.m in Sources */, - 307A8F9F1385A2EC00E43782 /* CDVConnection.m in Sources */, - 1F584B9C1385A28A00ED25E8 /* CDVCapture.m in Sources */, 30E33AF313A7E24B00594D64 /* CDVPlugin.m in Sources */, - 30B39EBF13D0268B0009682A /* CDVSplashScreen.m in Sources */, 30E563D013E217EC00C949AA /* NSMutableArray+QueueAdditions.m in Sources */, - 1F2BECC113F9785B00A93BF6 /* CDVBattery.m in Sources */, 30C684821406CB38004C1A8E /* CDVWhitelist.m in Sources */, 30C684961407044B004C1A8E /* CDVURLProtocol.m in Sources */, 8852C43C14B65FD800F0E735 /* CDVViewController.m in Sources */, 3034979E1513D56A0090E688 /* CDVLocalStorage.m in Sources */, 3062D122151D0EDB000D9128 /* UIDevice+Extensions.m in Sources */, - 3E76876D156A90EE00EB6FA3 /* CDVLogger.m in Sources */, EBA3557515ABD38C00F4DE24 /* NSArray+Comparisons.m in Sources */, - 30C5F1E015AF9E950052A00D /* CDVDevice.m in Sources */, - EB80C2AD15DEA63D004D9E7B /* CDVEcho.m in Sources */, 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 */, 30F3930C169F839700B22307 /* CDVJSON.m in Sources */, EB96673C16A8970A00D86CDF /* CDVUserAgentUtil.m in Sources */, EBFF4DBC16D3FE2E008F452B /* CDVWebViewDelegate.m in Sources */, - 68B7516F16FD18190076A8B4 /* CDVJpegHeaderWriter.m in Sources */, 7E14B5A91705050A0032169E /* CDVTimer.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -526,12 +370,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - "ARCHS[sdk=iphoneos*]" = armv7; - "ARCHS[sdk=iphoneos6.*]" = ( - armv7, - armv7s, - ); - "ARCHS[sdk=iphonesimulator*]" = i386; CLANG_ENABLE_OBJC_ARC = YES; COPY_PHASE_STRIP = NO; DSTROOT = "/tmp/$(PROJECT_NAME).dst"; @@ -542,9 +380,9 @@ GCC_PREFIX_HEADER = CordovaLib_Prefix.pch; GCC_PREPROCESSOR_DEFINITIONS = ""; GCC_THUMB_SUPPORT = NO; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_VERSION = ""; INSTALL_PATH = /usr/local/lib; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; PRODUCT_NAME = Cordova; PUBLIC_HEADERS_FOLDER_PATH = include/Cordova; SKIP_INSTALL = YES; @@ -555,12 +393,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - "ARCHS[sdk=iphoneos*]" = armv7; - "ARCHS[sdk=iphoneos6.*]" = ( - armv7, - armv7s, - ); - "ARCHS[sdk=iphonesimulator*]" = i386; CLANG_ENABLE_OBJC_ARC = YES; DSTROOT = "/tmp/$(PROJECT_NAME).dst"; GCC_MODEL_TUNING = G5; @@ -568,9 +400,9 @@ GCC_PREFIX_HEADER = CordovaLib_Prefix.pch; GCC_PREPROCESSOR_DEFINITIONS = ""; GCC_THUMB_SUPPORT = NO; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_VERSION = ""; INSTALL_PATH = /usr/local/lib; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; PRODUCT_NAME = Cordova; PUBLIC_HEADERS_FOLDER_PATH = include/Cordova; SKIP_INSTALL = YES; @@ -580,13 +412,9 @@ 1DEB922308733DC00010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - "ARCHS[sdk=iphoneos*]" = armv7; - "ARCHS[sdk=iphoneos6.*]" = ( - armv7, - armv7s, - ); - "ARCHS[sdk=iphonesimulator*]" = i386; + CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -594,49 +422,47 @@ GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ""; GCC_THUMB_SUPPORT = NO; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_VERSION = ""; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.3; - ONLY_ACTIVE_ARCH = NO; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "-DDEBUG"; PUBLIC_HEADERS_FOLDER_PATH = include/Cordova; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; USER_HEADER_SEARCH_PATHS = ""; - VALID_ARCHS = "i386 armv7 armv7s"; }; name = Debug; }; 1DEB922408733DC00010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - "ARCHS[sdk=iphoneos*]" = armv7; - "ARCHS[sdk=iphoneos6.*]" = ( - armv7, - armv7s, - ); - "ARCHS[sdk=iphonesimulator*]" = i386; + CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = 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_VERSION = ""; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.3; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; ONLY_ACTIVE_ARCH = NO; PUBLIC_HEADERS_FOLDER_PATH = include/Cordova; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; - VALID_ARCHS = "i386 armv7 armv7s"; }; name = Release; }; diff --git a/CordovaLib/CordovaLib_Prefix.pch b/platforms/ios/CordovaLib/CordovaLib_Prefix.pch old mode 100755 new mode 100644 similarity index 100% rename from CordovaLib/CordovaLib_Prefix.pch rename to platforms/ios/CordovaLib/CordovaLib_Prefix.pch diff --git a/platforms/ios/CordovaLib/VERSION b/platforms/ios/CordovaLib/VERSION new file mode 100644 index 0000000..7c69a55 --- /dev/null +++ b/platforms/ios/CordovaLib/VERSION @@ -0,0 +1 @@ +3.7.0 diff --git a/platforms/ios/CordovaLib/cordova.js b/platforms/ios/CordovaLib/cordova.js new file mode 100644 index 0000000..84b7642 --- /dev/null +++ b/platforms/ios/CordovaLib/cordova.js @@ -0,0 +1,1805 @@ +// Platform: ios +// 91157c2e1bf3eb098c7e2ab31404e895ccb0df2a +/* + 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. +*/ +;(function() { +var PLATFORM_VERSION_BUILD_LABEL = '3.7.0'; +// file: src/scripts/require.js + +/*jshint -W079 */ +/*jshint -W020 */ + +var require, + define; + +(function () { + var modules = {}, + // Stack of moduleIds currently being built. + requireStack = [], + // Map of module ID -> index into requireStack of modules currently being built. + inProgressModules = {}, + SEPARATOR = "."; + + + + function build(module) { + var factory = module.factory, + localRequire = function (id) { + var resultantId = id; + //Its a relative path, so lop off the last portion and add the id (minus "./") + if (id.charAt(0) === ".") { + resultantId = module.id.slice(0, module.id.lastIndexOf(SEPARATOR)) + SEPARATOR + id.slice(2); + } + return require(resultantId); + }; + module.exports = {}; + delete module.factory; + factory(localRequire, module.exports, module); + return module.exports; + } + + require = function (id) { + if (!modules[id]) { + throw "module " + id + " not found"; + } else if (id in inProgressModules) { + var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id; + throw "Cycle in require graph: " + cycle; + } + if (modules[id].factory) { + try { + inProgressModules[id] = requireStack.length; + requireStack.push(id); + return build(modules[id]); + } finally { + delete inProgressModules[id]; + requireStack.pop(); + } + } + return modules[id].exports; + }; + + define = function (id, factory) { + if (modules[id]) { + throw "module " + id + " already defined"; + } + + modules[id] = { + id: id, + factory: factory + }; + }; + + define.remove = function (id) { + delete modules[id]; + }; + + define.moduleMap = modules; +})(); + +//Export for use in node +if (typeof module === "object" && typeof require === "function") { + module.exports.require = require; + module.exports.define = define; +} + +// file: src/cordova.js +define("cordova", function(require, exports, module) { + + +var channel = require('cordova/channel'); +var platform = require('cordova/platform'); + +/** + * Intercept calls to addEventListener + removeEventListener and handle deviceready, + * resume, and pause events. + */ +var m_document_addEventListener = document.addEventListener; +var m_document_removeEventListener = document.removeEventListener; +var m_window_addEventListener = window.addEventListener; +var m_window_removeEventListener = window.removeEventListener; + +/** + * Houses custom event handlers to intercept on document + window event listeners. + */ +var documentEventHandlers = {}, + windowEventHandlers = {}; + +document.addEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + if (typeof documentEventHandlers[e] != 'undefined') { + documentEventHandlers[e].subscribe(handler); + } else { + m_document_addEventListener.call(document, evt, handler, capture); + } +}; + +window.addEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + if (typeof windowEventHandlers[e] != 'undefined') { + windowEventHandlers[e].subscribe(handler); + } else { + m_window_addEventListener.call(window, evt, handler, capture); + } +}; + +document.removeEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + // If unsubscribing from an event that is handled by a plugin + if (typeof documentEventHandlers[e] != "undefined") { + documentEventHandlers[e].unsubscribe(handler); + } else { + m_document_removeEventListener.call(document, evt, handler, capture); + } +}; + +window.removeEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + // If unsubscribing from an event that is handled by a plugin + if (typeof windowEventHandlers[e] != "undefined") { + windowEventHandlers[e].unsubscribe(handler); + } else { + m_window_removeEventListener.call(window, evt, handler, capture); + } +}; + +function createEvent(type, data) { + var event = document.createEvent('Events'); + event.initEvent(type, false, false); + if (data) { + for (var i in data) { + if (data.hasOwnProperty(i)) { + event[i] = data[i]; + } + } + } + return event; +} + + +var cordova = { + define:define, + require:require, + version:PLATFORM_VERSION_BUILD_LABEL, + platformVersion:PLATFORM_VERSION_BUILD_LABEL, + platformId:platform.id, + /** + * Methods to add/remove your own addEventListener hijacking on document + window. + */ + addWindowEventHandler:function(event) { + return (windowEventHandlers[event] = channel.create(event)); + }, + addStickyDocumentEventHandler:function(event) { + return (documentEventHandlers[event] = channel.createSticky(event)); + }, + addDocumentEventHandler:function(event) { + return (documentEventHandlers[event] = channel.create(event)); + }, + removeWindowEventHandler:function(event) { + delete windowEventHandlers[event]; + }, + removeDocumentEventHandler:function(event) { + delete documentEventHandlers[event]; + }, + /** + * Retrieve original event handlers that were replaced by Cordova + * + * @return object + */ + getOriginalHandlers: function() { + return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener}, + 'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}}; + }, + /** + * Method to fire event from native code + * bNoDetach is required for events which cause an exception which needs to be caught in native code + */ + fireDocumentEvent: function(type, data, bNoDetach) { + var evt = createEvent(type, data); + if (typeof documentEventHandlers[type] != 'undefined') { + if( bNoDetach ) { + documentEventHandlers[type].fire(evt); + } + else { + setTimeout(function() { + // Fire deviceready on listeners that were registered before cordova.js was loaded. + if (type == 'deviceready') { + document.dispatchEvent(evt); + } + documentEventHandlers[type].fire(evt); + }, 0); + } + } else { + document.dispatchEvent(evt); + } + }, + fireWindowEvent: function(type, data) { + var evt = createEvent(type,data); + if (typeof windowEventHandlers[type] != 'undefined') { + setTimeout(function() { + windowEventHandlers[type].fire(evt); + }, 0); + } else { + window.dispatchEvent(evt); + } + }, + + /** + * Plugin callback mechanism. + */ + // Randomize the starting callbackId to avoid collisions after refreshing or navigating. + // This way, it's very unlikely that any new callback would get the same callbackId as an old callback. + callbackId: Math.floor(Math.random() * 2000000000), + callbacks: {}, + callbackStatus: { + NO_RESULT: 0, + OK: 1, + CLASS_NOT_FOUND_EXCEPTION: 2, + ILLEGAL_ACCESS_EXCEPTION: 3, + INSTANTIATION_EXCEPTION: 4, + MALFORMED_URL_EXCEPTION: 5, + IO_EXCEPTION: 6, + INVALID_ACTION: 7, + JSON_EXCEPTION: 8, + ERROR: 9 + }, + + /** + * Called by native code when returning successful result from an action. + */ + callbackSuccess: function(callbackId, args) { + cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback); + }, + + /** + * Called by native code when returning error result from an action. + */ + callbackError: function(callbackId, args) { + // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative. + // Derive success from status. + cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback); + }, + + /** + * Called by native code when returning the result from an action. + */ + callbackFromNative: function(callbackId, isSuccess, status, args, keepCallback) { + try { + var callback = cordova.callbacks[callbackId]; + if (callback) { + if (isSuccess && status == cordova.callbackStatus.OK) { + callback.success && callback.success.apply(null, args); + } else { + callback.fail && callback.fail.apply(null, args); + } + + // Clear callback if not expecting any more results + if (!keepCallback) { + delete cordova.callbacks[callbackId]; + } + } + } + catch (err) { + var msg = "Error in " + (isSuccess ? "Success" : "Error") + " callbackId: " + callbackId + " : " + err; + console && console.log && console.log(msg); + cordova.fireWindowEvent("cordovacallbackerror", { 'message': msg }); + throw err; + } + }, + addConstructor: function(func) { + channel.onCordovaReady.subscribe(function() { + try { + func(); + } catch(e) { + console.log("Failed to run constructor: " + e); + } + }); + } +}; + + +module.exports = cordova; + +}); + +// file: src/common/argscheck.js +define("cordova/argscheck", function(require, exports, module) { + +var exec = require('cordova/exec'); +var utils = require('cordova/utils'); + +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 typeName; + 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; + } + typeName = utils.typeName(arg); + if ((arg === null || arg === undefined) && c == cUpper) { + continue; + } + if (typeName != typeMap[cUpper]) { + errMsg = 'Expected ' + typeMap[cUpper]; + break; + } + } + if (errMsg) { + errMsg += ', but got ' + typeName + '.'; + errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg; + // Don't log when running unit tests. + if (typeof jasmine == 'undefined') { + console.error(errMsg); + } + throw TypeError(errMsg); + } +} + +function getValue(value, defaultValue) { + return value === undefined ? defaultValue : value; +} + +moduleExports.checkArgs = checkArgs; +moduleExports.getValue = getValue; +moduleExports.enableChecks = true; + + +}); + +// file: src/common/base64.js +define("cordova/base64", function(require, exports, module) { + +var base64 = exports; + +base64.fromArrayBuffer = function(arrayBuffer) { + var array = new Uint8Array(arrayBuffer); + return uint8ToBase64(array); +}; + +base64.toArrayBuffer = function(str) { + var decodedStr = typeof atob != 'undefined' ? atob(str) : new Buffer(str,'base64').toString('binary'); + var arrayBuffer = new ArrayBuffer(decodedStr.length); + var array = new Uint8Array(arrayBuffer); + for (var i=0, len=decodedStr.length; i < len; i++) { + array[i] = decodedStr.charCodeAt(i); + } + return arrayBuffer; +}; + +//------------------------------------------------------------------------------ + +/* This code is based on the performance tests at http://jsperf.com/b64tests + * This 12-bit-at-a-time algorithm was the best performing version on all + * platforms tested. + */ + +var b64_6bit = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +var b64_12bit; + +var b64_12bitTable = function() { + b64_12bit = []; + for (var i=0; i<64; i++) { + for (var j=0; j<64; j++) { + b64_12bit[i*64+j] = b64_6bit[i] + b64_6bit[j]; + } + } + b64_12bitTable = function() { return b64_12bit; }; + return b64_12bit; +}; + +function uint8ToBase64(rawData) { + var numBytes = rawData.byteLength; + var output=""; + var segment; + var table = b64_12bitTable(); + for (var i=0;i> 12]; + output += table[segment & 0xfff]; + } + if (numBytes - i == 2) { + segment = (rawData[i] << 16) + (rawData[i+1] << 8); + output += table[segment >> 12]; + output += b64_6bit[(segment & 0xfff) >> 6]; + output += '='; + } else if (numBytes - i == 1) { + segment = (rawData[i] << 16); + output += table[segment >> 12]; + output += '=='; + } + return output; +} + +}); + +// file: src/common/builder.js +define("cordova/builder", function(require, exports, module) { + +var utils = require('cordova/utils'); + +function each(objects, func, context) { + for (var prop in objects) { + if (objects.hasOwnProperty(prop)) { + func.apply(context, [objects[prop], prop]); + } + } +} + +function clobber(obj, key, value) { + exports.replaceHookForTesting(obj, key); + 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() { + console.log(message); + delete obj[key]; + clobber(obj, key, value); + return value; + }); + } else { + clobber(obj, key, value); + } +} + +function include(parent, objects, clobber, merge) { + each(objects, function (obj, key) { + try { + var result = obj.path ? require(obj.path) : {}; + + if (clobber) { + // Clobber if it doesn't exist. + if (typeof parent[key] === 'undefined') { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } else if (typeof obj.path !== 'undefined') { + // If merging, merge properties onto parent, otherwise, clobber. + if (merge) { + recursiveMerge(parent[key], result); + } else { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } + } + result = parent[key]; + } else { + // Overwrite if not currently defined. + if (typeof parent[key] == 'undefined') { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } else { + // Set result to what already exists, so we can build children into it if they exist. + result = parent[key]; + } + } + + if (obj.children) { + include(result, obj.children, clobber, merge); + } + } catch(e) { + utils.alert('Exception building Cordova JS globals: ' + e + ' for key "' + key + '"'); + } + }); +} + +/** + * Merge properties from one object onto another recursively. Properties from + * the src object will overwrite existing target property. + * + * @param target Object to merge properties into. + * @param src Object to merge properties from. + */ +function recursiveMerge(target, src) { + for (var prop in src) { + if (src.hasOwnProperty(prop)) { + if (target.prototype && target.prototype.constructor === target) { + // If the target object is a constructor override off prototype. + clobber(target.prototype, prop, src[prop]); + } else { + if (typeof src[prop] === 'object' && typeof target[prop] === 'object') { + recursiveMerge(target[prop], src[prop]); + } else { + clobber(target, prop, src[prop]); + } + } + } + } +} + +exports.buildIntoButDoNotClobber = function(objects, target) { + include(target, objects, false, false); +}; +exports.buildIntoAndClobber = function(objects, target) { + include(target, objects, true, false); +}; +exports.buildIntoAndMerge = function(objects, target) { + include(target, objects, true, true); +}; +exports.recursiveMerge = recursiveMerge; +exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter; +exports.replaceHookForTesting = function() {}; + +}); + +// file: src/common/channel.js +define("cordova/channel", function(require, exports, module) { + +var utils = require('cordova/utils'), + nextGuid = 1; + +/** + * Custom pub-sub "channel" that can have functions subscribed to it + * This object is used to define and control firing of events for + * cordova initialization, as well as for custom events thereafter. + * + * The order of events during page load and Cordova startup is as follows: + * + * onDOMContentLoaded* Internal event that is received when the web page is loaded and parsed. + * onNativeReady* Internal event that indicates the Cordova native side is ready. + * onCordovaReady* Internal event fired when all Cordova JavaScript objects have been created. + * onDeviceReady* User event fired to indicate that Cordova is ready + * onResume User event fired to indicate a start/resume lifecycle event + * onPause User event fired to indicate a pause lifecycle event + * onDestroy* Internal event fired when app is being destroyed (User should use window.onunload event, not this one). + * + * The events marked with an * are sticky. Once they have fired, they will stay in the fired state. + * All listeners that subscribe after the event is fired will be executed right away. + * + * The only Cordova events that user code should register for are: + * deviceready Cordova native code is initialized and Cordova APIs can be called from JavaScript + * pause App has moved to background + * resume App has returned to foreground + * + * Listeners can be registered as: + * document.addEventListener("deviceready", myDeviceReadyListener, false); + * document.addEventListener("resume", myResumeListener, false); + * document.addEventListener("pause", myPauseListener, false); + * + * The DOM lifecycle events should be used for saving and restoring state + * window.onload + * window.onunload + * + */ + +/** + * Channel + * @constructor + * @param type String the channel name + */ +var Channel = function(type, sticky) { + this.type = type; + // Map of guid -> function. + this.handlers = {}; + // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired. + this.state = sticky ? 1 : 0; + // Used in sticky mode to remember args passed to fire(). + this.fireArgs = null; + // Used by onHasSubscribersChange to know if there are any listeners. + this.numHandlers = 0; + // Function that is called when the first listener is subscribed, or when + // the last listener is unsubscribed. + this.onHasSubscribersChange = null; +}, + channel = { + /** + * Calls the provided function only after all of the channels specified + * have been fired. All channels must be sticky channels. + */ + join: function(h, c) { + var len = c.length, + i = len, + f = function() { + if (!(--i)) h(); + }; + for (var j=0; jNative messages. + isInContextOfEvalJs = 0; + +function createExecIframe(src, unloadListener) { + var iframe = document.createElement("iframe"); + iframe.style.display = 'none'; + // Both the unload listener and the src must be set before adding the iframe + // to the document in order to avoid race conditions. Callbacks from native + // can happen within the appendChild() call! + iframe.onunload = unloadListener; + iframe.src = src; + document.body.appendChild(iframe); + return iframe; +} + +function createHashIframe() { + var ret = createExecIframe('about:blank'); + // Hash changes don't work on about:blank, so switch it to file:///. + ret.contentWindow.history.replaceState(null, null, 'file:///#'); + return ret; +} + +function shouldBundleCommandJson() { + if (bridgeMode === jsToNativeModes.XHR_WITH_PAYLOAD) { + return true; + } + if (bridgeMode === jsToNativeModes.XHR_OPTIONAL_PAYLOAD) { + var payloadLength = 0; + for (var i = 0; i < commandQueue.length; ++i) { + payloadLength += commandQueue[i].length; + } + // The value here was determined using the benchmark within CordovaLibApp on an iPad 3. + return payloadLength < 4500; + } + return false; +} + +function massageArgsJsToNative(args) { + if (!args || utils.typeName(args) != 'Array') { + return args; + } + var ret = []; + args.forEach(function(arg, i) { + if (utils.typeName(arg) == 'ArrayBuffer') { + ret.push({ + 'CDVType': 'ArrayBuffer', + 'data': base64.fromArrayBuffer(arg) + }); + } else { + ret.push(arg); + } + }); + return ret; +} + +function massageMessageNativeToJs(message) { + if (message.CDVType == 'ArrayBuffer') { + var stringToArrayBuffer = function(str) { + var ret = new Uint8Array(str.length); + for (var i = 0; i < str.length; i++) { + ret[i] = str.charCodeAt(i); + } + return ret.buffer; + }; + var base64ToArrayBuffer = function(b64) { + return stringToArrayBuffer(atob(b64)); + }; + message = base64ToArrayBuffer(message.data); + } + return message; +} + +function convertMessageToArgsNativeToJs(message) { + var args = []; + if (!message || !message.hasOwnProperty('CDVType')) { + args.push(message); + } else if (message.CDVType == 'MultiPart') { + message.messages.forEach(function(e) { + args.push(massageMessageNativeToJs(e)); + }); + } else { + args.push(massageMessageNativeToJs(message)); + } + return args; +} + +function iOSExec() { + if (bridgeMode === undefined) { + bridgeMode = jsToNativeModes.IFRAME_NAV; + } + + if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.cordova && window.webkit.messageHandlers.cordova.postMessage) { + bridgeMode = jsToNativeModes.WK_WEBVIEW_BINDING; + } + + var successCallback, failCallback, service, action, actionArgs, splitCommand; + var callbackId = null; + if (typeof arguments[0] !== "string") { + // FORMAT ONE + successCallback = arguments[0]; + failCallback = arguments[1]; + service = arguments[2]; + action = arguments[3]; + actionArgs = arguments[4]; + + // Since we need to maintain backwards compatibility, we have to pass + // an invalid callbackId even if no callback was provided since plugins + // will be expecting it. The Cordova.exec() implementation allocates + // an invalid callbackId and passes it even if no callbacks were given. + callbackId = 'INVALID'; + } else { + // FORMAT TWO, REMOVED + try { + splitCommand = arguments[0].split("."); + action = splitCommand.pop(); + service = splitCommand.join("."); + actionArgs = Array.prototype.splice.call(arguments, 1); + + console.log('The old format of this exec call has been removed (deprecated since 2.1). Change to: ' + + "cordova.exec(null, null, \"" + service + "\", \"" + action + "\"," + JSON.stringify(actionArgs) + ");" + ); + return; + } catch (e) {} + } + + // If actionArgs is not provided, default to an empty array + actionArgs = actionArgs || []; + + // Register the callbacks and add the callbackId to the positional + // arguments if given. + if (successCallback || failCallback) { + callbackId = service + cordova.callbackId++; + cordova.callbacks[callbackId] = + {success:successCallback, fail:failCallback}; + } + + actionArgs = massageArgsJsToNative(actionArgs); + + var command = [callbackId, service, action, actionArgs]; + + // Stringify and queue the command. We stringify to command now to + // effectively clone the command arguments in case they are mutated before + // the command is executed. + commandQueue.push(JSON.stringify(command)); + + if (bridgeMode === jsToNativeModes.WK_WEBVIEW_BINDING) { + window.webkit.messageHandlers.cordova.postMessage(command); + } else { + // 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) { + switch (bridgeMode) { + case jsToNativeModes.XHR_NO_PAYLOAD: + case jsToNativeModes.XHR_WITH_PAYLOAD: + case jsToNativeModes.XHR_OPTIONAL_PAYLOAD: + pokeNativeViaXhr(); + break; + default: // iframe-based. + pokeNativeViaIframe(); + } + } + } +} + +function pokeNativeViaXhr() { + // 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... + // Add a timestamp to the query param to prevent caching. + execXhr.open('HEAD', "/!gap_exec?" + (+new Date()), true); + if (!vcHeaderValue) { + vcHeaderValue = /.*\((.*)\)$/.exec(navigator.userAgent)[1]; + } + execXhr.setRequestHeader('vc', vcHeaderValue); + execXhr.setRequestHeader('rc', ++requestCount); + if (shouldBundleCommandJson()) { + execXhr.setRequestHeader('cmds', iOSExec.nativeFetchMessages()); + } + execXhr.send(null); +} + +function onIframeUnload() { + execIframe = null; + setTimeout(pokeNativeViaIframe, 0); +} + +function pokeNativeViaIframe() { + // CB-5488 - Don't attempt to create iframe before document.body is available. + if (!document.body) { + setTimeout(pokeNativeViaIframe); + return; + } + if (bridgeMode === jsToNativeModes.IFRAME_HASH_NO_PAYLOAD || bridgeMode === jsToNativeModes.IFRAME_HASH_WITH_PAYLOAD) { + // TODO: This bridge mode doesn't properly support being removed from the DOM (CB-7735) + execHashIframe = execHashIframe || createHashIframe(); + // Check if they've removed it from the DOM, and put it back if so. + if (!execHashIframe.contentWindow) { + execHashIframe = createHashIframe(); + } + // The delegate method is called only when the hash changes, so toggle it back and forth. + hashToggle = hashToggle ^ 3; + var hashValue = '%0' + hashToggle; + if (bridgeMode === jsToNativeModes.IFRAME_HASH_WITH_PAYLOAD) { + hashValue += iOSExec.nativeFetchMessages(); + } + execHashIframe.contentWindow.location.hash = hashValue; + } else { + // Check if they've removed it from the DOM, and put it back if so. + if (execIframe && execIframe.contentWindow) { + // Listen for unload, since it can happen (CB-7735) that the iframe gets + // removed from the DOM before it gets a chance to poke the native side. + execIframe.contentWindow.onunload = onIframeUnload; + execIframe.src = 'gap://ready'; + } else { + execIframe = createExecIframe('gap://ready', onIframeUnload); + } + } +} + +iOSExec.jsToNativeModes = jsToNativeModes; + +iOSExec.setJsToNativeBridgeMode = function(mode) { + // Remove the iFrame since it may be no longer required, and its existence + // can trigger browser bugs. + // https://issues.apache.org/jira/browse/CB-593 + if (execIframe) { + execIframe.parentNode.removeChild(execIframe); + execIframe = null; + } + bridgeMode = mode; +}; + +iOSExec.nativeFetchMessages = function() { + // Stop listing for window detatch once native side confirms poke. + if (execIframe && execIframe.contentWindow) { + execIframe.contentWindow.onunload = null; + } + // Each entry in commandQueue is a JSON string already. + if (!commandQueue.length) { + return ''; + } + var json = '[' + commandQueue.join(',') + ']'; + commandQueue.length = 0; + return json; +}; + +iOSExec.nativeCallback = function(callbackId, status, message, keepCallback) { + return iOSExec.nativeEvalAndFetch(function() { + var success = status === 0 || status === 1; + var args = convertMessageToArgsNativeToJs(message); + cordova.callbackFromNative(callbackId, success, status, args, keepCallback); + }); +}; + +iOSExec.nativeEvalAndFetch = function(func) { + // This shouldn't be nested, but better to be safe. + isInContextOfEvalJs++; + try { + func(); + return iOSExec.nativeFetchMessages(); + } finally { + isInContextOfEvalJs--; + } +}; + +module.exports = iOSExec; + +}); + +// file: src/common/exec/proxy.js +define("cordova/exec/proxy", function(require, exports, module) { + + +// internal map of proxy function +var CommandProxyMap = {}; + +module.exports = { + + // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...); + add:function(id,proxyObj) { + console.log("adding proxy for " + id); + CommandProxyMap[id] = proxyObj; + return proxyObj; + }, + + // cordova.commandProxy.remove("Accelerometer"); + remove:function(id) { + var proxy = CommandProxyMap[id]; + delete CommandProxyMap[id]; + CommandProxyMap[id] = null; + return proxy; + }, + + get:function(service,action) { + return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null ); + } +}; +}); + +// file: src/common/init.js +define("cordova/init", function(require, exports, module) { + +var channel = require('cordova/channel'); +var cordova = require('cordova'); +var modulemapper = require('cordova/modulemapper'); +var platform = require('cordova/platform'); +var pluginloader = require('cordova/pluginloader'); +var utils = require('cordova/utils'); + +var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady]; + +function logUnfiredChannels(arr) { + for (var i = 0; i < arr.length; ++i) { + if (arr[i].state != 2) { + console.log('Channel not fired: ' + arr[i].type); + } + } +} + +window.setTimeout(function() { + if (channel.onDeviceReady.state != 2) { + console.log('deviceready has not fired after 5 seconds.'); + logUnfiredChannels(platformInitChannelsArray); + logUnfiredChannels(channel.deviceReadyChannelsArray); + } +}, 5000); + +// 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. +function replaceNavigator(origNavigator) { + var CordovaNavigator = function() {}; + CordovaNavigator.prototype = origNavigator; + var newNavigator = new CordovaNavigator(); + // This work-around really only applies to new APIs that are newer than Function.bind. + // Without it, APIs such as getGamepads() break. + if (CordovaNavigator.bind) { + for (var key in origNavigator) { + if (typeof origNavigator[key] == 'function') { + newNavigator[key] = origNavigator[key].bind(origNavigator); + } + else { + (function(k) { + utils.defineGetterSetter(newNavigator,key,function() { + return origNavigator[k]; + }); + })(key); + } + } + } + return newNavigator; +} + +if (window.navigator) { + window.navigator = replaceNavigator(window.navigator); +} + +if (!window.console) { + window.console = { + log: function(){} + }; +} +if (!window.console.warn) { + window.console.warn = function(msg) { + this.log("warn: " + msg); + }; +} + +// Register pause, resume and deviceready channels as events on document. +channel.onPause = cordova.addDocumentEventHandler('pause'); +channel.onResume = cordova.addDocumentEventHandler('resume'); +channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready'); + +// Listen for DOMContentLoaded and notify our channel subscribers. +if (document.readyState == 'complete' || document.readyState == 'interactive') { + channel.onDOMContentLoaded.fire(); +} else { + document.addEventListener('DOMContentLoaded', function() { + channel.onDOMContentLoaded.fire(); + }, false); +} + +// _nativeReady is global variable that the native side can set +// to signify that the native code is ready. It is a global since +// it may be called before any cordova JS is ready. +if (window._nativeReady) { + channel.onNativeReady.fire(); +} + +modulemapper.clobbers('cordova', 'cordova'); +modulemapper.clobbers('cordova/exec', 'cordova.exec'); +modulemapper.clobbers('cordova/exec', 'Cordova.exec'); + +// Call the platform-specific initialization. +platform.bootstrap && platform.bootstrap(); + +// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js. +// The delay allows the attached modules to be defined before the plugin loader looks for them. +setTimeout(function() { + pluginloader.load(function() { + channel.onPluginsReady.fire(); + }); +}, 0); + +/** + * Create all cordova objects once native side is ready. + */ +channel.join(function() { + modulemapper.mapModules(window); + + platform.initialize && platform.initialize(); + + // Fire event to notify that all objects are created + channel.onCordovaReady.fire(); + + // Fire onDeviceReady event once page has fully loaded, all + // constructors have run and cordova info has been received from native + // side. + channel.join(function() { + require('cordova').fireDocumentEvent('deviceready'); + }, channel.deviceReadyChannelsArray); + +}, platformInitChannelsArray); + + +}); + +// file: src/common/init_b.js +define("cordova/init_b", function(require, exports, module) { + +var channel = require('cordova/channel'); +var cordova = require('cordova'); +var platform = require('cordova/platform'); +var utils = require('cordova/utils'); + +var platformInitChannelsArray = [channel.onDOMContentLoaded, channel.onNativeReady]; + +// setting exec +cordova.exec = require('cordova/exec'); + +function logUnfiredChannels(arr) { + for (var i = 0; i < arr.length; ++i) { + if (arr[i].state != 2) { + console.log('Channel not fired: ' + arr[i].type); + } + } +} + +window.setTimeout(function() { + if (channel.onDeviceReady.state != 2) { + console.log('deviceready has not fired after 5 seconds.'); + logUnfiredChannels(platformInitChannelsArray); + logUnfiredChannels(channel.deviceReadyChannelsArray); + } +}, 5000); + +// 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. +function replaceNavigator(origNavigator) { + var CordovaNavigator = function() {}; + CordovaNavigator.prototype = origNavigator; + var newNavigator = new CordovaNavigator(); + // This work-around really only applies to new APIs that are newer than Function.bind. + // Without it, APIs such as getGamepads() break. + if (CordovaNavigator.bind) { + for (var key in origNavigator) { + if (typeof origNavigator[key] == 'function') { + newNavigator[key] = origNavigator[key].bind(origNavigator); + } + else { + (function(k) { + utils.defineGetterSetter(newNavigator,key,function() { + return origNavigator[k]; + }); + })(key); + } + } + } + return newNavigator; +} +if (window.navigator) { + window.navigator = replaceNavigator(window.navigator); +} + +if (!window.console) { + window.console = { + log: function(){} + }; +} +if (!window.console.warn) { + window.console.warn = function(msg) { + this.log("warn: " + msg); + }; +} + +// Register pause, resume and deviceready channels as events on document. +channel.onPause = cordova.addDocumentEventHandler('pause'); +channel.onResume = cordova.addDocumentEventHandler('resume'); +channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready'); + +// Listen for DOMContentLoaded and notify our channel subscribers. +if (document.readyState == 'complete' || document.readyState == 'interactive') { + channel.onDOMContentLoaded.fire(); +} else { + document.addEventListener('DOMContentLoaded', function() { + channel.onDOMContentLoaded.fire(); + }, false); +} + +// _nativeReady is global variable that the native side can set +// to signify that the native code is ready. It is a global since +// it may be called before any cordova JS is ready. +if (window._nativeReady) { + channel.onNativeReady.fire(); +} + +// Call the platform-specific initialization. +platform.bootstrap && platform.bootstrap(); + +/** + * Create all cordova objects once native side is ready. + */ +channel.join(function() { + + platform.initialize && platform.initialize(); + + // Fire event to notify that all objects are created + channel.onCordovaReady.fire(); + + // Fire onDeviceReady event once page has fully loaded, all + // constructors have run and cordova info has been received from native + // side. + channel.join(function() { + require('cordova').fireDocumentEvent('deviceready'); + }, channel.deviceReadyChannelsArray); + +}, platformInitChannelsArray); + +}); + +// file: src/common/modulemapper.js +define("cordova/modulemapper", function(require, exports, module) { + +var builder = require('cordova/builder'), + moduleMap = define.moduleMap, + symbolList, + deprecationMap; + +exports.reset = function() { + symbolList = []; + deprecationMap = {}; +}; + +function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) { + if (!(moduleName in moduleMap)) { + throw new Error('Module ' + moduleName + ' does not exist.'); + } + symbolList.push(strategy, moduleName, symbolPath); + if (opt_deprecationMessage) { + deprecationMap[symbolPath] = opt_deprecationMessage; + } +} + +// Note: Android 2.3 does have Function.bind(). +exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('c', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('m', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('d', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.runs = function(moduleName) { + addEntry('r', moduleName, null); +}; + +function prepareNamespace(symbolPath, context) { + if (!symbolPath) { + return context; + } + var parts = symbolPath.split('.'); + var cur = context; + for (var i = 0, part; part = parts[i]; ++i) { + cur = cur[part] = cur[part] || {}; + } + return cur; +} + +exports.mapModules = function(context) { + var origSymbols = {}; + context.CDV_origSymbols = origSymbols; + for (var i = 0, len = symbolList.length; i < len; i += 3) { + var strategy = symbolList[i]; + var moduleName = symbolList[i + 1]; + var module = require(moduleName); + // + if (strategy == 'r') { + continue; + } + var symbolPath = symbolList[i + 2]; + var lastDot = symbolPath.lastIndexOf('.'); + var namespace = symbolPath.substr(0, lastDot); + var lastName = symbolPath.substr(lastDot + 1); + + var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null; + var parentObj = prepareNamespace(namespace, context); + var target = parentObj[lastName]; + + if (strategy == 'm' && target) { + builder.recursiveMerge(target, module); + } else if ((strategy == 'd' && !target) || (strategy != 'd')) { + if (!(symbolPath in origSymbols)) { + origSymbols[symbolPath] = target; + } + builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg); + } + } +}; + +exports.getOriginalSymbol = function(context, symbolPath) { + var origSymbols = context.CDV_origSymbols; + if (origSymbols && (symbolPath in origSymbols)) { + return origSymbols[symbolPath]; + } + var parts = symbolPath.split('.'); + var obj = context; + for (var i = 0; i < parts.length; ++i) { + obj = obj && obj[parts[i]]; + } + return obj; +}; + +exports.reset(); + + +}); + +// file: src/ios/platform.js +define("cordova/platform", function(require, exports, module) { + +module.exports = { + id: 'ios', + bootstrap: function() { + require('cordova/channel').onNativeReady.fire(); + } +}; + + +}); + +// file: src/common/pluginloader.js +define("cordova/pluginloader", function(require, exports, module) { + +var modulemapper = require('cordova/modulemapper'); +var urlutil = require('cordova/urlutil'); + +// Helper function to inject a - - - + + + + + TDA Enrichment + + + + + - - -
- -

TDA Enrichment

Info - - - -
- Close -
-

Welcome

-

Welcome to Thomas Deacon Academy's Sports Enrichment app! This app contains the full timetable for the after school sports enrichment as well as the Big Friday events. The app also contains details on attending inter-college enrichment as well as the results and rankings of the colleges.

-
-
- -
- - - -
-

© George Garside

-
-
- - -
- -

Monday

- -
- -
    -
  • Badminton
  • -
  • Week A & B

    -
    -

    All Years

    -

    Staff: BCH / BHU

    -

    Location: Sports Hall

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Cricket
  • -
  • Week A & B

    -
    -

    Year 7

    -

    Staff: BHU / JHI

    -

    Location: Sports Hall

    -

    Time: 4:00 - 5:00pm

    -
  • -
  • Fitness
  • -
  • Week A & B

    -
    -

    All Years

    -

    Staff: SHOFF / JME

    -

    Location: Fitness Suite

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Girls Hockey
  • -
  • Week A & B

    -
    -

    Year 8

    -

    Staff: MYE / RLO

    -

    Location: Astro

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Gold DOE
  • -
  • Week A & B

    -
    -

    6th Form

    -

    Staff: CMCC / HED

    -

    Location: LT1 / T01

    -

    Time: 5:30 - 6:30pm

    -
  • -
  • Hockey
  • -
  • Week A & B

    -
    -

    Year 8

    -

    Staff: Coach (A) • EFI (Week B)

    -

    Location: Astro

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Week A & B

    -
    -

    Year 9

    -

    Staff: JME / MYE

    -

    Location: Astro / Sports Hall

    -

    Time: 4:00 - 5:00pm

    -
  • -
  • Week A

    -
    -

    Year 10

    -

    Staff: CGE

    -

    Location: Astro

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Netball
  • -
  • Week A

    -
    -

    Year 10

    -

    Staff: KGE

    -

    Location: Netball Courts

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Rugby
  • -
  • Week A & B

    -
    -

    Year 7, 8 & 9

    -

    Staff: SWI (Week A) • SCL / GWI (Week B)

    -

    Location: Field

    -

    Time: 4:00 - 5:00pm

    -
  • -
- -
- -
- Back -
-
- - -
- -

Tuesday

- -
- -
    -
  • Badminton
  • -
  • Week A & B

    -
    -

    All Years

    -

    Staff: BCH / BHU

    -

    Location: Sports Hall

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Cricket
  • -
  • Week A & B

    -
    -

    Year 8 & 9

    -

    Staff: BHU / JHI

    -

    Location: Sports Hall

    -

    Time: 4:00 - 5:00pm

    -
  • -
  • Fitness
  • -
  • Week A & B

    -
    -

    All Years

    -

    Staff: SCL / AHO (Week A) • SWI (Week B)

    -

    Location: Fitness Suite

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Hockey
  • -
  • Week A & B

    -
    -

    Year 7

    -

    Staff: AME / CGE / CTH

    -

    Location: Astro

    -

    Time: 2:45 - 4:15pm

    -
  • -
  • Indoor Athletics
  • -
  • Week A & B

    -
    -

    All Years

    -

    Staff: EFI / CTH / VTO

    -

    Location: Sports Hall

    -

    Time: 4:00 - 5:00pm

    -
  • -
  • Boys Indoor Hockey
  • -
  • Week A

    -
    -

    6th Form

    -

    Staff: MYE

    -

    Location: Astro

    -

    Time: 12:10 - 1:40pm

    -
  • -
  • Week A

    -
    -

    6th Form

    -

    Staff: MYE

    -

    Location: Astro

    -

    Time: 12:50 - 1:40pm

    -
  • -
  • Netball
  • -
  • Week A & B

    -
    -

    Year 7

    -

    Staff: GWI / RBRO (Week A) • RLO (Week B)

    -

    Location: Netball Courts

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Week A & B

    -
    -

    Year 8

    -

    Staff: VTO

    -

    Location: Netball Courts

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Table Tennis
  • -
  • Week A & B

    -
    -

    All Years

    -

    Staff: CGEL

    -

    Location: Sports Hall

    -

    Time: 2:45 - 4:00pm

    -
  • -
- -
- -
- Back -
-
- - -
- -

Wednesday

- -
- -
    -
  • A-Level Pract
  • -
  • Week A & B

    -
    -

    A-Level

    -

    Staff: EFI / CMCC

    -

    Location: Fitness Suite

    -

    Time: 1:45 - 2:45pm

    -
  • -
  • Athletics (Joggers)
  • -
  • Week A & B

    -
    -

    All Years

    -

    Staff: OMA

    -

    Location: Field

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • CCF
  • -
  • Week A & B

    -
    -

    Year 9, 10, 11 and 6th Form

    -

    Staff: CTH / CGEL / GWI / CMCC

    -

    Location: CCF HQ

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Cricket
  • -
  • Week A & B

    -
    -

    -

    Staff: BHU / JHI

    -

    Location: Sports Hall

    -

    Time: 4:00 - 5:00pm

    -
  • -
  • Fitness
  • -
  • Week B

    -
    -

    6th Form

    -

    Staff: SHOFF / VTO

    -

    Location: Field

    -

    Time: 1:45 - 2:45pm

    -
  • -
  • Football
  • -
  • Week B

    -
    -

    6th Form

    -

    Staff: CGE

    -

    Location: Field

    -

    Time: 1:45 - 2:45pm

    -
  • -
  • Girls Fitness
  • -
  • Week A & B

    -
    -

    All Years

    -

    Staff: VTO (Week A) • SHOFF / BHU (Week B)

    -

    Location: Indoor

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Indoor Hockey
  • -
  • Week A & B

    -
    -

    Year 10 & 11

    -

    Staff: SCL

    -

    Location: Sports Hall

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Netball
  • -
  • Week A & B

    -
    -

    Year 9

    -

    Staff: SWI

    -

    Location: Netball Courts

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Week A & B

    -
    -

    Year 10

    -

    Staff: KGE / KSP

    -

    Location: Netball Courts

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Week A

    -
    -

    6th Form Girls

    -

    Staff: AHO

    -

    Location: Netball Courts

    -

    Time: 12:00 - 12:55pm

    -
  • -
  • Week B

    -
    -

    6th Form Girls

    -

    Staff: AHO

    -

    Location: Netball Courts

    -

    Time: 1:45 - 2:45pm

    -
  • -
  • Rugby
  • -
  • Week A & B

    -
    -

    Year 10, 11, 12 & 13

    -

    Staff: AME

    -

    Location: Astro

    -

    Time: 4:00 - 5:00pm

    -
  • -
  • Swimming
  • -
  • Week A & B

    -
    -

    All Years

    -

    Staff: RBR

    -

    Location: Regional Pool

    -

    Time: 2:45 - 4:00pm

    -
  • -
- -
- -
- Back -
-
- - -
- -

Thursday

- -
- -
    -
  • Fitness
  • -
  • Week A & B

    -
    -

    All Years

    -

    Staff: SHOFF / CGEL

    -

    Location: Fitness Suite

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Basketball
  • -
  • Week A & B

    -
    -

    6th Form

    -

    Staff: IWH / LMA

    -

    Location: Sports Hall

    -

    Time: 4:00 - 5:00pm

    -
  • -
  • Hockey
  • -
  • Week A & B

    -
    -

    Year 7

    -

    Staff: AME / CTH / MYE

    -

    Location: Astro

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Week A & B

    -
    -

    Year 8

    -

    Staff: EFI (Week A) • Coach (Week B)

    -

    Location: Astro

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Week A & B

    -
    -

    Year 8 Girls

    -

    Staff: RLO / MYE

    -

    Location: Sports Hall

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Netball
  • -
  • Week A & B

    -
    -

    Year 7

    -

    Staff: RBRO / GWI

    -

    Location: Netball Courts

    -

    Time: 2:45 - 4:00pm

    -
  • -
- -
- -
- Back -
-
- - -
- -

Friday

- -
- -
    -
  • Badminton
  • -
  • Week A & B

    -
    -

    All Years

    -

    Staff: BCH / BHU

    -

    Location: Sports Hall

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Fitness
  • -
  • Week A & B

    -
    -

    All Years

    -

    Staff: SHOFF / VTO (Week A) • AME (Week B)

    -

    Location: Fitness Suite

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Hockey
  • -
  • Week A

    -
    -

    Year 9

    -

    Staff: JME

    -

    Location: Astro

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Week B

    -
    -

    Year 9

    -

    Staff: JME

    -

    Location: Astro

    -

    Time: 12:20 - 1:30pm

    -
  • -
  • Week B

    -
    -

    Year 10

    -

    Staff: CGE

    -

    Location: Astro

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Week A & B

    -
    -

    Year 11

    -

    Staff: SCL

    -

    Location: Astro

    -

    Time: 2:45 - 4:00pm

    -
  • -
  • Netball
  • -
  • Week B

    -
    -

    Year 9

    -

    Staff: SWI

    -

    Location: Netball Courts

    -

    Time: 12:20 - 1:30pm

    -
  • -
  • Trampoline
  • -
  • Week A & B

    -
    -

    All Years

    -

    Staff: AGL / SWI

    -

    Location: Sports Hall

    -

    Time: 2:45 - 4:00pm

    -
  • -
- -
- -
- Back -
-
- - -
- -

Dodgeball

- -
- - -

Now Tug of War has finished, it's time to get your Dodgeball teams ready!

-

Your college’s PE teachers will be coming round to get your team sheets filled in - get your name down if you want to play.

-

See below for when your competition is:

- -
-

Timetable

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TimeLocation
March 22ndYear 11, 12, 13 & Staff DodgeballBig FridaySports Hall
Easter: Term 5
April 26thYear 10 DodgeballBig FridaySports Hall
May 10thYear 9 DodgeballBig FridaySports Hall
May 24thYear 8 DodgeballBig FridaySports Hall
Term Break: Term 6
June 14thYear 7 DodgeballBig FridaySports Hall
- -
- -
- -
- Back -
-
- - -
- -

H&F HOFF's 5 Wheels

- -
- -
-
-

1st: Aerobic Training

-

This is the wheel that those desperate to lose weight fast always drive on first. Even though it's not the answer to helping you obtain that celebrity-perfect look by itself, aerobic exercise is still a valuable wheel.

-

The Facts

-

Without aerobic training, you'll lack the adequate stamina to push your muscles beyond what they're capable of doing so they will become stronger and shape up faster. Without aerobic training you'll have to watch calories religiously, your body wont be as efficient at flushing out the toxins that resistance training leaves behind, such as lactic acid. Add the fact that aerobic training improves the quality of your sleep and its pretty easy to see how it fits into the bigger picture.

-

Foundation

-

The term aerobic means with oxygen. Aerobic activity is any physical activity done for an extended period of time that forces your cardiovascular system (heart, lungs and blood vessels) to increase the amount of oxygen and blood circulating through your body, so that you're benefiting even at rest. Your body doesn't care how you make that happen, although choosing activities that work larger muscle groups, typically your legs, is more effective at getting that job done.

-

To count as aerobic exercise, any activity you choose has to keep your heart beating around sixty-five percent of your maximum heart rate for at least 20 minutes or more.

-

Your maximum heart rate, or MHR, is the highest number of times your heart can contract in one minute. To find yours, all you do is subtract your age from the number 220. That means if you're 35 years old, your MHR is 220 minus 35 (or 185 beats per minute). This is an important number to know, as it can help you know how hard you should be exercising.

-

To get the most from aerobic exercise, you need to keep your pulse between a range of 60% and 70% of your MHR to burn fat. For the 35 year old that equates to a pulse of between 111 to 130 per minute. If you increase the intensity you're working at to between 70% and 80% this will improve your aerobic fitness, the pulse rate will then be at 130 to 148 beats per minute.

-

Try to do some form of aerobic activity 3 times a week, for at least 20 minutes. More is better; less might be suitable if you have a favourable metabolism. If you can do more than 20 minutes, then do it: every minute past the twenty burns additional body fat as fuel. After that magic number (20 minutes), you've exhausted your body's glycogen (carbohydrate) stores, which it uses as fuel when you workout. From a fat-burning standpoint, if you can exercise beyond 20 minutes, your body has no choice but to use more of its own stored body fat for energy instead.

-

Your Options

- There are hundreds of things you could do to get an aerobic workout besides using the typical gym machines (stationary bikes, treadmills, cross-trainers and rowing machines) and the obvious outside choices (biking, jogging, running, swimming and walking). If you're not into any of these don't write off exercise, as playing a sport, dancing, ice-skating skiing, kayaking, rollerblading, even house cleaning and gardening can be aerobic if done a certain way at a certain intensity! -

Use Everything in One Workout

-

If you want a workout your body will never get used to (or forgive you for), try flip-flopping between your cardio choices at the gym (stationary bike, treadmill, step routine, jump rope, stair climber or rower) every three minutes. Make the first minute a warm-up, push yourself around 65% of your MHR for the second minute (or on a scale 1 to 10 in effort, around a 6), then go for it in the last minute (85% or level 8 effort).

-

Know When Too Much Is Too Much

-

Pushing yourself higher within your target heart rate zone will definitely reap more results, but you need to know when too much is too much. If you can't speak a full sentence while exercising without being winded, then you're most likely pushing yourself to the far end of your target heart rate zone. On the other hand, if you're able to carry on a full conversation, then you're probably working at a level thats below your target heart rate zone.

-
-
-

2nd: Resistance Training

-

Whether you're brand new to this whole exercise experience, or fitness is old hat, you probably still know what resistance training entails, or know it by one of its many other names: strength training, weight training, pumping iron, anaerobic exercise, etc.

-

This is the chapter you've either been waiting for or dreading. If you're a male and breathing, you may start to get a bit fired up by now. If you're a female, and fairly new to fitness, you might have doubts, or even visions of morphing into a 300-pound monster with arms like ham hocks as soon as you start bench pressing. Relax, its not like that.

-

The Facts

-

Resistance training is not just about building muscle that will help you look great. Its also a prehab for preventing injuries and making sure you feel great. Resistance training also turns back the clock by reversing many factors that naturally occur in the ageing process.

-

Reshaping your muscles can even help you stay leaner. Aerobic exercise burns more calories per minute and gets your metabolism into overdrive faster than resistance training. However, after you've finished weight training, your body has to use extra calories throughout the day just to sustain the new, leaner body you've built for yourself. Using weights effectively will keep your metabolism turned on all day long.

-

So think of muscle as a fat burning friend who's with you all day long. The more muscle you have, the higher your Basal Metabolic Rate (BMR). What's a BMR, and why should you care about it? Your BMR is another important number: it is the number of calories you burn every day to keep your body functioning, your heart beating, your lungs breathing, and so on. It's your BMR that accounts for almost 75% of all of the calories you burn daily, with the other 25% being burned from all your daily physical activities.

-

Building more muscle though resistance training means you'll have extra muscle fibres consuming more energy. Even when you're just sitting there looking good but not doing a thing. In fact, every pound of muscle you add to your frame burns an additional 30 to 50 calories per day. Substitute 5 pounds of muscle for 5 pounds of fat and not only will you naturally be more aesthetically in shape, but you'll burn and extra 150-250 calories a day doing absolutely nothing at all.

-

Foundation

-

You already know that Aerobic activity is any activity that increases your pulse for an extended period of time, causing your heart and lungs to work harder to get more oxygen to your muscles. Resistance training, Anaerobic exercise is any activity done in short, intense bursts that works your body without requiring much oxygen.

-

Resistance training means working one muscle (or a group of muscles) against some form of resistance so that your muscles have no choice but to break down from fatigue and stress. Do it the right way, and those beaten-down muscles have no choice but to rebuild themselves so they're stronger for the next time you decide to put them through the paces.

-

No matter what tool you use to stress your muscles barbells, dumbbells, weight machines, stretch cords, medicine balls, your own body weight if you provide enough resistance to fatigue your muscles by making them repeat a movement for a given number of repetitions, you'll achieve the same goal.

-

Heres how it works: Lifting the weight one time is called a repetition (rep). A group of repetitions performed without stopping is called a set. The number of reps you should do to fatigue your muscles depends on your goals. Most experts stick with using a weight you can lift, raise, or pull 8 to 15 times. If you're looking to noticeably strengthen your muscles, then using a heavier weight that allows you do to between 6 and 10 reps is better. If improving muscle tone is your goal then 10 to 15 reps is more suited and lastly muscle endurance 15 to 20 reps.

-

Your Options

-

The choices you have with resistance training are virtually limitless there are literally hundreds of exercises that will prevent your muscles (or you) from being bored.

-

The best resistance training workout leaves no stone unturned. It's a program that targets every major muscle group in your body, not just the ones you're concerned with. These 13 exercises are for overall muscle-development. There are countless spin-off movements from these core exercises. Learn these, master them effectively, and then variations can be added.

-
    -
  • For your legs and butt → The squat and the lunge
  • -
  • For your chest → The chest press and the chest fly
  • -
  • For your back → The pulldown and the row
  • -
  • For your shoulders → The shoulder press and the raise
  • -
  • For your triceps → The pressdown and the extension
  • -
  • For your biceps → The curl
  • -
  • For your abs → The crunch and the reverse crunch
  • -
-

Focus

-

If resistance training has never worked for you and you use perfect form (perfect technique during an exercise), Id say that you're using weights that are too light for you. If you're not using a weight heavy enough to fully fatigue during each set, you'll never push them enough to make them want, and need, to improve themselves. For example, if an exercise asks you do 12-15 repetitions, you need to select a weight that you can complete only 12-15 reps with while keeping good form. If you could have easily eked out three more reps before quitting, your muscles were never really challenged enough to improve themselves, making the entire set less effective than it should and certainly could have been. Once you can do more than the required number of reps, then its time to raise the weight slightly.

-

Frequently asked questions

-
Wont weights make me big?
-

If you're a guy, you can probably skip over this question! If you're a woman You wont get big! As a rule, thats because most women are simply not genetically capable of ballooning up from strength training alone. Your body has 10% of the testosterone that the average male has and look at how hard it is for a man to add muscle. Even they cant do it without lifting heavy weights, eating steak for breakfast, milkshakes all day, and doing sets of 4 to 6 reps! I think you get my point!

-

If you're worried about adding a pound of muscle, it's estimated that the space of a pound of muscle is about 22% less than a pound of fat. That means adding 5 pounds of muscle and losing 5 pounds of fat would actually make you look smaller. I'd say thats a fair trade off. Finally, muscle isn't created by weights. It's created by food proteins to be more precise. You have to eat quality and a quantity of food above and beyond what you burn, and break the muscle down in the gym so they need to repair, plus eat every 3 to 4 hours, and get adequate rest so that they recover... Do you see what I mean? Besides, it's not an overnight process, so you could always back off or even stop.

-
Can I burn fat from a specific area by doing specific exercise?
-

Welcome to the biggest con in fitness and exercise. It may be the quick fix you're wishing for, but spot reduction (the popular term for it) is one of the biggest exercise lies out there. It's impossible to lose weight in one particular area by lifting weights or doing exercises that target only that area. You body burns fat in a genetically predetermined patter over which you have no control. But there's good news: As you start driving on all four wheels, you'll begin to burn fat gradually from all over your body, including your specific wish list of areas. Typically the last place you store fat is the first area you'll see a noticeable difference. Unfortunately, that also means the first place you started storing fat is usually the last area to get lean: men around the waist; women around the hips/butt.

-

Until you reduce the body fat above or around your muscles through cardiovascular exercise, resistance training, eating right, and adequate rest you'll never make those muscles or perfect set of abs visible.

-
-
-

3rd: Nutrition

-

Eating right isn't really all that complicated. It's a choice, and a conscious, daily choice at that. Making the right choice on a regular basis, and sticking with your choice over time, will get you there.

-

The Facts

-

Choose to eat the right way and you won't just improve every possible aspect of your health, but you'll make the job of reshaping yourself through exercising that much easier. The time-starved amongst us are at the mercy of convenience eating. You are your own food-police deciding the type of foods you eat; I can't monitor that all the time because I'm only with you for 1 hour at the gym. The other 23 hours are your responsibility.

-

Ingest the wrong foods and you can easily prevent your system from operating at its most efficient level especially if you're active. Eat less than enough to counterbalance the extra nutritional requirements your body needs to maintain itself and you'll store the same excess fat you're trying to get rid of because your body thinks it's going to starve, and so it hold onto every calorie in anticipation of not getting any more.

-

Regardless of what your goals are from exercise, following a few basic nutrition rules of the thumb will make this 3rd wheel worth a lot more to your body than you ever thought it could be.

-

Foundation

-

If you're trying to lose weight, calories may represent a guilty pleasure or a great evil to your brain. But to your body, calories are just energy units to be used as fuel.

-

You wouldn't give your car more fuel than it really needed, would you? If you did, all the fuel would just overflow and make a mess, right? That's exactly what happens with your body: when you eat more calories than it needs, the result is overflow to every place your body holds excess calories (i.e. fat). It doesn't know you don't want to gain weight, it just sees all those extra calories and assumes you want to store them as energy for later on.

-

Stand up and jump an inch or two off the ground. Anything move? For every pound of stored body fat you felt jiggle, all you're really looking at is roughly 3500 calories. Just 3500 units of fuel your body thinks it needs to hold onto because you haven't given it any reason to think otherwise. But don't worry. Now that you know why you're storing calories, it's going to be easier to convince your body to use them up and stop storing then unnecessarily.

-

Eating a low-fat, high-fibre diet along with doing aerobic exercise to burn calories (and resistance training to maintain lean mass and to naturally boost your metabolism) is the most effective way to lose fat without holding you back from building muscle tissue. Try not to use the word diet because it makes people feel like they're walking a tightrope: one tiny misstep (doughnut!) and they assume that all their hopes and dreams will come crashing down. Diets are usually temporary by nature, leading to eventual failure, whereas an on-going healthy nutritional intake that is a lifestyle will last a lifetime.

-

Calories

-

How many calories you really need to eat every day depends on who you are. Some people can maintain their bodyweight on 1400 calories a day, whereas others have metabolisms like a hummingbird: eat suet at every meal and never put on an ounce of fat. It all depends on everything from your metabolism and level of activity to your age, heritage, gender, what you're putting in your mouth, and when you're putting it in your mouth.

-

As a starting point the most common method used by dieticians and other health-care professionals is the Harris-Benedict formula.

-

Men: 66 + (6.3 x wt in lbs) + (12.9 x height in inches) - (6.8 x age in years)

-

Women: 655 + (4.3 x wt in lbs) + (4.7 x height in inches) - (4.7 x age in years)

-

The number you are left with is your estimated basal metabolic rate expenditure (or BMR): the minimum number of calories your body needs just to keep you going. Getting to school, typing up that report, racing around trying to find a decent place to eat these are all extra actions that increase your BMR by around 20%. For example a 35 year old woman who weighs 140lbs and stands 5 feet 6 inches would have a BMR of approx. 1402 calories a day. Multiply this by 120% and all she really needs to eat every day is 1683 calories. If your goal is to trim down, its just a matter of eating less and/or burning extra calories through exercise to lose weight.

-

Carbohydrates, Proteins, and fats

-

No matter how many calories you need each day, its important to make sure they don't all come from the same place. Carbohydrates, proteins, and fats are all broken down at different speeds in the body to create a continual flow of caloric energy.

-

Most nutritionists recommend dividing up your daily Carbohydrates, proteins, and fats using a ratio of 5:3:2 (respectively). This translates into getting 50% of your daily calories from carbs, 30% from protein, and 20% from fat. Using the example above, the woman that requires 1683 calories to maintain her weight would have a nutritional profile as follows to maintain her weight:

-
    -
  • Carbohydrate 841.5 cal. (50%)
  • -
  • Protein 504.9 cal. (30%)
  • -
  • Fat 336.6 cal. (20%)
  • -
-

To make this number crunching easier to calculate for everyday living we can equate these numbers further into grams and workout how much to allow for each meal.

-
    -
  • Carbohydrate 210g (4 cal/g)
  • -
  • Protein 126g (4 cal/g)
  • -
  • Fat 37g (9 cal/g)
  • -
-

Its healthier to eat all day long, breaking-up your caloric intake into smaller increments (5 to 6 meals) instead of the standard 3, you also help curb binges, and also keep blood sugar levels even throughout the day. Larger meals raise your blood sugar, which can trigger an increase in the release of insulin within the bloodstream. Remember, little and often. The easiest way to accomplish 5 or even 6 meals per day is to moderate the traditional 3 meals in size and snack in between. One snack mid-morning and one mid-afternoon.

-

For the example above based on 1683 calories, each of the 5 meals would average 336 calories, carbs 42 grams, protein 25 grams, fats 7 grams. It would be unrealistic to expect an exact equality between meals but use these figures as a guide.

-

There is so much good information on nutrition: what's good, what's not, nutrition plans, when to eat, when to stop, etc. I'll leave that for you to decide whats a wise choice and what's an unwise choice (cue another 30 minutes cycling!).

-

These are my nutritional guidelines:

-
    -
  • Most caloric meal - breakfast; the least - dinner. Drink 4-pints of water a day. Chicken, tuna (packed in water), eggs, wholemeal bread and rice. Plenty of fruit and veg. Protein shakes are convenient as are smoothies for snacks.
  • -
  • Read all labels, avoid sugar and salt. After 4pm drop pasta, rice, potato and bread. Obtain carbs from veg and salads for evening meal.
  • -
  • Protein sources Lean mince beef, chicken, fish, soya, eggs
  • -
  • Carbs Wholemeal bread and rice, porridge. Plenty of fruit (such as apples, bananas, oranges, satsumas, grapes, pears, strawberries, peaches, apricots) and vegetables (carrots, broccoli, spinach, beans)
  • -
  • Healthy fats: vegetable oils, oily fish, nuts, omega 3 enriched eggs, olive oil olives, seeds.
  • -
-
-
-

4th: Rest and Recovery

-

It sounds like the easiest wheel of the five to drive on, but it's actually the one that most frequently gets either too much or too little use. Give your body too much rest and it'll look like it. Give it too little and you increase your odds of not only injuring yourself, but never seeing the body-shaping results you're shooting for.

-

The facts

-

Whether you hate or love exercise, your body interprets all that time you've spent pulling, pushing, and sweating on gym equipment as on thing: stress. Thats why the time you give your muscles to rest and recover in between each workout can make a huge difference in the kind of results you end up seeing for all of your hard work.

-

Rest is also important between sets at the gym, 30 to 180 seconds ideally, depending on the intensity of the exercise and the routine. This downtime gives your body time to drain the muscles of any leftover lactic acid (a by-product of exercise that gives that fun, burning sensation towards the end of a set!).

-

Resting between workouts or lack of it is one of the biggest mistakes most overzealous exercisers make. Lifting weight causes microscopic breaks or tears inside your muscle fibres, breaks that trick your body into thinking its about go to war. These fibres react by rebuilding their legions to be stronger and firmer for the next battle, that is, if you give them an armistice to start recruiting. After exhausting a muscle with resistance training, it needs at least 48-72 hours of recovery time in order to heal from all that microscopic damage. If you work out before that time you risk injury, you wont be able to lift as much weight which will hold you back from using enough resistance to make your muscles stronger. Muscle strength is directly relative to muscle size. Increase your strength and the muscles have to respond by increasing in volume.

-

A decent nights sleep. Most healthy adults need an average of 7 to 9 hours of sleep a night. Whatever your cycle is, find it, stick with it.

-
-
-

5th: Mental Conditioning

-

What makes one person lie on a sofa eating pizza, chips and cake, while another may be up at 6am pounding the streets trying to beat a personal best? Why are some people more motivated than others? Not just at sport, exercise or at work, but in life?

-

Each of us has motivations, goals and inspirational figures that shape what we do, what we think, how we react. Some of these goals are verbalised, debated and shared, some are deep rooted and personal. It all starts in the mind.

-

Life is a mind game. All your aspirations are played out in your head. All your relationships are shaped in your head. Your mind dictates whether you fulfil your potential or live your life dreaming. It's about attitude. The good thing in life is that you can choose your attitude, you cant always choose or change the circumstances in your arena, but you can always choose or change your attitude.

-

Sport and exercise provide a framework for personal development. It appeals to people because it meets a basic, instinctive need to want to take on challenges and succeed, and encourages people to develop skills along the way.

-

It's inappropriate to talk about a healthy lifestyle, fitness regime or weight training program as a sacrifice. What top performers do is make choices. We all have choices to make, its all about attitude.

-

If you want to lose weight or gain some definition in your arms you can visualise how you want to look after you've succeeded. So many people on diets (temporary punishment!) don't actually see themselves how they want to be, getting into certain clothes. If you visualise the result in advance it'll help on days when you lose your motivation. But what is visualisation? It's the process of seeing yourself doing what it is you need to do whether running a winning race, throwing a record breaking javelin distance or lifting your heaviest weight. What the mind imagines usually creates a capacity for the body to do it.

-

What a person believes can determine the outcome. There is no doubt that in sport as in many other areas of life, there is such a thing as the self-fulfilling prophecy. If you limit your beliefs, you limit your potential to achieve.

-
-
- -
- -
- Back -
-
- - -
- -

H&F Warm-ups & Cool-downs

- -
- - -

-There is no doubt that time spent on warming up and cooling down will improve an athlete's level of performance and accelerate the recovery process needed before and after training or competition. As a result, the coach must encourage the athlete to regard the warm up and cool down as an essential part of both the training session and competition itself. -

- -
-
-

Warm-up

-

Muscle stiffness is thought to be directly related to muscle injury and therefore the warm up should be aimed at reducing muscle stiffness.

-

Warming up should at least consist of the following:

-
    -
  • 5 to 10 minutes jogging to increase body temperature
  • -
  • 10 to 15 minutes dynamic stretching exercises to reduce muscle stiffness
  • -
  • 10 to 15 minutes general and event specific drills to prepare for the session or competition: e.g. for a runner: -
      -
    • Lower leg drills
    • -
    • Leg drills
    • -
    • Technique drills
    • -
    -
  • -
  • 4 to 8 easy run outs over 30 to 60 metres - focus on correct running technique (Tall, Relaxed, Smooth and Drive)
  • -
-

Dynamic stretches are more appropriate to the warm up as they help reduce muscle stiffness. Static stretching exercises do not reduce muscle stiffness.

-

What are the benefits of a warm up?

-

Performance may be improved, as an appropriate warm up will result in an:

-
    -
  • Increased speed of contraction and relaxation of warmed muscles
  • -
  • Dynamic exercises reduce muscle stiffness
  • -
  • Greater economy of movement because of lowered viscous resistance within warmed muscles
  • -
  • Facilitated oxygen utilisation by warmed muscles because haemoglobin releases oxygen more readily at higher muscle temperatures
  • -
  • Facilitated nerve transmission and muscle metabolism at higher temperatures; a specific warm up can facilitate motor unit recruitment required in subsequent all out activity
  • -
  • Increased blood flow through active tissues as local vascular beds dilate, increasing metabolism and muscle temperatures
  • -
  • Allows the heart rate get to a workable rate for beginning exercise
  • -
  • Mentally focused on the training or competition
  • -
-
-
-

Cool-down

-

Cooling down should consist of the following:

-
    -
  • 5 to 10 minutes jogging/walking - decrease body temperature and remove waste products from the working muscles
  • -
  • 5 to 10 minutes static stretching exercises
  • -
-

Static stretches are more appropriate to the cool down as they help muscles to relax, realign muscle fibres and re-establish their normal range of movement. These stretches should be held for approximately 10 seconds.

-

What are the benefits of a cool down?

-

An appropriate cool down will:

-
    -
  • aid in the dissipation of waste products, including lactic acid
  • -
  • reduce the potential for DOMS
  • -
  • reduce the chances of dizziness or fainting caused by the pooling of venous blood at the extremities
  • -
  • reduce the level of adrenaline in the blood
  • -
  • allows the heart rate to return to its resting rate
  • -
-
-
- - -
- -
- Back -
-
- - -
- -

H&F Resistance Training

- -
- - -

Resistance training is not just about building muscle that will help you look great. Its also a prehab for preventing injuries and making sure you feel great. Resistance training also turns back the clock by reversing many factors that naturally occur in the ageing process.

-

Reshaping your muscles can even help you stay leaner. Aerobic exercise burns more calories per minute and gets your metabolism into overdrive faster than resistance training. However, after you've finished weight training, your body has to use extra calories throughout the day just to sustain the new, leaner body you've built for yourself. Using weights effectively will keep your metabolism going all day long.

-

The Facts

-

Resistance training means working one muscle (or a group of muscles) against some form of resistance so that your muscles have no choice but to break down from fatigue and stress. Do it the right way, and those beaten-down muscles have no choice but to rebuild themselves so they're stronger for the next time you decide to put them through the paces.

-

No matter what tool you use to stress your muscles barbells, dumbbells, weight machines, stretch cords, medicine balls, your own body weight if you provide enough resistance to fatigue your muscles by making them repeat a movement for a given number of repetitions, you'll achieve the same goal.

-

Heres how it works: Lifting the weight one time is called a repetition (rep). A group of repetitions performed without stopping is called a set.

-

The number of reps you should do to fatigue your muscles depends on your goals. Most experts stick with using a weight you can lift, raise, or pull 8 to 15 times.

-
    -
  • For Strength - 6 to 10 reps
  • -
  • For Toning - 10 to 15 reps
  • -
  • For Endurance - 15 to 20 reps
  • -
-

…but remember, whatever amount of reps you are doing the weight needs to be heavy enough to make your muscles work. There is no point in doing a weight that's too easy, as your muscles won't be overloaded and forced to react or grow.

- -

Training Frequency

- - - -

Training Age

- - - -

Muscle Group Training

- -
- Legs - Arms -
-
- Back - Chest - Shoulders -
- -

Resources

- - - -
-
-

Are you sure you want to open this resource?

-

This action can use data, and may not work on some Android devices.

-
- - -
-
-
- -
- -
- Back -
-
- - -
- -

H&F RTF 1/wk

- -
- -

LEGS

-

Squat 2 sets (12, 10)

-

Lunges 2 sets (12,10)

-

Deadlift 2 sets (12,10)

-

BACK

-

Chin-ups 2 sets (10,10) – either with assistance machine or using own bodyweight

-

Lat pull down to chest, medium grip, 2 sets (12,10)

-

Seated Row, narrow handle, 2 sets (12,10)

-

CHEST

-

Flat Dumbbell bench press 2 sets (12,10)

-

Incline Dumbbell Flys 2 sets (12,10)

-

Chest press machine 2 sets (12,10)

-

Optional;

-

Dips, wide grip position, 2 sets of 10 or 12.

-

SHOULDERS

-

Seated dumbbell press 2 sets (12,10)

-

Upright Row 2 sets (12,10)

-

Lateral Raise 2 sets (12,10)

-

TRICEPS

-

Lying Triceps extension 2 sets (12,10)

-

Triceps press down 2 sets (12,10)

-

BICEPS

-

Standing barbell curls 2 sets (12,10)

-

Seated Dumbbell curls 2 sets (,12,10)

- -

Back

- -
- -
- - -
- -

H&F RTF 2/wk

- -
- -
    -
  • Mon: Workout 1
  • -
  • Tuesday: rest or cardio
  • -
  • Wed: rest or cardio
  • -
  • Thur: rest or cardio
  • -
  • Fri: Workout 2
  • -
-

Workout 1 – Chest, Shoulders, Triceps

-

Warm up first, then warm up specific muscle group with a couple of lighter sets, then go into the workout…

-

CHEST

-

Flat Dumbbell bench press 3 sets (15,12,10)

-

Incline Dumbbell Flys 3 sets (12,12,10)

-

Chest press machine 3 sets (15,12,10)

-

Optional;

-

Dips, wide grip position, 3 sets of 10 or 12.

-

SHOULDERS

-

Seated dumbbell press 3 sets (15,12,10)

-

Upright Row 3 sets (15,12,10)

-

Lateral Raise 3 sets (15,12,10)

-

TRICEPS

-

Lying Triceps extension 3 sets (15,12,10)

-

Triceps press down 3 sets (12,12,10)

-

Workout 2 – Legs, Back, Biceps

-

Warm up first, then warm up specific muscle group with a couple of lighter sets, then go into the workout....

-

LEGS

-

Squat 3 sets (10, 10, 10)

-

Lunges 3 sets (12,12,10)

-

Deadlift 3 sets (15,12,10)

-

BACK

-

Chin-ups 3 sets (10,10,10) – either with assistance machine or using own bodyweight

-

Lat pull down to chest, medium grip, 3 sets (15,12,10)

-

Seated Row, narrow handle, 3 sets (15,12,10)

-

BICEPS

-

Standing barbell curls 3 sets (15,12,10)

-

Seated Dumbbell curls 3 sets (12,12,10)

- -

Back

- -
- -
- - -
- -

H&F RTF 3/wk

- -
- -
    -
  • Mon: Workout 1
  • -
  • Tue: rest or cardio
  • -
  • Wed: Workout 2
  • -
  • Thur: rest or cardio
  • -
  • Fri: Workout 1
  • -
  • Sat: rest or cardio
  • -
  • Sun: rest or cardio
  • -
  • Mon: Workout 2
  • -
  • Tue: rest or cardio
  • -
  • Wed: Workout 1
  • -
  • Thur: rest or cardio
  • -
  • Fri: Workout 2
  • -
-

Workout 1 – Chest, Shoulders, Triceps

-

Warm up first, then warm up specific muscle group with a couple of lighter sets, then go into the workout....

-

CHEST

-

Flat Dumbbell bench press 3 sets (15,12,10)

-

Incline Dumbbell Flys 3 sets (12,12,10)

-

Chest press machine 3 sets (15,12,10)

-

Optional;

-

Dips, wide grip position, 3 sets of 10 or 12.

-

SHOULDERS

-

Seated dumbbell press 3 sets (15,12,10)

-

Upright Row 3 sets (15,12,10)

-

Lateral Raise 3 sets (15,12,10)

-

TRICEPS

-

Lying Triceps extension 3 sets (15,12,10)

-

Triceps press down 3 sets (12,12,10)

-

Workout 2 – Legs, Back, Biceps

-

Warm up first, then warm up specific muscle group with a couple of lighter sets, then go into the workout....

-

LEGS

-

Squat 3 sets (10, 10, 10)

-

Lunges 3 sets (12,12,10)

-

Deadlift 3 sets (15,12,10)

-

BACK

-

Chin-ups 3 sets (10,10,10) – either with assistance machine or using own bodyweight

-

Lat pull down to chest, medium grip, 3 sets (15,12,10)

-

Seated Row, narrow handle, 3 sets (15,12,10)

-

BICEPS

-

Standing barbell curls 3 sets (15,12,10)

-

Seated Dumbbell curls 3 sets (12,12,10)

- -

Back

- -
- -
- - -
- -

H&F Y7&8

- -
- -

Training for years 7 & 8 should be based around aerobic activity, however there are some exercises that can be undertaken using bodyweight as resistance.

-

As a minimum you should be doing at least 30 minutes of Aerobic activity as a starter (bike, row, run, cross-train, power walk!). Try doing between 5 and 10 minutes on each, which makes the time go faster. You should get into the habit of recording what you do in those 5-10 minutes: how far you went, what the resistance was set on, how many calories you burned, etc. It'll give you a target each time you do your workout.

-

The exercises

-

These can done as a circuit, repeat the circuit 3 times.

-
    -
  • Bodyweight squats or swiss ball squats, 12 reps
  • -
  • Lunges, 12 reps
  • -
  • Step-ups onto a reebok step, 20 reps
  • -
  • Push-ups, 12 reps
  • -
  • Bench dips, 12 reps
  • -
  • Crunches, 12 reps
  • -
- -

Back

- -
- -
- - -
- -

H&F Y9&10

- -
- -

Whole Body Workout – Legs, Back, Chest, Shoulders, Triceps, Biceps

-

Warm up first, then go into the workout…

-

Do this at lease twice a week, along with some cardio training or in game situations.

-

LEGS

-

Squat 2 sets (12,10)

-

Lunges 2 sets (12,10)

-

Deadlift 2 sets (12,10)

-

BACK

-

Chin-ups 2 sets (10,10) – either with assistance machine or using own bodyweight

-

Lat pull down to chest, medium grip, 2 sets (12,10)

-

Seated Row, narrow handle, 2 sets (12,10)

-

CHEST

-

Flat Dumbbell bench press 2 sets (12,10)

-

Incline Dumbbell Flys 2 sets (12,10)

-

Chest press machine 2 sets (12,10)

-

Optional:

-

Dips, wide grip position, 2 sets of 10 or 12.

-

SHOULDERS

-

Seated dumbbell press 2 sets (12,10)

-

Upright Row 2 sets (12,10)

-

Lateral Raise 2 sets (12,10)

-

TRICEPS

-

Lying Triceps extension 2 sets (12,10)

-

Triceps press down 2 sets (12,10)

-

BICEPS

-

Standing barbell curls 2 sets (12,10)

-

Seated Dumbbell curls 2 sets (12,10)

- -
- -
- - -
- -

H&F Y11,12&13

- -
- -

Workout 1 (Monday) - Upper body

-

Flat Dumbbell (DB) Bench press 3x6 (this means 3 sets of 6 reps)

-

Barbell Row 3x6

-

Incline Barbell (BB) bench press 2x10

-

Lat Pull down 2x10

-

Seated DB shoulder press 2x10

-

Barbell curl 2x10

-

Workout 2 (Tuesday) - Lower body

-

Squat 3x6

-

Good morning 3x6

-

Leg extension 2x10

-

Seated calf raise 3x6

-

Workout 3 (Thursday) - Upper body

-

Incline DB press 3x6

-

Pull up 3x6

-

Flat BB bench 2x10

-

Cable row 2x10

-

Seated shoulder press 2x10

-

Barbell curl 2x10

-

Close grip bench press 2x10

-

Workout 4 (Friday or Saturday) - Lower body

-

Dead lift 3x6

-

Lunges 3x6

-

Leg curl 2x10

-

Standing calf raise 3x10

- -

Back

- -
- -
- - -
- -

H&F MGT Legs

- -
- -

Basic Leg workout

-
    -
  • Warm-up: Stationary bike 3-5 minutes
  • -
  • Squat 3 sets - 15, 12, 10 increasing weight with each set
  • -
  • Leg Extension 3 sets - 15, 12, 10 increasing weight with each set
  • -
  • Lunges holding Dumbbells 2 sets - 12, 10 increasing weight each set
  • -
  • Leg Curl machine 3 sets - 15, 12, 10 increasing weight with each
  • -
  • Deadlift 3 sets - 15, 12, 10 increasing weight with each set
  • -
  • Step-ups holding dumbbells 3 sets - 10, 10, 10
  • -
-

Super-set Leg workout

-
    -
  • Warm-up: Stationary bike 3-5 minutes, then 2 sets of bodyweight squats, 15-20 reps
  • -
  • Leg Extension, 12 reps, then Squat, 12 reps, with no rest in between sets
  • -
  • Repeat three times, set number 2 increase weight and perform 10 reps, same for set number 3.
  • -
  • Leg Curl, 12 reps, then Deadlift, 12 reps, with no rest in between sets
  • -
  • Repeat three times, set number 2 increase weight and perform 10 reps, same for set number 3.
  • -
- -

Back

- -
- -
- - -
- -

H&F MGT Back

- -
- -

Basic Back Workout

-

Warm-up: Rower 3-5 minutes

-

Chin-ups 3 sets - 10, 10, 10 reverse grip. Change to overhand grip and wider hand position to increase difficulty.

-

Seated Rows 3 sets - 15, 12, 10 increasing weight with each set

-

Lat Pull-downs 3 sets - 15, 12, 10 increasing weight each set

-

Dumbbell pullovers 3 sets - 15, 12, 10 increasing weight with each

-

Back extensions using Swiss Ball 3 sets - 10, 10, 10 increasing weight with each set

- -

Back

- -
- -
- - -
- -

H&F Y9&10

- -
- -

Basic Chest Workout

-

Warm-up : Rower 3-5 minutes

-

Chest Press machine 3 sets (15,12,10). Increase weight with each set.

-

Dumbbell Bench press (flat or incline) 3 sets. (15,12,10). Increase weight with each set.

-

Parallel Bar Dips 3 sets (10,10,10)

-

Flys (flat or incline) 3 sets (15, 12, 10). Increase weight with each set.

- -

Back

- -
- -
- - -
- -

H&F Y9&10

- -
- -

Basic Shoulder Workout

-

Warm-up : Rower 3-5 minutes

-

Standing Barbell Shoulder Press 3 sets (15,12,10). Increase weight with each set.

-

Seated Dumbbell Shoulder press 3 sets. (15,12,10). Increase weight with each set.

-

Lateral Raise 3 sets (10,10,10)

-

Upright Row 3 sets (15, 12, 10). Increase weight with each set.

- -

Back

- -
- -
- - -
- -

H&F Y9&10

- -
- -

Basic Arm Routine

-

Warm-up : 3-5 minutes on Rower

-

Triceps

-

Parallel Bar Triceps Dips 3 sets (10,10,10).

-

Lying Dumbbell Triceps Extension 3 sets (15,12,10). Increase weight with each set.

-

Close grip machine Bench Press 3 sets (15,12,10). Increase weight with each set.

-

Biceps

-

Standing Barbell Curls 3 sets (15,12,10). Increase weight with each set.

-

Seated Dumbbell Curls 3 sets (15,12,10). Increase weight with each set.

-

Chin-ups 3 sets (10,10,10).

- -

Back

- -
- -
- - -
- -

Super Seven Strength

- -
- -

It’s absolutely essential you warm up first, 5/10 mins of light CV, then low weight reps until thoroughly warmed up.

-
    -
  1. Squats - 4 sets (heavy one week, moderate the next). 15/12/12/10 reps (moderate week, bodyweight x 20 reps, 3 sets.)
  2. -
  3. Lunges - 3 sets. 8/8/8 reps on each leg.
  4. -
  5. Deadlifts - 3 sets. 15/12/10 reps
  6. -
  7. Pullups - 2 sets, to failure. Aim for 10, then 5.
  8. -
  9. Bent over Rows - 2 sets. 12/10.
  10. -
  11. Bench Press - 3 sets. 12/10/8
  12. -
  13. Core - 3 sets of, swiss-ball roll-outs x 12/plank 45secs/supermans x 10
  14. -
-

If you can make the reps easily then increase the weight. The last couple of reps should be difficult/almost failure. Try to do this at least twice a week (Mon & Fri). Record what you do.

-

Forget the beach exercises (arm training!) until you've completed the above routine. Biceps and Triceps are already being used doing the above moves.

-

Back

- -
- -
- - - -
- -

H&F Aerobic Training

- -
- - -

What is Aerobic Training?

-

Also known as cardiovascular exercise, it is any sustained, rhythmic activity that involves large muscle groups. Aerobic exercise makes the lungs work harder as the body’s need for oxygen is increased.

-

What are the benefits of aerobic exercise?

-

There are numerous benefits for health and general well being to be gained from regular cardiovascular exercise:

-
    -
  • Increased energy levels
  • -
  • Reduced stress and improved mental health (due to the release of endorphins in the brain)
  • -
  • Increased heart and lung efficiency
  • -
  • Reduced blood pressure, resting heart rate and risk of stroke or heart attack
  • -
-

Does aerobic exercise aid weight loss?

-

Weight is lost by creating a calorie deficit, burning more calories than you take in, so undertaking activities that burn large amounts of calories is an excellent accompaniment to a calorie controlled diet to help shift those unwanted pounds.

-

For example, half an hour of low paced jogging can burn around 300 calories. This can make a substantial contribution towards achieving the necessary calorie deficit to lose weight, or alternatively it can earn you a bar of chocolate that you feel less guilty about eating.

-

Aerobic exercises: At home

-

It is not essential to join a gym or to go out in the middle of winter to get an aerobic workout. There are a number of exercises that you can do in the privacy of your own home.

-

The cheapest options being putting on your favourite CD and dancing around the living room or giving the house a vigorous clean.

-

There is also an ever increasing array of affordable home fitness products available, such as steps, skipping ropes (remember to put your breakables a safe distance away), dance mats that you can use with your games console and exercise videos so that you can workout with your favourite celebrity.

-

Aerobic exercises: Outdoors

-

Even taking a few extra brisk walks can be enough to improve fitness and receive the benefits of aerobic exercise, just as long as you are working hard enough that your heart rate is increased and you are breathing faster.

-

Running, jogging or going out for a bike ride when the weather’s nice are all good forms of aerobic exercise.

-

Pretty much any exercise is better than no exercise at all, however, team sports are often less effective for developing aerobic fitness as while they involve periods where large amounts of energy is expended, these are often surrounded by periods of activity where the heart rate is allowed to drop.

-

The real benefits of aerobic exercise come from constant movement.

-

Aerobic exercises: Down the gym (or the TDA Fitness suite!)

-

Your local gym will provide a wide variety of aerobic options, such as treadmills, cross trainers, exercise bikes, stair masters, rowing and ski machines so that you can just switch on and get started with your workout. It can be a good idea to diversify between different machines and different speeds/levels of resistance as your body can get used to a certain routine and after a number of sessions the same routine will not work your heart and lungs as much as it once did.

-

For those who prefer to work out as part of a group, many gyms provide classes, such as various forms of dance, body pump, body combat and step aerobics with a trained instructor to ensure that you get the most out of your workout.

-

If you have access to a pool, swimming is also a very effective cardiovascular activity. As it is very low impact it is often suitable for people who have had injuries or problems with muscles or joints.

-

How often to train?

-

For good cardiovascular fitness it is generally recommended to exercise 3 to 5 times a week and for 30-60 minutes, not including warming up at the start and cooling down at the end.

-

The main thing is to ensure that your heart and lungs are worked hard enough and for long enough to gain the benefits of aerobic exercise but not so long that you run the risk of injury. To check whether you are working out at the correct intensity, you should be out of breath but still capable of speaking.

-

It is important to start slowly. If you have been inactive for some time, don’t throw on your trainers and set off on a ten mile run.

-

If a half an hour session feels like too much, start with 10 minute sessions for the first week then increase that to 15 or 20 minute sessions the next week and so on until you feel comfortable exercising for longer.

-

Make sure that you listen to your body. It’s ok for muscles to be tired, but if they or your joints start to feel sore or breathing becomes uncomfortable slow down or stop to ensure that you are in a fit state for your next session.

- -

Resources

- - - -
-
-

Are you sure you want to open this resource?

-

This action can use data, and may not work on some Android devices.

-
- - -
-
-
-
-
-

Are you sure you want to open this resource?

-

This action can use data, and may not work on some Android devices.

-
- - -
-
-
-
-
-

Disabled

- -

This external resource has been removed since it no longer exists. This button, along with this message, will be completely removed in a future update. Sorry for the inconvenience.

- -
- - -
-
-
- -
- -
- Back -
-
- - -
- -

Training Zones

- -
- Training Zones -
- Close - Training Zones - -
- -

The Energy Efficient zone 60-70%: Training within this zone develops basic endurance and aerobic capacity. All easy recovery running should be completed at a maximum of 70%. Another advantage to running in this zone is that while you are happily fat burning you may lose weight and you will be allowing your muscles to re-energise with glycogen, which has been expended during those faster paced workouts.

-

The Aerobic zone 70-80%: Training in this zone will develop your cardiovascular system. The body's ability to transport oxygen to, and carbon dioxide away from, the working muscles can be developed and improved. As you become fitter and stronger from training in this zone it will be possible to run some of your long weekend runs at up to 75%, so getting the benefits of some fat burning and improved aerobic capacity.

-

The Anaerobic Zone 80-90%: Training in this zone will develop your lactic acid system. In this zone, your individual anaerobic threshold (AT) is found - sometimes referred to the point of deflection (POD). During these heart rates, the amount of fat being utilised as the main source of energy is greatly reduced and glycogen stored in the muscle is predominantly used. One of the by-products of burning this glycogen is lactic acid. There is a point at which the body can no longer remove the lactic acid from the working muscles quickly enough. This is your anaerobic threshold (AT). Through the correct training, it is possible to delay the AT by being able to increase your ability to deal with the lactic acid for a longer period of time or by pushing the AT higher.

-

The Red-line Zone 90-100%: Training in this zone will only be possible for short periods. It effectively trains your fast twitch muscle fibres and helps to develop speed. This zone is reserved for interval running and only the very fit are able to train effectively within this zone.

- -

Back

- -
- -
- - -
- -

Fitness Testing

- -
-

This test is designed to measure your cardiovascular endurance

-

Using a 12 inch high bench (or a similar sized stair in your house), step on and off for 3 minutes.

-

Step up with one foot and then the other. Step down with one foot followed by the other foot.

-

Try to maintain a steady four beat cycle. It's easy to maintain if you say "up, up, down, down".

-

Go at a steady and consistent pace.

-

At the end of 3 minutes, remain standing and immediately check your heart rate by taking your pulse…

- - Fitness Testing Boys Table -
- Close - Fitness Testing Boys Table - -
- - Fitness Testing Girls Table -
- Close - Fitness Testing Girls Table - -
- -

The Aerobic zone 70-80%: Training in this zone will develop your cardiovascular system. The body's ability to transport oxygen to, and carbon dioxide away from, the working muscles can be developed and improved. As you become fitter and stronger from training in this zone it will be possible to run some of your long weekend runs at up to 75%, so getting the benefits of some fat burning and improved aerobic capacity.

-

The Anaerobic Zone 80-90%: Training in this zone will develop your lactic acid system. In this zone, your individual anaerobic threshold (AT) is found - sometimes referred to the point of deflection (POD). During these heart rates, the amount of fat being utilised as the main source of energy is greatly reduced and glycogen stored in the muscle is predominantly used. One of the by-products of burning this glycogen is lactic acid. There is a point at which the body can no longer remove the lactic acid from the working muscles quickly enough. This is your anaerobic threshold (AT). Through the correct training, it is possible to delay the AT by being able to increase your ability to deal with the lactic acid for a longer period of time or by pushing the AT higher.

-

The Red-line Zone 90-100%: Training in this zone will only be possible for short periods. It effectively trains your fast twitch muscle fibres and helps to develop speed. This zone is reserved for interval running and only the very fit are able to train effectively within this zone.

- -

Back

- -
- -
- - -
- -

H&F Nutrition

- -
- - -

Introduction

-

There's SO much information on nutrition that I could fill this app with it! Here's what I'll do:

-
    -
  1. Cover the basics here, and
  2. -
  3. Provide the links for you to do some research for yourself.
  4. -
-

What YOU eat will literally shape your future. It won't be someone else putting food into your mouth. You won't be force fed food you don't want. It will be YOU eating, YOU making choices about what you eat, when you eat, how much you eat. What you eat is what you are. End of story. No myths, no fads, just YOUR choices.

-

teenweightwise.com

-

eatwell.gov.uk/agesandstages/teens

-

The basics…

-

If you want to get the balance of your diet right, use the eatwell plate. The eatwell plate makes healthy eating easier to understand by showing the types and proportions of foods we need to have a healthy and well balanced diet. The eatwell plate shows how much of what you eat should come from each food group. This includes everything you eat during the day, including snacks.

-

So, try to eat:

-
    -
  • Plenty of fruit and vegetables
  • -
  • Plenty of bread, rice, potatoes, pasta and other starchy foods – choose wholegrain varieties whenever you can
  • -
  • Some milk and dairy foods
  • -
  • Some meat, fish, eggs, beans and other non-dairy sources of protein
  • -
  • Just a small amount of foods and drinks high in fat and/or sugar
  • -
  • Look at the eatwell plate to see how much of your food should come from each food group. You don’t need to get the balance right at every meal. But try to get it right over time such as a whole day or week.
  • -
-

Try to choose options that are lower in fat, salt and sugar when you can.

-

The eatwell plate is consistent with the Government’s Eight tips for eating well, published in October 2005, which are:

-
    -
  1. Base your meals on starchy foods
  2. -
  3. Eat lots of fruit and veg
  4. -
  5. Eat more fish
  6. -
  7. Cut down on saturated fat and sugar
  8. -
  9. Try to eat less salt – no more than 6g a day
  10. -
  11. Get active and try to be a healthy weight
  12. -
  13. Drink plenty of water
  14. -
  15. Don’t skip breakfast
  16. -
- -

Resources

- - - -
- -
- Back -
-
- - -
- -

Nutrition Food Labelling

- -
- - -

You're standing in a supermarket aisle looking at two similar products, trying to decide which to choose. You want to make the healthier choice but, as usual, you're in a hurry. Well, help is at hand.

-

A growing number of supermarkets and food manufacturers are using traffic light colours on the labels of some products to help you make your choice.

-

What do the traffic light colours mean?

-

If we want to eat a healthy diet, one of the key things we should be doing is trying to cut down on fat (especially saturated fat), salt and added sugars.

-

Food products with traffic light labels on the front of the pack show you at-a-glance if the food you are thinking about buying has high, medium or low amounts of fat, saturated fat, sugars and salt, helping you get a better balance.

-

In addition to traffic light colours you will also see the number of grams of fat, saturated fat, sugars and salt in what the manufacturer or retailer suggests as a 'serving' of the food.

-

So, if you see a red light on the front of the pack, you know the food is high in something we should be trying to cut down on. It's fine to have the food occasionally, or as a treat, but try to keep an eye on how often you choose these foods, or try eating them in smaller amounts.

-

If you see amber, you know the food isn't high or low in the nutrient, so this is an ok choice most of the time, but you might want to go for green for that nutrient some of the time.

-

Green means the food is low in that nutrient. The more green lights, the healthier the choice.

-

Many of the foods with traffic light colours that you see in the shops will have a mixture of red, amber and greens. So, when you're choosing between similar products, try to go for more greens and ambers, and fewer reds, if you want to make the healthier choice.

-

The traffic light colours will make it easier for you to compare products at-a-glance. The label also tells you how much of each nutrient is in a portion, so if two labels have similar colours you can compare these figures, and choose the one that is lower to make a healthier choice.

-

But remember, it's all about getting the overall balance of our diet right.

-

How do traffic light colours fit into a healthy diet?

-

If you want to choose a healthy diet, you should:

-
    -
  • base your meals on starchy foods such as wholegrain bread, pasta and rice
  • -
  • eat lots of fruit and vegetables, which means try to go for at least five portions of a variety every day
  • -
  • have some protein-rich foods such as meat, fish, pulses, milk and dairy foods
  • -
  • keep foods (and drinks) high in fat, especially saturated fat, sugars or salt to a minimum
  • -
-

Traffic light colours can help you get the balance right by helping you to choose between products and keep a check on the amount of foods high in fat, sugars and salt that you are eating. You can use the signpost labelling to help put you in control, so keep a look out for the colours on the front of food packs.

-

Making the healthy choice isn't always easy – sometimes there seems to be so much to remember. But with traffic light colours you just need to go for as many greens as you can and avoid choosing too many reds. This way you'll know you'll be making a healthier choice.

-

You should also try to remember that although some products may contain a lot of sugars, they can be healthier choices if they contain lots of fruit. You can tell this by checking the ingredients list; the higher up the ingredients list the more fruit there is.

-

Check it out

-

Some products you might have thought were healthy choices could qualify for red lights.

-

Try comparing the fat and salt content of your favourite sandwich with other sandwiches. For example, a Waitrose poached salmon and cucumber sandwich qualifies for three green lights. Does your sandwich?

-

What do the different traffic lights look like?

-

Although the traffic light label designs may look different, you can still compare these foods because the companies are all using the Food Standards Agency guidelines. So when, for example, you are deciding between two pizzas, check out the colours to make a healthier choice.

-

Which foods have traffic light colours on them?

-

All of the manufacturers and retailers shown above are using traffic light labelling on some or all of their products, and the Agency is also in discussions with other companies that are considering using it.

-

Awareness of traffic light labelling is also on the increase in the service sector, with train companies such as GNER and Virgin, Roadchef motorway service stations, and shoppers websites such as Mysupermarket.com all using the Agency's recommended approach.

-

The Agency recommends that traffic light colours are used on processed convenience foods such as ready meals, pizzas, sausages, burgers, pies, sandwiches and breakfast cereals.

-

This is because people have told us that they find it difficult to understand the nutritional content of these sorts of foods.

-

When will the traffic light colours be in other supermarkets and in my local shop?

-

The FSA is continuing to encourage as many supermarkets, manufacturers and service providers as possible to use this approach.

-

If you'd like to see them in your supermarket, or on your favourite products, why not contact the supermarket or manufacturer yourself?

-

Please let us know what you think of traffic light labelling by completing our feedback form available at the link below.

-

How can I get more nutritional information?

-

The traffic light colours on the front of food packs are a quick and easy guide, but when you have time, and if you are particularly interested in finding out more, you can still check the back of packs for more information.

-

On the back of some food packs, you will find the nutrition panel, Guideline Daily Amounts information and the ingredients list.

-

Nutrition panel

-

You often see this panel on the back of food packs. It gives the nutritional breakdown of the food.

-

This is the sort of information you might see: the amount of energy, protein, carbohydrates, sugars, fat, dietary fibre and sodium.

-

You can use this information to help you make healthier choices.

-

Guideline Daily Amounts

- GDA -
- Close - GDA - -

An example of a GDA. Source

- -
-

Guideline Daily Amounts (GDAs) were developed by food manufacturers and retailers and you can find out more by visiting the IGD website. IGD is a food and grocery industry research organisation.

-

Ingredients list

-

To get a feel for whether a product is high in a certain ingredient such as fat, salt or added sugars, you might need to look at the ingredients list.

-

Ingredients lists always start with the biggest ingredient first and are listed in descending order of weight at the time they were used to make the food

- -
- -
- Back -
-
- - -
- -

Nutrition Classification

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CarbohydratesEnergy can be stored in the body in the form of carbohydrates and this is particularly important for endurance performers, who may not be able to restock their energy stores adequately while they are competing. Carbohydrates are high in glucose and enter the blood. Excess glucose is stored as glycogen in the liver and muscles. Extra glucose is not wasted, but converted into glycogen or fat and stored.Cereals, All wholegrain foods, Potato, Rice, Vegetables, Fruits, Beans, Pasta.
ProteinsIt contributes to the development and growth of hormones and haemoglobin in the blood, both of which are essential for those involved in sport or regular physical activity. Protein is necessary for the growth and repair of body tissues. It is also a relatively minor source of energy (10%).Meat, Fish, Eggs, Milk, Cheese, Cereals, Nuts.
FatsThere are many forms of fat in the body and it supplies around 70% of our energy requirements. Fat supplies energy (calories) that can either be used immediately or stored for future use. Although fat is the body’s preferred energy source, it also uses energy in the form of stored carbohydrate (glycogen) for intensive burst of energy. If we consume an excessive amount of fat, it is stored in the body tissues and causes us to become overweight. In order to avoid this, dieticians recommend that we should not consume more than ⅓rd of our daily nutritional needs in the form of fat.

Saturated – meat, burgers, sausages, butter, cheese.

-

Hydrogenated – margarine, biscuits, cakes, puddings, chocolate.

-

Polyunsaturated / Omega 6 – vegetable oils, nuts, seeds

-

Omega 3 – Oily fish, walnuts, soya beans, sweet potatoes

-

Monounsaturated – Olive oil, olives, avocados, nuts, seeds, rapeseed oil

FibreDietary fibre comprises the edible parts of plants that are not broken down and absorbed in the small intestine. It does not contain any nutrients. It therefore adds bulk to our food without adding extra kilojoules. Fibre regulates the digestive system.Whole-grain and high-fibre breakfast cereals and bread, fruit and vegetables.
MineralsMinerals are required by the body for a variety of functions including the formation of bones & teeth, as essential constituents of body fluids & tissues, components of enzyme systems, and nerve function.

Calcium for bones and teeth – milk, cheese, dairy products.

-

Magnesium for energy metabolism – dark green leafy vegetables, grains and nuts.

-

Sodium for regulating body fluids - salted foods, crisps, canned foods.

-

Potassium for water and electrolyte balance – dried fruits, bananas, berries, veg, milk.

-

Iron for formation of haemoglobin/oxygen transport – spinach, dark green veg, liver, red meat, nuts, peas

-

Iodine for hormone formation – salt water fish, milk.

Vitamins

Vitamins are chemical compounds found in the food we eat. Our bodies cannot make vitamins so must take them from our food. Vitamins perform the following functions: aiding growth, increasing resistance to infection, regulating some body functions such as good vision, and helping the metabolism of certain foods.

-

There are two main groups of Vitamins:

-
    -
  1. FAT Soluble Vitamins – Vitamins A, D, & K, they can be stored in our body.
  2. -
  3. WATER Soluble Vitamins – Vitamins C & B, They cannot be stored in the body.
  4. -

Vitamin A – Liver, whole milk, cheese, butter, carrots, leafy veg.

-

Vitamin D – Oily fish, eggs, butter, and meat.

-

Vitamin K – most plant and animal sources, also made by bacteria in the gut.

-

Vitamin C – plant sources, fresh milk, liver.

-

Vitamin B1 – Whole grains, nuts, meat.

-

Vitamin B2 – milk, eggs, breakfast cereals, liver, green veg.

-

Niacin – meat.

-

Vitamin B6 – beef, fish, poultry, eggs, whole grains, some veg.

-

Vitamin B12 – milk, meat, eggs.

WaterWater makes up 70% of the human body. It is essential for the correct functioning of virtually all living cells. Water has many functions: it provides the medium in which most reactions in the body occur, it acts as a lubricant for joints and eyes, and it helps regulate body temperature. The amount of water we drink varies from person to person, depending on age, time of year, climatic conditions, diet, the amount of physical activity we do. Dehydration is common amongst athletes, especially in hot climates, or at altitude. As little as a 2% loss of bodyweight can result in impaired responses and performance. Water replacement is essential before, during and after exercise.

Tap water is suitable for replacing lost fluid following mild or moderate exercise.

-

Isotonic drinks are more suitable after vigorous or prolonged exercise.

- -
- -
- Back -
-
- - -
- -

H&F CC Core Stability

- -
- - -

Core Stability

-

The aim of core stability training is to effectively recruit the trunk musculature and then learn to control the position of the lumbar spine during dynamic movements. The information presented on this page is based on an article written by Raphael Brandon that was first published in Peak Performance.

-

The Muscles

-

The deep trunk muscles, Transversus Abdominis (TA), multifidus (MF), Internal Oblique (IO), paraspinal, pelvic floor, are key to the active support of the lumbar spine. The co-contraction of these muscles produce forces via the "theracolumbar fascia" (TLF) and the "intra-abdominal pressure" (IAP) mechanism which stabilise the lumbar spine, and the paraspinal and MF muscles act directly to resist the forces acting on the lumbar spine.

-

It is not just the recruitment of these deep-trunk muscles, but how they are recruited that is important. Hodges and Richardson (1996) showed that the co-contraction of the TA and MF muscles occurred prior to any movement of the limbs. This suggests that these muscles anticipate dynamic forces that may act on the lumbar spine and stabilise the area prior to any movement. Hodges and Richardson showed that the timing of co-ordination of these muscles was very significant.

-

Training

-

Having identified the key muscles and how they act, the next step is to establish how best to train these muscles. As with any type of strength and conditioning training, the training protocol for improving the function of the deep-trunk muscles must be specific to the task required. This specificity of training must take into account the type of contraction, the muscle fibre type and the anatomical position required. By definition, the deep-trunk muscles act as "stabilisers" and are not involved in producing movements, but instead involve static, or isometric, contractions. Furthermore, they must act as stabilisers continuously throughout everyday activities as well as fitness and sport activities, and so require very good endurance of low-level forces. These muscles do not need to be very strong, but they must be correctly coordinated and capable of working continuously. In addition, we want these stabiliser muscles to act by holding the lumbar spine in the neutral position, which is the correct alignment of the pelvis that allows for the natural 'S' curve of the spine. These characteristics underpin the following deep-trunk muscle training program.

-

The basics

-

Core-stability training begins with learning to co-contract the TA and MF muscles effectively as this has been identified as key to the lumbar-support mechanism. To perform the TA and MF co-contraction, you must perform the "abdominal hollowing" technique with the spine in the neutral position.

-

To do this use the following guidelines:

-
    -
  • Start by lying on your back with knees bent
  • -
  • Your lumbar spine should be neither arched up nor flattened against the floor, but aligned normally with a small gap between the floor and your back. This is the "neutral" lumbar position you should learn to achieve
  • -
  • Breathe in deeply and relax all your stomach muscles
  • -
  • Breathe out and, as you do so, draw your lower abdomen inwards as if your belly button is going back towards the floor. Pilates teachers describe this as "zipping up", as if you are fastening up a tight pair of jeans
  • -
  • Hold the contraction for 10 seconds and stay relaxed, allowing yourself to breathe in and out as you hold the tension in your lower stomach area
  • -
  • Repeat 5-10 times
  • -
-

It is vital that you perform this abdominal hollowing exercise correctly otherwise you will not recruit the TA and MF effectively. Bear in mind the following points:

-
    -
  • Visualise the deep abdominal muscles as a corset that wraps round the abdomen
  • -
  • Place one hand above the umbilicus (belly button) and one below
  • -
  • Slowly draw in the lower abdomen, below the umbilicus, without drawing in the upper abdomen
  • -
  • Hold the contraction whilst breathing normally
  • -
  • Aim for a 10 second contraction, repeating it 10 times
  • -
  • Do not let the whole stomach tense up or your upper abdominals bulge outwards, as this means you have cheated by using the large rectus abdominus muscle (the six-pack) instead of TA
  • -
  • Do not brace your TA muscle too hard; just a gentle contraction is enough. Remember it's endurance not max strength your are trying to improve
  • -
  • Do not tilt your pelvis nor flatten your back, as this means you have lost the neutral position you are trying to learn to stabilise
  • -
  • Do not hold your breath, as this means you are not relaxed. You must learn to breathe normally and maintain the co-contraction of TA and MF
  • -
  • Use your fingers for biofeedback on either side of your lower abdomen (below the umbilicus) to feel the tension in the TA muscle
  • -
-

Once you have mastered the abdominal hollowing lying on your back, practice it lying on your front, four-point kneeling, sitting and standing. In each position, get your lumbar spine into neutral before you perform the hollowing movement.

- -
- -
- Back -
-
- - -
- -

H&F CC Exercises

- -
- - -

The next step

-

Having learned to recruit the TA and MF muscles correctly in various positions, which can take anything from one session to one month or more, it is time to move onto simple core stability exercises. These exercises may also involve the oblique muscles, other lumbar muscles and gluteals to assist the TA and MF in maintaining the lumbar spine in a stable neutral position.

-

Lying leg lift stabilisation

-
    -
  • Lying on your back with your knees bent
  • -
  • Ensure your back is in neutral
  • -
  • Place your hands on your hips for biofeedback
  • -
  • Breathe in and relax
  • -
  • Breathe out and, as you do so, perform the abdominal hollowing or zipping-up action
  • -
  • Once you have established some TA tension, slowly slide your left leg out along the floor until it is straight and then slide it back
  • -
  • Your back should not have moved, and your pelvis should not have tilted as you performed this action
  • -
  • If your back or pelvis moved, you did not achieve the correct stability
  • -
  • Repeat for the other side 10 times each leg
  • -
  • Variations include the same exercise with knee lifts up and knee drops out to the side. Again, the aim is to retain a stable lumbar spine in the neutral position as the legs move.
  • -
  • he waiter's bow
  • -
  • Stand up with good posture, knees soft, lumbar spine in neutral, head up and shoulders back and relaxed
  • -
  • Breathe in and relax
  • -
  • Breathe out and as you do so perform the abdominal hollowing action
  • -
  • Keeping the tension, slowly lean forward from the hips 20° and stop, like a waiter's bow, keeping your back completely straight and long as you lean
  • -
  • Hold the lean position for 10 seconds - you will feel your TA and MF supporting you if you hold the correct position
  • -
  • Keeping the tension and the alignment, slowly return to your start position
  • -
  • Repeat 10 times
  • -
-

These exercises are two examples of learning how to keep the spine in neutral, using slow and controlled static contractions of the trunk stabiliser muscles. Notice how technique is vital and the aim is to build up the time you are able to maintain good stability.

-

Getting functional

-

The ultimate aim of core stability training is to ensure the deep trunk muscles are working correctly to control the lumbar spine during dynamic movements, e.g. lifting a heavy box or running. Therefore, it is important that once you have achieved proficiency of the simple core exercises, you must progress on to achieving stability during more functional movements. Try the following two exercises.

-

The lunge

-
    -
  • Stand with feet hip width apart in front of a mirror
  • -
  • Ensure your lumbar spine is in neutral and your back is tall with your shoulders back and head up
  • -
  • Lunge forward and bend your knee only halfway down
  • -
  • Ensure that your front knee is in line with your toes and your back has remained upright with your lumbar spine in neutral and your hips level
  • -
  • Push back up, initiating the movement by pushing down into the floor with your front foot
  • -
  • The force from your legs should bring you back up quickly and easily to your start position
  • -
  • Your back should have remained totally still and your hips level as you performed the push back
  • -
-

Many people wrongly initiate the up movement by pulling their heads and shoulders back first. This extends the lumbar spine, losing the neutral position. Others have problems keeping their pelvis level while performing the lunge. You must learn to use your deep trunk and gluteal muscles to hold your lumbar spine in neutral and pelvis level as you perform the movement up and down. The movement should only come from the leg muscles.

-

The Press-up

-
    -
  • Start from your knees, even if this means it is easy for your upper body, to learn the correct technique
  • -
  • Your hands should be slightly wider than your shoulders and your head must be in front of your hands
  • -
  • Lift your hips so that there is a straight line from your knees through your pelvis and lower back, through your shoulders and all the way to your head
  • -
  • Ensure your lumbar spine is in neutral, using a mirror or a partner/trainer to help you
  • -
  • To maintain a neutral spine and a straight back during the exercise, the trunk muscles must provide active support
  • -
  • Slowly lower down, bending your arms all the way to the floor. Keep your head still with your neck straight relative to your back
  • -
  • Push up, initiating the movement by pressing down into the floor with your hands
  • -
  • Your back should remain straight and your lumbar spine in neutral throughout the exercise.
  • -
-

These two exercises enable you to learn core stability while performing dynamic movements. By reducing the resistance i.e. doing only half lunges and knee press ups, your are able to focus on the trunk stabilisers and achieving perfect technique rather than working the major muscle groups. The whole essence of core stability training is quality of movement and relaxation. The more you practice, the easier it becomes until you can control your lumbar stability at all times and during complex movements.

- -
- -
- Back -
-
- - -
- -

H&F CC Static & Dynamic Core

- -
- - -

Static Floor Exercises

- Plank -

Hold a straight body position, supported on elbows and toes. Brace the abdominals and maintain a straight body line through feet, hips and head.

- Side plank -

Lie on one side, ensuring the top hip is above the bottom hip. Push up until there is a straight body line through feet, hips and head. Keep the elbow under the shoulder. Lower under control and repeat on opposite side.

- Bridge -

Lie on the floor with your knees bent and feet flat on the floor. Squeeze your gluteals and then push your hips up until there is a straight line through knee and hip to upper body and shoulders remain on the floor.

- Superman -

Kneel on the floor and place your hands below your shoulders and knees below your hips. Extend right leg back and the left arm forward. Maintain a straight body line through extended leg, body and extended arm. Repeat with opposite limbs

-

Dynamic Floor Exercises

- Side lying hip abduction -

Lie on your side with your top hip above the lower hip. Brace the abdominals and lift the top leg slowly up and down.

- Oblique crunch -

Lie on your back with your right ankle resting on your left knee. Right arm is placed on the floor out to the side. Keeping the right shoulder down, curl the left shoulder up to the right knee. Repeat with opposite limbs.

- Straight leg raise -

Lie on your back with knees bent. Brace your abdominals and lift your legs up straight in the air to an angle of 45 degrees keeping you back on the ground. Keeping one leg in the air, slowly lower the other down to the floor. Only go as far as you can until you feel the lumbar spine start to move. Keep bracing the abdominals and then lift the leg slowly back up. Repeat with the other leg.

- Lying windscreen wipers -

Lie on your back with arms out to the sides. Lift your legs straight up in the air until the hips are at 90 degrees. Keeping your legs straight and maintaining the hip angle, rotate the legs to one side. Go as far as you can keeping your upper back and shoulders on the floor. Bring the legs to a halt, pull them back up to the start position and then over to the other side.

- -
- -
- Back -
-
- - -
- -

H&F How do I?

- -
- - -

I want to burn calories quickly…

-

Answer: Interval training. It doesn’t matter what you do, run, row, or jog on the spot. If you do these exercises at FULL pace (after a warm up) for 20 seconds, then have a 40 second rest, repeating this for up to 5 minutes, it will burn a huge amount of calories. The good thing about this type of training is that your metabolism is given a jump-start so it keeps burning calories for hours after you have finished.

-

I want a fast fitness workout…

-

Answer: Crossfit training. This type of training focuses on strength and endurance training and is scalable to your own fitness and ability level. It also burns lots of calories. For example, a favourite of mine is to do 5 pull-ups, 10 push-ups then 15 bodyweight squats, one after the other, no rest. Each time you complete this its one rep. The idea is that you do as many reps as you can in 10 minutes. If you can’t do the pull-ups then swap them for something like bench-dips or anything you can do.

-
-

Here are a few crossfit routines:

- -
-

How do I lose weight?

-

Answer: Eat sensibly, increase your activity. We all know when the food we eat is a ‘treat’ or something that’s ‘clean’. The difference between the two is our own motivation. If we have a goal or a beach holiday coming up its much easier to be strict with what we eat. The way I look at it is this; its MUCH easier to stay in shape than to GET in shape. Maintenance is the key to a healthy weight, once you get there. Fast answer; walk briskly when you walk, jog up the stairs, bike instead of getting a lift, say no to the second helping, and yes just once a week to treats… you get the picture.

-

So try crossfit and interval training as faster ways to increase your activity. If this is too intense then start with 10 minutes on the cross-trainer or bike. Get into the habit of doing this and you will see a difference in your health.

-

How do I get bigger?

-

Answer: Just wait a few months. If you train regularly and eat well you will grow stronger and as a result, bigger. Steer clear of eating junk and sugary foods, they will slow you down and lower your performance generally, compared to a balanced diet.

-

How do I tone my legs?

-

Answer: Squats, lunges, running, rowing and eating less fatty foods. Your tone/muscles will show up if the fat under your skin is low enough. The training will promote muscle development and the correct nutrition will create the definition that results in toned legs, or arms, shoulders and stomach. Toning your upper body can be achieved by doing push-ups and stomach crunches as a starting point.

- -
- -
- Back -
-
- - -
- -

Crossfit Routines

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Angie -
    -
  • 100 Pull-ups
  • -
  • 100 Push-ups
  • -
  • 100 Sit-ups
  • -
  • 100 Squats
  • -
-
For Time. Complete all reps of each exercise before moving to the next.
Barbara -
    -
  • 20 Pull-ups
  • -
  • 30 Push-ups
  • -
  • 40 Sit-ups
  • -
  • 50 Squats
  • -
-

Rest precisely three minutes between each round.

-
5 rounds, time each round.
Chelsea -
    -
  • 5 Pull-ups
  • -
  • 10 Push-ups
  • -
  • 15 Squats
  • -
-
Each min on the min for 30 min.
Cindy -
    -
  • 5 Pull-ups
  • -
  • 10 Push-ups
  • -
  • 15 Squats
  • -
-
As many rounds as possible in 20 min.
Fran -
    -
  • Thruster 95 lbs
  • -
  • Pull-ups
  • -
-
21-15-9 reps, for time.
Karen -
    -
  • Wall-ball 150 shots
  • -
-
For time.
Nancy -
    -
  • 400 meter run
  • -
  • Overhead squat 95 lbs x 15
  • -
-
5 rounds for time.
Kelly -
    -
  • Run 400 meters
  • -
  • 30 box jump, 24 inch box
  • -
  • 30 Wall ball shots, 20 pound ball
  • -
-
Five rounds for time.
Nicole -
    -
  • Run 400 meters
  • -
  • Max rep Pull-ups
  • -
-
As many rounds as possible in 20 minutes.
TDA 5 -

Five rounds of:

-
    -
  • 30 push-ups
  • -
  • 40 sit-ups
  • -
  • 50 Air Squats
  • -
-
For time.
Crossfit 25 -
    -
  • Sprint 100M
  • -
  • 25 push-ups
  • -
  • Sprint 100M
  • -
  • 25 crunches
  • -
  • Sprint 100M
  • -
  • 25 air Squats
  • -
  • Sprint 100
  • -
  • 25 burpees
  • -
-
Three rounds for time.
RSP -
    -
  • Run ½ mile (1 lap of back field)
  • -
  • 100 Air Squats
  • -
  • 50 push-ups
  • -
  • Run ½ mile
  • -
-
For time.
Filthy Fifty -
    -
  • 50 push-up
  • -
  • 50 squats
  • -
  • 50 crunches
  • -
  • 50 lunges
  • -
  • 50 burpees
  • -
-
For time.
Ten-minute Challenge -

One of the following:

-
    -
  • Max push-ups
  • -
  • Max Pull-ups
  • -
  • Air Squats
  • -
  • Burpees
  • -
-
Record score.
10-10-10 -

10 push-ups, 10-crunches, 10 air squats – 10 rounds of.

-

Set 10 cones, 10M apart, do 1st round at start cone then sprint to the next cone. Repeat. Sprint back from last cone.

-
Burpees for time -
    -
  • 100 burpees
  • -
-
For time.
- -

Back

- -
- -
- - -
- -

H&F Info

- -
- - -

Welcome

- -

Welcome to the TDA Health & Fitness mini-site. Here you will find information on the main aspects of Health and Fitness along with other resources. If you can't find what you want on here, or require further information, please e-mail Mr Hoffmann with suggestions or ideas.

-

Before you start on ANY fitness training program, remember: if you have any injuries, medical conditions or are not sure about what to do, ask a member of staff or check with your doctor that it's fine for you to train.

-

Warm-ups. You HAVE to do them, read the WARM-UP page first and INCLUDE one with every workout, run, row, team game, individual event. Make it a HABIT and it will go along way to help you stay injury-free.

- -

Acknowledgements

- -
    -
  • ‘G-Force’, the ultimate guide to you best body ever – Gunnar Peterson
  • -
  • ‘ABSolution’ – Shawn Phillips
  • -
  • ‘Mind Games’ – Jeff Grout & Sarah Perrin
  • -
-
-

Some information also provided by Mr Hoffmann.

- -
- -
- Back -
-
+
+ + +
+
+
+
+

Welcome to Thomas Deacon Academy's Sports Enrichment app! This app contains the full timetable for the after school sports enrichment as well other fitness information.

+

For more information about this app, see the website at georgegarside.com/apps/tda-enrichment/

+
+
+
+ + + - + \ No newline at end of file diff --git a/www/jquery.mobile-1.3.0/images/ajax-loader.gif b/www/jquery.mobile-1.3.0/images/ajax-loader.gif deleted file mode 100644 index fd1a189..0000000 Binary files a/www/jquery.mobile-1.3.0/images/ajax-loader.gif and /dev/null differ diff --git a/www/jquery.mobile-1.3.0/images/icons-18-black.png b/www/jquery.mobile-1.3.0/images/icons-18-black.png deleted file mode 100644 index 7916463..0000000 Binary files a/www/jquery.mobile-1.3.0/images/icons-18-black.png and /dev/null differ diff --git a/www/jquery.mobile-1.3.0/images/icons-18-white.png b/www/jquery.mobile-1.3.0/images/icons-18-white.png deleted file mode 100644 index 3419b81..0000000 Binary files a/www/jquery.mobile-1.3.0/images/icons-18-white.png and /dev/null differ diff --git a/www/jquery.mobile-1.3.0/images/icons-36-black.png b/www/jquery.mobile-1.3.0/images/icons-36-black.png deleted file mode 100644 index 043bfcd..0000000 Binary files a/www/jquery.mobile-1.3.0/images/icons-36-black.png and /dev/null differ diff --git a/www/jquery.mobile-1.3.0/images/icons-36-white.png b/www/jquery.mobile-1.3.0/images/icons-36-white.png deleted file mode 100644 index 12455c9..0000000 Binary files a/www/jquery.mobile-1.3.0/images/icons-36-white.png and /dev/null differ diff --git a/www/jquery.mobile-1.3.0/jquery.mobile-1.3.0.min.css b/www/jquery.mobile-1.3.0/jquery.mobile-1.3.0.min.css deleted file mode 100644 index 7c783e6..0000000 --- a/www/jquery.mobile-1.3.0/jquery.mobile-1.3.0.min.css +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery Mobile vGit Build: SHA1: caa77b258660731d663844fe7867aa2c3a107ab1 <> Date: Wed Feb 20 15:03:27 2013 -0500 jquerymobile.com | jquery.org/license !*/ -.ui-bar-a{border:1px solid #333;background:#111;color:#fff;font-weight:bold;text-shadow:0 -1px 0 #000;background-image:-webkit-gradient(linear,left top,left bottom,from( #3c3c3c ),to( #111 ));background-image:-webkit-linear-gradient( #3c3c3c,#111 );background-image:-moz-linear-gradient( #3c3c3c,#111 );background-image:-ms-linear-gradient( #3c3c3c,#111 );background-image:-o-linear-gradient( #3c3c3c,#111 );background-image:linear-gradient( #3c3c3c,#111 )}.ui-bar-a,.ui-bar-a input,.ui-bar-a select,.ui-bar-a textarea,.ui-bar-a button{font-family:Helvetica,Arial,sans-serif}.ui-bar-a .ui-link-inherit{color:#fff}.ui-bar-a a.ui-link{color:#7cc4e7;font-weight:bold}.ui-bar-a a.ui-link:visited{color:#2489ce}.ui-bar-a a.ui-link:hover{color:#2489ce}.ui-bar-a a.ui-link:active{color:#2489ce}.ui-body-a,.ui-overlay-a{border:1px solid #444;background:#222;color:#fff;text-shadow:0 1px 0 #111;font-weight:normal;background-image:-webkit-gradient(linear,left top,left bottom,from( #444 ),to( #222 ));background-image:-webkit-linear-gradient( #444,#222 );background-image:-moz-linear-gradient( #444,#222 );background-image:-ms-linear-gradient( #444,#222 );background-image:-o-linear-gradient( #444,#222 );background-image:linear-gradient( #444,#222 )}.ui-overlay-a{background-image:none;border-width:0}.ui-body-a,.ui-body-a input,.ui-body-a select,.ui-body-a textarea,.ui-body-a button{font-family:Helvetica,Arial,sans-serif}.ui-body-a .ui-link-inherit{color:#fff}.ui-body-a .ui-link{color:#2489ce;font-weight:bold}.ui-body-a .ui-link:visited{color:#2489ce}.ui-body-a .ui-link:hover{color:#2489ce}.ui-body-a .ui-link:active{color:#2489ce}.ui-btn-up-a{border:1px solid #111;background:#333;font-weight:bold;color:#fff;text-shadow:0 1px 0 #111;background-image:-webkit-gradient(linear,left top,left bottom,from( #444 ),to( #2d2d2d ));background-image:-webkit-linear-gradient( #444,#2d2d2d );background-image:-moz-linear-gradient( #444,#2d2d2d );background-image:-ms-linear-gradient( #444,#2d2d2d );background-image:-o-linear-gradient( #444,#2d2d2d );background-image:linear-gradient( #444,#2d2d2d )}.ui-btn-up-a:visited,.ui-btn-up-a a.ui-link-inherit{color:#fff}.ui-btn-hover-a{border:1px solid #000;background:#444;font-weight:bold;color:#fff;text-shadow:0 1px 0 #111;background-image:-webkit-gradient(linear,left top,left bottom,from( #555 ),to( #383838 ));background-image:-webkit-linear-gradient( #555,#383838 );background-image:-moz-linear-gradient( #555,#383838 );background-image:-ms-linear-gradient( #555,#383838 );background-image:-o-linear-gradient( #555,#383838 );background-image:linear-gradient( #555,#383838 )}.ui-btn-hover-a:visited,.ui-btn-hover-a:hover,.ui-btn-hover-a a.ui-link-inherit{color:#fff}.ui-btn-down-a{border:1px solid #000;background:#222;font-weight:bold;color:#fff;text-shadow:0 1px 0 #111;background-image:-webkit-gradient(linear,left top,left bottom,from( #202020 ),to( #2c2c2c ));background-image:-webkit-linear-gradient( #202020,#2c2c2c );background-image:-moz-linear-gradient( #202020,#2c2c2c );background-image:-ms-linear-gradient( #202020,#2c2c2c );background-image:-o-linear-gradient( #202020,#2c2c2c );background-image:linear-gradient( #202020,#2c2c2c )}.ui-btn-down-a:visited,.ui-btn-down-a:hover,.ui-btn-down-a a.ui-link-inherit{color:#fff}.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-b{border:1px solid #456f9a;background:#5e87b0;color:#fff;font-weight:bold;text-shadow:0 1px 0 #3e6790;background-image:-webkit-gradient(linear,left top,left bottom,from( #6facd5 ),to( #497bae ));background-image:-webkit-linear-gradient( #6facd5,#497bae );background-image:-moz-linear-gradient( #6facd5,#497bae );background-image:-ms-linear-gradient( #6facd5,#497bae );background-image:-o-linear-gradient( #6facd5,#497bae );background-image:linear-gradient( #6facd5,#497bae )}.ui-bar-b,.ui-bar-b input,.ui-bar-b select,.ui-bar-b textarea,.ui-bar-b button{font-family:Helvetica,Arial,sans-serif}.ui-bar-b .ui-link-inherit{color:#fff}.ui-bar-b a.ui-link{color:#ddf0f8;font-weight:bold}.ui-bar-b a.ui-link:visited{color:#ddf0f8}.ui-bar-b a.ui-link:hover{color:#ddf0f8}.ui-bar-b a.ui-link:active{color:#ddf0f8}.ui-body-b,.ui-overlay-b{border:1px solid #999;background:#f3f3f3;color:#222;text-shadow:0 1px 0 #fff;font-weight:normal;background-image:-webkit-gradient(linear,left top,left bottom,from( #ddd ),to( #ccc ));background-image:-webkit-linear-gradient( #ddd,#ccc );background-image:-moz-linear-gradient( #ddd,#ccc );background-image:-ms-linear-gradient( #ddd,#ccc );background-image:-o-linear-gradient( #ddd,#ccc );background-image:linear-gradient( #ddd,#ccc )}.ui-overlay-b{background-image:none;border-width:0}.ui-body-b,.ui-body-b input,.ui-body-b select,.ui-body-b textarea,.ui-body-b button{font-family:Helvetica,Arial,sans-serif}.ui-body-b .ui-link-inherit{color:#333}.ui-body-b .ui-link{color:#2489ce;font-weight:bold}.ui-body-b .ui-link:visited{color:#2489ce}.ui-body-b .ui-link:hover{color:#2489ce}.ui-body-b .ui-link:active{color:#2489ce}.ui-btn-up-b{border:1px solid #044062;background:#396b9e;font-weight:bold;color:#fff;text-shadow:0 1px 0 #194b7e;background-image:-webkit-gradient(linear,left top,left bottom,from( #5f9cc5 ),to( #396b9e ));background-image:-webkit-linear-gradient( #5f9cc5,#396b9e );background-image:-moz-linear-gradient( #5f9cc5,#396b9e );background-image:-ms-linear-gradient( #5f9cc5,#396b9e );background-image:-o-linear-gradient( #5f9cc5,#396b9e );background-image:linear-gradient( #5f9cc5,#396b9e )}.ui-btn-up-b:visited,.ui-btn-up-b a.ui-link-inherit{color:#fff}.ui-btn-hover-b{border:1px solid #00415e;background:#4b88b6;font-weight:bold;color:#fff;text-shadow:0 1px 0 #194b7e;background-image:-webkit-gradient(linear,left top,left bottom,from( #6facd5 ),to( #4272a4 ));background-image:-webkit-linear-gradient( #6facd5,#4272a4 );background-image:-moz-linear-gradient( #6facd5,#4272a4 );background-image:-ms-linear-gradient( #6facd5,#4272a4 );background-image:-o-linear-gradient( #6facd5,#4272a4 );background-image:linear-gradient( #6facd5,#4272a4 )}.ui-btn-hover-b:visited,.ui-btn-hover-b:hover,.ui-btn-hover-b a.ui-link-inherit{color:#fff}.ui-btn-down-b{border:1px solid #225377;background:#4e89c5;font-weight:bold;color:#fff;text-shadow:0 1px 0 #194b7e;background-image:-webkit-gradient(linear,left top,left bottom,from( #295b8e ),to( #3e79b5 ));background-image:-webkit-linear-gradient( #295b8e,#3e79b5 );background-image:-moz-linear-gradient( #295b8e,#3e79b5 );background-image:-ms-linear-gradient( #295b8e,#3e79b5 );background-image:-o-linear-gradient( #295b8e,#3e79b5 );background-image:linear-gradient( #295b8e,#3e79b5 )}.ui-btn-down-b:visited,.ui-btn-down-b:hover,.ui-btn-down-b a.ui-link-inherit{color:#fff}.ui-btn-up-b,.ui-btn-hover-b,.ui-btn-down-b{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-c{border:1px solid #b3b3b3;background:#eee;color:#3e3e3e;font-weight:bold;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #f0f0f0 ),to( #ddd ));background-image:-webkit-linear-gradient( #f0f0f0,#ddd );background-image:-moz-linear-gradient( #f0f0f0,#ddd );background-image:-ms-linear-gradient( #f0f0f0,#ddd );background-image:-o-linear-gradient( #f0f0f0,#ddd );background-image:linear-gradient( #f0f0f0,#ddd )}.ui-bar-c .ui-link-inherit{color:#3e3e3e}.ui-bar-c a.ui-link{color:#7cc4e7;font-weight:bold}.ui-bar-c a.ui-link:visited{color:#2489ce}.ui-bar-c a.ui-link:hover{color:#2489ce}.ui-bar-c a.ui-link:active{color:#2489ce}.ui-bar-c,.ui-bar-c input,.ui-bar-c select,.ui-bar-c textarea,.ui-bar-c button{font-family:Helvetica,Arial,sans-serif}.ui-body-c,.ui-overlay-c{border:1px solid #aaa;color:#333;text-shadow:0 1px 0 #fff;background:#f9f9f9;background-image:-webkit-gradient(linear,left top,left bottom,from( #f9f9f9 ),to( #eee ));background-image:-webkit-linear-gradient( #f9f9f9,#eee );background-image:-moz-linear-gradient( #f9f9f9,#eee );background-image:-ms-linear-gradient( #f9f9f9,#eee );background-image:-o-linear-gradient( #f9f9f9,#eee );background-image:linear-gradient( #f9f9f9,#eee )}.ui-overlay-c{background-image:none;border-width:0}.ui-body-c,.ui-body-c input,.ui-body-c select,.ui-body-c textarea,.ui-body-c button{font-family:Helvetica,Arial,sans-serif}.ui-body-c .ui-link-inherit{color:#333}.ui-body-c .ui-link{color:#2489ce;font-weight:bold}.ui-body-c .ui-link:visited{color:#2489ce}.ui-body-c .ui-link:hover{color:#2489ce}.ui-body-c .ui-link:active{color:#2489ce}.ui-btn-up-c{border:1px solid #ccc;background:#eee;font-weight:bold;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #fff ),to( #f1f1f1 ));background-image:-webkit-linear-gradient( #fff,#f1f1f1 );background-image:-moz-linear-gradient( #fff,#f1f1f1 );background-image:-ms-linear-gradient( #fff,#f1f1f1 );background-image:-o-linear-gradient( #fff,#f1f1f1 );background-image:linear-gradient( #fff,#f1f1f1 )}.ui-btn-up-c:visited,.ui-btn-up-c a.ui-link-inherit{color:#2f3e46}.ui-btn-hover-c{border:1px solid #bbb;background:#dfdfdf;font-weight:bold;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #f6f6f6 ),to( #e0e0e0 ));background-image:-webkit-linear-gradient( #f6f6f6,#e0e0e0 );background-image:-moz-linear-gradient( #f6f6f6,#e0e0e0 );background-image:-ms-linear-gradient( #f6f6f6,#e0e0e0 );background-image:-o-linear-gradient( #f6f6f6,#e0e0e0 );background-image:linear-gradient( #f6f6f6,#e0e0e0 )}.ui-btn-hover-c:visited,.ui-btn-hover-c:hover,.ui-btn-hover-c a.ui-link-inherit{color:#2f3e46}.ui-btn-down-c{border:1px solid #bbb;background:#d6d6d6;font-weight:bold;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #d0d0d0 ),to( #dfdfdf ));background-image:-webkit-linear-gradient( #d0d0d0,#dfdfdf );background-image:-moz-linear-gradient( #d0d0d0,#dfdfdf );background-image:-ms-linear-gradient( #d0d0d0,#dfdfdf );background-image:-o-linear-gradient( #d0d0d0,#dfdfdf );background-image:linear-gradient( #d0d0d0,#dfdfdf )}.ui-btn-down-c:visited,.ui-btn-down-c:hover,.ui-btn-down-c a.ui-link-inherit{color:#2f3e46}.ui-btn-up-c,.ui-btn-hover-c,.ui-btn-down-c{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-d{border:1px solid #bbb;background:#bbb;color:#333;font-weight:bold;text-shadow:0 1px 0 #eee;background-image:-webkit-gradient(linear,left top,left bottom,from( #ddd ),to( #bbb ));background-image:-webkit-linear-gradient( #ddd,#bbb );background-image:-moz-linear-gradient( #ddd,#bbb );background-image:-ms-linear-gradient( #ddd,#bbb );background-image:-o-linear-gradient( #ddd,#bbb );background-image:linear-gradient( #ddd,#bbb )}.ui-bar-d,.ui-bar-d input,.ui-bar-d select,.ui-bar-d textarea,.ui-bar-d button{font-family:Helvetica,Arial,sans-serif}.ui-bar-d .ui-link-inherit{color:#333}.ui-bar-d a.ui-link{color:#2489ce;font-weight:bold}.ui-bar-d a.ui-link:visited{color:#2489ce}.ui-bar-d a.ui-link:hover{color:#2489ce}.ui-bar-d a.ui-link:active{color:#2489ce}.ui-body-d,.ui-overlay-d{border:1px solid #bbb;color:#333;text-shadow:0 1px 0 #fff;background:#fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #fff ),to( #fff ));background-image:-webkit-linear-gradient( #fff,#fff );background-image:-moz-linear-gradient( #fff,#fff );background-image:-ms-linear-gradient( #fff,#fff );background-image:-o-linear-gradient( #fff,#fff );background-image:linear-gradient( #fff,#fff )}.ui-overlay-d{background-image:none;border-width:0}.ui-body-d,.ui-body-d input,.ui-body-d select,.ui-body-d textarea,.ui-body-d button{font-family:Helvetica,Arial,sans-serif}.ui-body-d .ui-link-inherit{color:#333}.ui-body-d .ui-link{color:#2489ce;font-weight:bold}.ui-body-d .ui-link:visited{color:#2489ce}.ui-body-d .ui-link:hover{color:#2489ce}.ui-body-d .ui-link:active{color:#2489ce}.ui-btn-up-d{border:1px solid #bbb;background:#fff;font-weight:bold;color:#333;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #fafafa ),to( #f6f6f6 ));background-image:-webkit-linear-gradient( #fafafa,#f6f6f6 );background-image:-moz-linear-gradient( #fafafa,#f6f6f6 );background-image:-ms-linear-gradient( #fafafa,#f6f6f6 );background-image:-o-linear-gradient( #fafafa,#f6f6f6 );background-image:linear-gradient( #fafafa,#f6f6f6 )}.ui-btn-up-d:visited,.ui-btn-up-d a.ui-link-inherit{color:#333}.ui-btn-hover-d{border:1px solid #aaa;background:#eee;font-weight:bold;color:#333;cursor:pointer;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #eee ),to( #fff ));background-image:-webkit-linear-gradient( #eee,#fff );background-image:-moz-linear-gradient( #eee,#fff );background-image:-ms-linear-gradient( #eee,#fff );background-image:-o-linear-gradient( #eee,#fff );background-image:linear-gradient( #eee,#fff )}.ui-btn-hover-d:visited,.ui-btn-hover-d:hover,.ui-btn-hover-d a.ui-link-inherit{color:#333}.ui-btn-down-d{border:1px solid #aaa;background:#eee;font-weight:bold;color:#333;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #e5e5e5 ),to( #f2f2f2 ));background-image:-webkit-linear-gradient( #e5e5e5,#f2f2f2 );background-image:-moz-linear-gradient( #e5e5e5,#f2f2f2 );background-image:-ms-linear-gradient( #e5e5e5,#f2f2f2 );background-image:-o-linear-gradient( #e5e5e5,#f2f2f2 );background-image:linear-gradient( #e5e5e5,#f2f2f2 )}.ui-btn-down-d:visited,.ui-btn-down-d:hover,.ui-btn-down-d a.ui-link-inherit{color:#333}.ui-btn-up-d,.ui-btn-hover-d,.ui-btn-down-d{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-e{border:1px solid #f7c942;background:#fadb4e;color:#333;font-weight:bold;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #fceda7 ),to( #fbef7e ));background-image:-webkit-linear-gradient( #fceda7,#fbef7e );background-image:-moz-linear-gradient( #fceda7,#fbef7e );background-image:-ms-linear-gradient( #fceda7,#fbef7e );background-image:-o-linear-gradient( #fceda7,#fbef7e );background-image:linear-gradient( #fceda7,#fbef7e )}.ui-bar-e,.ui-bar-e input,.ui-bar-e select,.ui-bar-e textarea,.ui-bar-e button{font-family:Helvetica,Arial,sans-serif}.ui-bar-e .ui-link-inherit{color:#333}.ui-bar-e a.ui-link{color:#2489ce;font-weight:bold}.ui-bar-e a.ui-link:visited{color:#2489ce}.ui-bar-e a.ui-link:hover{color:#2489ce}.ui-bar-e a.ui-link:active{color:#2489ce}.ui-body-e,.ui-overlay-e{border:1px solid #f7c942;color:#222;text-shadow:0 1px 0 #fff;background:#fff9df;background-image:-webkit-gradient(linear,left top,left bottom,from( #fffadf ),to( #fff3a5 ));background-image:-webkit-linear-gradient( #fffadf,#fff3a5 );background-image:-moz-linear-gradient( #fffadf,#fff3a5 );background-image:-ms-linear-gradient( #fffadf,#fff3a5 );background-image:-o-linear-gradient( #fffadf,#fff3a5 );background-image:linear-gradient( #fffadf,#fff3a5 )}.ui-overlay-e{background-image:none;border-width:0}.ui-body-e,.ui-body-e input,.ui-body-e select,.ui-body-e textarea,.ui-body-e button{font-family:Helvetica,Arial,sans-serif}.ui-body-e .ui-link-inherit{color:#222}.ui-body-e .ui-link{color:#2489ce;font-weight:bold}.ui-body-e .ui-link:visited{color:#2489ce}.ui-body-e .ui-link:hover{color:#2489ce}.ui-body-e .ui-link:active{color:#2489ce}.ui-btn-up-e{border:1px solid #f4c63f;background:#fadb4e;font-weight:bold;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #ffefaa ),to( #ffe155 ));background-image:-webkit-linear-gradient( #ffefaa,#ffe155 );background-image:-moz-linear-gradient( #ffefaa,#ffe155 );background-image:-ms-linear-gradient( #ffefaa,#ffe155 );background-image:-o-linear-gradient( #ffefaa,#ffe155 );background-image:linear-gradient( #ffefaa,#ffe155 )}.ui-btn-up-e:visited,.ui-btn-up-e a.ui-link-inherit{color:#222}.ui-btn-hover-e{border:1px solid #f2c43d;background:#fbe26f;font-weight:bold;color:#111;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #fff5ba ),to( #fbdd52 ));background-image:-webkit-linear-gradient( #fff5ba,#fbdd52 );background-image:-moz-linear-gradient( #fff5ba,#fbdd52 );background-image:-ms-linear-gradient( #fff5ba,#fbdd52 );background-image:-o-linear-gradient( #fff5ba,#fbdd52 );background-image:linear-gradient( #fff5ba,#fbdd52 )}.ui-btn-hover-e:visited,.ui-btn-hover-e:hover,.ui-btn-hover-e a.ui-link-inherit{color:#333}.ui-btn-down-e{border:1px solid #f2c43d;background:#fceda7;font-weight:bold;color:#111;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #f8d94c ),to( #fadb4e ));background-image:-webkit-linear-gradient( #f8d94c,#fadb4e );background-image:-moz-linear-gradient( #f8d94c,#fadb4e );background-image:-ms-linear-gradient( #f8d94c,#fadb4e );background-image:-o-linear-gradient( #f8d94c,#fadb4e );background-image:linear-gradient( #f8d94c,#fadb4e )}.ui-btn-down-e:visited,.ui-btn-down-e:hover,.ui-btn-down-e a.ui-link-inherit{color:#333}.ui-btn-up-e,.ui-btn-hover-e,.ui-btn-down-e{font-family:Helvetica,Arial,sans-serif;text-decoration:none}a.ui-link-inherit{text-decoration:none!important}.ui-btn-active{border:1px solid #2373a5;background:#5393c5;font-weight:bold;color:#fff;cursor:pointer;text-shadow:0 1px 0 #3373a5;text-decoration:none;background-image:-webkit-gradient(linear,left top,left bottom,from( #5393c5 ),to( #6facd5 ));background-image:-webkit-linear-gradient( #5393c5,#6facd5 );background-image:-moz-linear-gradient( #5393c5,#6facd5 );background-image:-ms-linear-gradient( #5393c5,#6facd5 );background-image:-o-linear-gradient( #5393c5,#6facd5 );background-image:linear-gradient( #5393c5,#6facd5 );font-family:Helvetica,Arial,sans-serif}.ui-btn-active:visited,.ui-btn-active:hover,.ui-btn-active a.ui-link-inherit{color:#fff}.ui-btn-inner{border-top:1px solid #fff;border-color:rgba(255,255,255,.3)}.ui-corner-all{-webkit-border-radius:.6em;border-radius:.6em}.ui-br{border-color:rgb(130,130,130);border-color:rgba(130,130,130,.3);border-style:solid}.ui-disabled{filter:Alpha(Opacity=30);opacity:.3;zoom:1}.ui-disabled,.ui-disabled a{cursor:default!important;pointer-events:none}.ui-icon,.ui-icon-searchfield:after{background-color:#666;background-color:rgba(0,0,0,.4);background-image:url(images/icons-18-white.png);background-repeat:no-repeat;-webkit-border-radius:9px;border-radius:9px}.ui-icon-alt .ui-icon,.ui-icon-alt .ui-icon-searchfield:after{background-color:#fff;background-color:rgba(255,255,255,.3);background-image:url(images/icons-18-black.png);background-repeat:no-repeat}.ui-icon-nodisc .ui-icon,.ui-icon-nodisc .ui-icon-searchfield:after,.ui-icon-nodisc .ui-icon-alt .ui-icon,.ui-icon-nodisc .ui-icon-alt .ui-icon-searchfield:after{background-color:transparent}.ui-icon-plus{background-position:-1px -1px}.ui-icon-minus{background-position:-37px -1px}.ui-icon-delete{background-position:-73px -1px}.ui-icon-arrow-r{background-position:-108px -1px}.ui-icon-arrow-l{background-position:-144px -1px}.ui-icon-arrow-u{background-position:-180px -1px}.ui-icon-arrow-d{background-position:-216px -1px}.ui-icon-check{background-position:-252px -1px}.ui-icon-gear{background-position:-288px -1px}.ui-icon-refresh{background-position:-323px -1px}.ui-icon-forward{background-position:-360px -1px}.ui-icon-back{background-position:-396px -1px}.ui-icon-grid{background-position:-432px -1px}.ui-icon-star{background-position:-467px -1px}.ui-icon-alert{background-position:-503px -1px}.ui-icon-info{background-position:-539px -1px}.ui-icon-home{background-position:-575px -1px}.ui-icon-search,.ui-icon-searchfield:after{background-position:-611px -1px}.ui-icon-checkbox-on{background-position:-647px -1px}.ui-icon-checkbox-off{background-position:-683px -1px}.ui-icon-radio-on{background-position:-718px -1px}.ui-icon-radio-off{background-position:-754px -1px}.ui-icon-bars{background-position:-788px -1px}.ui-icon-edit{background-position:-824px -1px}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (min--moz-device-pixel-ratio:1.3),only screen and (min-resolution:200dpi){.ui-icon-plus,.ui-icon-minus,.ui-icon-delete,.ui-icon-arrow-r,.ui-icon-arrow-l,.ui-icon-arrow-u,.ui-icon-arrow-d,.ui-icon-check,.ui-icon-gear,.ui-icon-refresh,.ui-icon-forward,.ui-icon-back,.ui-icon-grid,.ui-icon-star,.ui-icon-alert,.ui-icon-info,.ui-icon-home,.ui-icon-bars,.ui-icon-edit,.ui-icon-search,.ui-icon-searchfield:after,.ui-icon-checkbox-off,.ui-icon-checkbox-on,.ui-icon-radio-off,.ui-icon-radio-on{background-image:url(images/icons-36-white.png);-moz-background-size:864px 18px;-o-background-size:864px 18px;-webkit-background-size:864px 18px;background-size:864px 18px}.ui-icon-alt .ui-icon{background-image:url(images/icons-36-black.png)}.ui-icon-plus{background-position:0 50%}.ui-icon-minus{background-position:-36px 50%}.ui-icon-delete{background-position:-72px 50%}.ui-icon-arrow-r{background-position:-108px 50%}.ui-icon-arrow-l{background-position:-144px 50%}.ui-icon-arrow-u{background-position:-179px 50%}.ui-icon-arrow-d{background-position:-215px 50%}.ui-icon-check{background-position:-252px 50%}.ui-icon-gear{background-position:-287px 50%}.ui-icon-refresh{background-position:-323px 50%}.ui-icon-forward{background-position:-360px 50%}.ui-icon-back{background-position:-395px 50%}.ui-icon-grid{background-position:-431px 50%}.ui-icon-star{background-position:-467px 50%}.ui-icon-alert{background-position:-503px 50%}.ui-icon-info{background-position:-538px 50%}.ui-icon-home{background-position:-575px 50%}.ui-icon-search,.ui-icon-searchfield:after{background-position:-611px 50%}.ui-icon-checkbox-on{background-position:-647px 50%}.ui-icon-checkbox-off{background-position:-683px 50%}.ui-icon-radio-on{background-position:-718px 50%}.ui-icon-radio-off{background-position:-754px 50%}.ui-icon-bars{background-position:-788px 50%}.ui-icon-edit{background-position:-824px 50%}}.ui-checkbox .ui-icon,.ui-selectmenu-list .ui-icon{-webkit-border-radius:3px;border-radius:3px}.ui-icon-checkbox-off,.ui-icon-radio-off{background-color:transparent}.ui-checkbox-on .ui-icon,.ui-radio-on .ui-icon{background-color:#4596ce}.ui-icon-loading{background:url(images/ajax-loader.gif);background-size:46px 46px}.ui-btn-corner-all{-webkit-border-radius:1em;border-radius:1em}.ui-corner-all,.ui-btn-corner-all{-webkit-background-clip:padding;background-clip:padding-box}.ui-overlay{background:#666;filter:Alpha(Opacity=50);opacity:.5;position:absolute;width:100%;height:100%}.ui-overlay-shadow{-moz-box-shadow:0 0 12px rgba(0,0,0,.6);-webkit-box-shadow:0 0 12px rgba(0,0,0,.6);box-shadow:0 0 12px rgba(0,0,0,.6)}.ui-shadow{-moz-box-shadow:0 1px 3px rgba(0,0,0,.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,.2);box-shadow:0 1px 3px rgba(0,0,0,.2)}.ui-bar-a .ui-shadow,.ui-bar-b .ui-shadow,.ui-bar-c .ui-shadow{-moz-box-shadow:0 1px 0 rgba(255,255,255,.3);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.3);box-shadow:0 1px 0 rgba(255,255,255,.3)}.ui-shadow-inset{-moz-box-shadow:inset 0 1px 4px rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 4px rgba(0,0,0,.2);box-shadow:inset 0 1px 4px rgba(0,0,0,.2)}.ui-icon-shadow{-moz-box-shadow:0 1px 0 rgba(255,255,255,.4);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.4);box-shadow:0 1px 0 rgba(255,255,255,.4)}.ui-btn:focus,.ui-link-inherit:focus{outline:0}.ui-btn.ui-focus{z-index:1}.ui-focus,.ui-btn:focus{-moz-box-shadow:inset 0 0 3px #387bbe,0px 0 9px #387bbe;-webkit-box-shadow:inset 0 0 3px #387bbe,0px 0 9px #387bbe;box-shadow:inset 0 0 3px #387bbe,0px 0 9px #387bbe}.ui-input-text.ui-focus,.ui-input-search.ui-focus{-moz-box-shadow:0 0 12px #387bbe;-webkit-box-shadow:0 0 12px #387bbe;box-shadow:0 0 12px #387bbe}.ui-mobile-nosupport-boxshadow *{-moz-box-shadow:none!important;-webkit-box-shadow:none!important;box-shadow:none!important}.ui-mobile-nosupport-boxshadow .ui-focus,.ui-mobile-nosupport-boxshadow .ui-btn:focus,.ui-mobile-nosupport-boxshadow .ui-link-inherit:focus{outline-width:1px;outline-style:auto}.ui-mobile,.ui-mobile body{height:99.9%}.ui-mobile fieldset,.ui-page{padding:0;margin:0}.ui-mobile a img,.ui-mobile fieldset{border-width:0}.ui-mobile-viewport{margin:0;overflow-x:visible;-webkit-text-size-adjust:100%;-ms-text-size-adjust:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}body.ui-mobile-viewport,div.ui-mobile-viewport{overflow-x:hidden}.ui-mobile [data-role=page],.ui-mobile [data-role=dialog],.ui-page{top:0;left:0;width:100%;min-height:100%;position:absolute;display:none;border:0}.ui-mobile .ui-page-active{display:block;overflow:visible}.ui-page{outline:none}@media screen and (orientation:portrait){.ui-mobile,.ui-mobile .ui-page{min-height:420px}}@media screen and (orientation:landscape){.ui-mobile,.ui-mobile .ui-page{min-height:300px}}.ui-loading .ui-loader{display:block}.ui-loader{display:none;z-index:9999999;position:fixed;top:50%;left:50%;border:0}.ui-loader-default{background:none;filter:Alpha(Opacity=18);opacity:.18;width:46px;height:46px;margin-left:-23px;margin-top:-23px}.ui-loader-verbose{width:200px;filter:Alpha(Opacity=88);opacity:.88;box-shadow:0 1px 1px -1px #fff;height:auto;margin-left:-110px;margin-top:-43px;padding:10px}.ui-loader-default h1{font-size:0;width:0;height:0;overflow:hidden}.ui-loader-verbose h1{font-size:16px;margin:0;text-align:center}.ui-loader .ui-icon{background-color:#000;display:block;margin:0;width:44px;height:44px;padding:1px;-webkit-border-radius:36px;border-radius:36px}.ui-loader-verbose .ui-icon{margin:0 auto 10px;filter:Alpha(Opacity=75);opacity:.75}.ui-loader-textonly{padding:15px;margin-left:-115px}.ui-loader-textonly .ui-icon{display:none}.ui-loader-fakefix{position:absolute}.ui-mobile-rendering > *{visibility:hidden}.ui-bar,.ui-body{position:relative;padding:.4em 15px;overflow:hidden;display:block;clear:both}.ui-bar{font-size:16px;margin:0}.ui-bar h1,.ui-bar h2,.ui-bar h3,.ui-bar h4,.ui-bar h5,.ui-bar h6{margin:0;padding:0;font-size:16px;display:inline-block}.ui-header,.ui-footer{position:relative;zoom:1}.ui-mobile .ui-header,.ui-mobile .ui-footer{border-left-width:0;border-right-width:0}.ui-header .ui-btn-left,.ui-header .ui-btn-right,.ui-footer .ui-btn-left,.ui-footer .ui-btn-right,.ui-header-fixed.ui-fixed-hidden .ui-btn-left,.ui-header-fixed.ui-fixed-hidden .ui-btn-right{position:absolute;top:3px}.ui-header-fixed .ui-btn-left,.ui-header-fixed .ui-btn-right{top:4px}.ui-header .ui-btn-left,.ui-footer .ui-btn-left{left:5px}.ui-header .ui-btn-right,.ui-footer .ui-btn-right{right:5px}.ui-footer > .ui-btn-icon-notext,.ui-header > .ui-btn-icon-notext,.ui-header-fixed.ui-fixed-hidden > .ui-btn-icon-notext{top:6px}.ui-header-fixed > .ui-btn-icon-notext{top:7px}.ui-header .ui-title,.ui-footer .ui-title{min-height:1.1em;text-align:center;font-size:16px;display:block;margin:.6em 30% .8em;padding:0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;outline:0!important}.ui-footer .ui-title{margin:.6em 15px .8em}.ui-content{border-width:0;overflow:visible;overflow-x:hidden;padding:15px}.ui-corner-all > .ui-header:first-child,.ui-corner-all > .ui-content:first-child,.ui-corner-all > .ui-footer:first-child{-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit;-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit}.ui-corner-all > .ui-header:last-child,.ui-corner-all > .ui-content:last-child,.ui-corner-all > .ui-footer:last-child{-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit;-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit}.ui-icon{width:18px;height:18px}.ui-nojs{position:absolute;left:-9999px}.ui-hide-label label.ui-input-text,.ui-hide-label label.ui-select,.ui-hide-label label.ui-slider,.ui-hide-label label.ui-submit,.ui-hide-label .ui-controlgroup-label,.ui-hidden-accessible{position:absolute!important;left:-9999px;clip:rect(1px);clip:rect(1px,1px,1px,1px)}.ui-mobile-viewport-transitioning,.ui-mobile-viewport-transitioning .ui-page{width:100%;height:100%;overflow:hidden;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.ui-page-pre-in{opacity:0}.in{-webkit-animation-fill-mode:both;-webkit-animation-timing-function:ease-out;-webkit-animation-duration:350ms;-moz-animation-fill-mode:both;-moz-animation-timing-function:ease-out;-moz-animation-duration:350ms;animation-fill-mode:both;animation-timing-function:ease-out;animation-duration:350ms}.out{-webkit-animation-fill-mode:both;-webkit-animation-timing-function:ease-in;-webkit-animation-duration:225ms;-moz-animation-fill-mode:both;-moz-animation-timing-function:ease-in;-moz-animation-duration:225ms;animation-fill-mode:both;animation-timing-function:ease-in;animation-duration:225ms}@-webkit-keyframes fadein{from{opacity:0}to{opacity:1}}@-moz-keyframes fadein{from{opacity:0}to{opacity:1}}@keyframes fadein{from{opacity:0}to{opacity:1}}@-webkit-keyframes fadeout{from{opacity:1}to{opacity:0}}@-moz-keyframes fadeout{from{opacity:1}to{opacity:0}}@keyframes fadeout{from{opacity:1}to{opacity:0}}.fade.out{opacity:0;-webkit-animation-duration:125ms;-webkit-animation-name:fadeout;-moz-animation-duration:125ms;-moz-animation-name:fadeout;animation-duration:125ms;animation-name:fadeout}.fade.in{opacity:1;-webkit-animation-duration:225ms;-webkit-animation-name:fadein;-moz-animation-duration:225ms;-moz-animation-name:fadein;animation-duration:225ms;animation-name:fadein}.pop{-webkit-transform-origin:50% 50%;-moz-transform-origin:50% 50%;transform-origin:50% 50%}.pop.in{-webkit-transform:scale(1);-webkit-animation-name:popin;-webkit-animation-duration:350ms;-moz-transform:scale(1);-moz-animation-name:popin;-moz-animation-duration:350ms;transform:scale(1);animation-name:popin;animation-duration:350ms;opacity:1}.pop.out{-webkit-animation-name:fadeout;-webkit-animation-duration:100ms;-moz-animation-name:fadeout;-moz-animation-duration:100ms;animation-name:fadeout;animation-duration:100ms;opacity:0}.pop.in.reverse{-webkit-animation-name:fadein;-moz-animation-name:fadein;animation-name:fadein}.pop.out.reverse{-webkit-transform:scale(.8);-webkit-animation-name:popout;-moz-transform:scale(.8);-moz-animation-name:popout;transform:scale(.8);animation-name:popout}@-webkit-keyframes popin{from{-webkit-transform:scale(.8);opacity:0}to{-webkit-transform:scale(1);opacity:1}}@-moz-keyframes popin{from{-moz-transform:scale(.8);opacity:0}to{-moz-transform:scale(1);opacity:1}}@keyframes popin{from{transform:scale(.8);opacity:0}to{transform:scale(1);opacity:1}}@-webkit-keyframes popout{from{-webkit-transform:scale(1);opacity:1}to{-webkit-transform:scale(.8);opacity:0}}@-moz-keyframes popout{from{-moz-transform:scale(1);opacity:1}to{-moz-transform:scale(.8);opacity:0}}@keyframes popout{from{transform:scale(1);opacity:1}to{transform:scale(.8);opacity:0}}@-webkit-keyframes slideinfromright{from{-webkit-transform:translateX(100%)}to{-webkit-transform:translateX(0)}}@-moz-keyframes slideinfromright{from{-moz-transform:translateX(100%)}to{-moz-transform:translateX(0)}}@keyframes slideinfromright{from{transform:translateX(100%)}to{transform:translateX(0)}}@-webkit-keyframes slideinfromleft{from{-webkit-transform:translateX(-100%)}to{-webkit-transform:translateX(0)}}@-moz-keyframes slideinfromleft{from{-moz-transform:translateX(-100%)}to{-moz-transform:translateX(0)}}@keyframes slideinfromleft{from{transform:translateX(-100%)}to{transform:translateX(0)}}@-webkit-keyframes slideouttoleft{from{-webkit-transform:translateX(0)}to{-webkit-transform:translateX(-100%)}}@-moz-keyframes slideouttoleft{from{-moz-transform:translateX(0)}to{-moz-transform:translateX(-100%)}}@keyframes slideouttoleft{from{transform:translateX(0)}to{transform:translateX(-100%)}}@-webkit-keyframes slideouttoright{from{-webkit-transform:translateX(0)}to{-webkit-transform:translateX(100%)}}@-moz-keyframes slideouttoright{from{-moz-transform:translateX(0)}to{-moz-transform:translateX(100%)}}@keyframes slideouttoright{from{transform:translateX(0)}to{transform:translateX(100%)}}.slide.out,.slide.in{-webkit-animation-timing-function:ease-out;-webkit-animation-duration:350ms;-moz-animation-timing-function:ease-out;-moz-animation-duration:350ms;animation-timing-function:ease-out;animation-duration:350ms}.slide.out{-webkit-transform:translateX(-100%);-webkit-animation-name:slideouttoleft;-moz-transform:translateX(-100%);-moz-animation-name:slideouttoleft;transform:translateX(-100%);animation-name:slideouttoleft}.slide.in{-webkit-transform:translateX(0);-webkit-animation-name:slideinfromright;-moz-transform:translateX(0);-moz-animation-name:slideinfromright;transform:translateX(0);animation-name:slideinfromright}.slide.out.reverse{-webkit-transform:translateX(100%);-webkit-animation-name:slideouttoright;-moz-transform:translateX(100%);-moz-animation-name:slideouttoright;transform:translateX(100%);animation-name:slideouttoright}.slide.in.reverse{-webkit-transform:translateX(0);-webkit-animation-name:slideinfromleft;-moz-transform:translateX(0);-moz-animation-name:slideinfromleft;transform:translateX(0);animation-name:slideinfromleft}.slidefade.out{-webkit-transform:translateX(-100%);-webkit-animation-name:slideouttoleft;-webkit-animation-duration:225ms;-moz-transform:translateX(-100%);-moz-animation-name:slideouttoleft;-moz-animation-duration:225ms;transform:translateX(-100%);animation-name:slideouttoleft;animation-duration:225ms}.slidefade.in{-webkit-transform:translateX(0);-webkit-animation-name:fadein;-webkit-animation-duration:200ms;-moz-transform:translateX(0);-moz-animation-name:fadein;-moz-animation-duration:200ms;transform:translateX(0);animation-name:fadein;animation-duration:200ms}.slidefade.out.reverse{-webkit-transform:translateX(100%);-webkit-animation-name:slideouttoright;-webkit-animation-duration:200ms;-moz-transform:translateX(100%);-moz-animation-name:slideouttoright;-moz-animation-duration:200ms;transform:translateX(100%);animation-name:slideouttoright;animation-duration:200ms}.slidefade.in.reverse{-webkit-transform:translateX(0);-webkit-animation-name:fadein;-webkit-animation-duration:200ms;-moz-transform:translateX(0);-moz-animation-name:fadein;-moz-animation-duration:200ms;transform:translateX(0);animation-name:fadein;animation-duration:200ms}.slidedown.out{-webkit-animation-name:fadeout;-webkit-animation-duration:100ms;-moz-animation-name:fadeout;-moz-animation-duration:100ms;animation-name:fadeout;animation-duration:100ms}.slidedown.in{-webkit-transform:translateY(0);-webkit-animation-name:slideinfromtop;-webkit-animation-duration:250ms;-moz-transform:translateY(0);-moz-animation-name:slideinfromtop;-moz-animation-duration:250ms;transform:translateY(0);animation-name:slideinfromtop;animation-duration:250ms}.slidedown.in.reverse{-webkit-animation-name:fadein;-webkit-animation-duration:150ms;-moz-animation-name:fadein;-moz-animation-duration:150ms;animation-name:fadein;animation-duration:150ms}.slidedown.out.reverse{-webkit-transform:translateY(-100%);-webkit-animation-name:slideouttotop;-webkit-animation-duration:200ms;-moz-transform:translateY(-100%);-moz-animation-name:slideouttotop;-moz-animation-duration:200ms;transform:translateY(-100%);animation-name:slideouttotop;animation-duration:200ms}@-webkit-keyframes slideinfromtop{from{-webkit-transform:translateY(-100%)}to{-webkit-transform:translateY(0)}}@-moz-keyframes slideinfromtop{from{-moz-transform:translateY(-100%)}to{-moz-transform:translateY(0)}}@keyframes slideinfromtop{from{transform:translateY(-100%)}to{transform:translateY(0)}}@-webkit-keyframes slideouttotop{from{-webkit-transform:translateY(0)}to{-webkit-transform:translateY(-100%)}}@-moz-keyframes slideouttotop{from{-moz-transform:translateY(0)}to{-moz-transform:translateY(-100%)}}@keyframes slideouttotop{from{transform:translateY(0)}to{transform:translateY(-100%)}}.slideup.out{-webkit-animation-name:fadeout;-webkit-animation-duration:100ms;-moz-animation-name:fadeout;-moz-animation-duration:100ms;animation-name:fadeout;animation-duration:100ms}.slideup.in{-webkit-transform:translateY(0);-webkit-animation-name:slideinfrombottom;-webkit-animation-duration:250ms;-moz-transform:translateY(0);-moz-animation-name:slideinfrombottom;-moz-animation-duration:250ms;transform:translateY(0);animation-name:slideinfrombottom;animation-duration:250ms}.slideup.in.reverse{-webkit-animation-name:fadein;-webkit-animation-duration:150ms;-moz-animation-name:fadein;-moz-animation-duration:150ms;animation-name:fadein;animation-duration:150ms}.slideup.out.reverse{-webkit-transform:translateY(100%);-webkit-animation-name:slideouttobottom;-webkit-animation-duration:200ms;-moz-transform:translateY(100%);-moz-animation-name:slideouttobottom;-moz-animation-duration:200ms;transform:translateY(100%);animation-name:slideouttobottom;animation-duration:200ms}@-webkit-keyframes slideinfrombottom{from{-webkit-transform:translateY(100%)}to{-webkit-transform:translateY(0)}}@-moz-keyframes slideinfrombottom{from{-moz-transform:translateY(100%)}to{-moz-transform:translateY(0)}}@keyframes slideinfrombottom{from{transform:translateY(100%)}to{transform:translateY(0)}}@-webkit-keyframes slideouttobottom{from{-webkit-transform:translateY(0)}to{-webkit-transform:translateY(100%)}}@-moz-keyframes slideouttobottom{from{-moz-transform:translateY(0)}to{-moz-transform:translateY(100%)}}@keyframes slideouttobottom{from{transform:translateY(0)}to{transform:translateY(100%)}}.viewport-flip{-webkit-perspective:1000;-moz-perspective:1000;perspective:1000;position:absolute}.flip{-webkit-backface-visibility:hidden;-webkit-transform:translateX(0);-moz-backface-visibility:hidden;-moz-transform:translateX(0);backface-visibility:hidden;transform:translateX(0)}.flip.out{-webkit-transform:rotateY(-90deg) scale(.9);-webkit-animation-name:flipouttoleft;-webkit-animation-duration:175ms;-moz-transform:rotateY(-90deg) scale(.9);-moz-animation-name:flipouttoleft;-moz-animation-duration:175ms;transform:rotateY(-90deg) scale(.9);animation-name:flipouttoleft;animation-duration:175ms}.flip.in{-webkit-animation-name:flipintoright;-webkit-animation-duration:225ms;-moz-animation-name:flipintoright;-moz-animation-duration:225ms;animation-name:flipintoright;animation-duration:225ms}.flip.out.reverse{-webkit-transform:rotateY(90deg) scale(.9);-webkit-animation-name:flipouttoright;-moz-transform:rotateY(90deg) scale(.9);-moz-animation-name:flipouttoright;transform:rotateY(90deg) scale(.9);animation-name:flipouttoright}.flip.in.reverse{-webkit-animation-name:flipintoleft;-moz-animation-name:flipintoleft;animation-name:flipintoleft}@-webkit-keyframes flipouttoleft{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(-90deg) scale(.9)}}@-moz-keyframes flipouttoleft{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(-90deg) scale(.9)}}@keyframes flipouttoleft{from{transform:rotateY(0)}to{transform:rotateY(-90deg) scale(.9)}}@-webkit-keyframes flipouttoright{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(90deg) scale(.9)}}@-moz-keyframes flipouttoright{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(90deg) scale(.9)}}@keyframes flipouttoright{from{transform:rotateY(0)}to{transform:rotateY(90deg) scale(.9)}}@-webkit-keyframes flipintoleft{from{-webkit-transform:rotateY(-90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoleft{from{-moz-transform:rotateY(-90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@keyframes flipintoleft{from{transform:rotateY(-90deg) scale(.9)}to{transform:rotateY(0)}}@-webkit-keyframes flipintoright{from{-webkit-transform:rotateY(90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoright{from{-moz-transform:rotateY(90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@keyframes flipintoright{from{transform:rotateY(90deg) scale(.9)}to{transform:rotateY(0)}}.viewport-turn{-webkit-perspective:200px;-moz-perspective:200px;-ms-perspective:200px;perspective:200px;position:absolute}.turn{-webkit-backface-visibility:hidden;-webkit-transform:translateX(0);-webkit-transform-origin:0;-moz-backface-visibility:hidden;-moz-transform:translateX(0);-moz-transform-origin:0;backface-visibility:hidden;transform:translateX(0);transform-origin:0}.turn.out{-webkit-transform:rotateY(-90deg) scale(.9);-webkit-animation-name:flipouttoleft;-webkit-animation-duration:125ms;-moz-transform:rotateY(-90deg) scale(.9);-moz-animation-name:flipouttoleft;-moz-animation-duration:125ms;transform:rotateY(-90deg) scale(.9);animation-name:flipouttoleft;animation-duration:125ms}.turn.in{-webkit-animation-name:flipintoright;-webkit-animation-duration:250ms;-moz-animation-name:flipintoright;-moz-animation-duration:250ms;animation-name:flipintoright;animation-duration:250ms}.turn.out.reverse{-webkit-transform:rotateY(90deg) scale(.9);-webkit-animation-name:flipouttoright;-moz-transform:rotateY(90deg) scale(.9);-moz-animation-name:flipouttoright;transform:rotateY(90deg) scale(.9);animation-name:flipouttoright}.turn.in.reverse{-webkit-animation-name:flipintoleft;-moz-animation-name:flipintoleft;animation-name:flipintoleft}@-webkit-keyframes flipouttoleft{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(-90deg) scale(.9)}}@-moz-keyframes flipouttoleft{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(-90deg) scale(.9)}}@keyframes flipouttoleft{from{transform:rotateY(0)}to{transform:rotateY(-90deg) scale(.9)}}@-webkit-keyframes flipouttoright{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(90deg) scale(.9)}}@-moz-keyframes flipouttoright{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(90deg) scale(.9)}}@keyframes flipouttoright{from{transform:rotateY(0)}to{transform:rotateY(90deg) scale(.9)}}@-webkit-keyframes flipintoleft{from{-webkit-transform:rotateY(-90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoleft{from{-moz-transform:rotateY(-90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@keyframes flipintoleft{from{transform:rotateY(-90deg) scale(.9)}to{transform:rotateY(0)}}@-webkit-keyframes flipintoright{from{-webkit-transform:rotateY(90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoright{from{-moz-transform:rotateY(90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@keyframes flipintoright{from{transform:rotateY(90deg) scale(.9)}to{transform:rotateY(0)}}.flow{-webkit-transform-origin:50% 30%;-webkit-box-shadow:0 0 20px rgba(0,0,0,.4);-moz-transform-origin:50% 30%;-moz-box-shadow:0 0 20px rgba(0,0,0,.4);transform-origin:50% 30%;box-shadow:0 0 20px rgba(0,0,0,.4)}.ui-dialog.flow{-webkit-transform-origin:none;-webkit-box-shadow:none;-moz-transform-origin:none;-moz-box-shadow:none;transform-origin:none;box-shadow:none}.flow.out{-webkit-transform:translateX(-100%) scale(.7);-webkit-animation-name:flowouttoleft;-webkit-animation-timing-function:ease;-webkit-animation-duration:350ms;-moz-transform:translateX(-100%) scale(.7);-moz-animation-name:flowouttoleft;-moz-animation-timing-function:ease;-moz-animation-duration:350ms;transform:translateX(-100%) scale(.7);animation-name:flowouttoleft;animation-timing-function:ease;animation-duration:350ms}.flow.in{-webkit-transform:translateX(0) scale(1);-webkit-animation-name:flowinfromright;-webkit-animation-timing-function:ease;-webkit-animation-duration:350ms;-moz-transform:translateX(0) scale(1);-moz-animation-name:flowinfromright;-moz-animation-timing-function:ease;-moz-animation-duration:350ms;transform:translateX(0) scale(1);animation-name:flowinfromright;animation-timing-function:ease;animation-duration:350ms}.flow.out.reverse{-webkit-transform:translateX(100%);-webkit-animation-name:flowouttoright;-moz-transform:translateX(100%);-moz-animation-name:flowouttoright;transform:translateX(100%);animation-name:flowouttoright}.flow.in.reverse{-webkit-animation-name:flowinfromleft;-moz-animation-name:flowinfromleft;animation-name:flowinfromleft}@-webkit-keyframes flowouttoleft{0%{-webkit-transform:translateX(0) scale(1)}60%,70%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(-100%) scale(.7)}}@-moz-keyframes flowouttoleft{0%{-moz-transform:translateX(0) scale(1)}60%,70%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(-100%) scale(.7)}}@keyframes flowouttoleft{0%{transform:translateX(0) scale(1)}60%,70%{transform:translateX(0) scale(.7)}100%{transform:translateX(-100%) scale(.7)}}@-webkit-keyframes flowouttoright{0%{-webkit-transform:translateX(0) scale(1)}60%,70%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(100%) scale(.7)}}@-moz-keyframes flowouttoright{0%{-moz-transform:translateX(0) scale(1)}60%,70%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(100%) scale(.7)}}@keyframes flowouttoright{0%{transform:translateX(0) scale(1)}60%,70%{transform:translateX(0) scale(.7)}100%{transform:translateX(100%) scale(.7)}}@-webkit-keyframes flowinfromleft{0%{-webkit-transform:translateX(-100%) scale(.7)}30%,40%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(0) scale(1)}}@-moz-keyframes flowinfromleft{0%{-moz-transform:translateX(-100%) scale(.7)}30%,40%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(0) scale(1)}}@keyframes flowinfromleft{0%{transform:translateX(-100%) scale(.7)}30%,40%{transform:translateX(0) scale(.7)}100%{transform:translateX(0) scale(1)}}@-webkit-keyframes flowinfromright{0%{-webkit-transform:translateX(100%) scale(.7)}30%,40%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(0) scale(1)}}@-moz-keyframes flowinfromright{0%{-moz-transform:translateX(100%) scale(.7)}30%,40%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(0) scale(1)}}@keyframes flowinfromright{0%{transform:translateX(100%) scale(.7)}30%,40%{transform:translateX(0) scale(.7)}100%{transform:translateX(0) scale(1)}}.ui-grid-a,.ui-grid-b,.ui-grid-c,.ui-grid-d{overflow:hidden}.ui-block-a,.ui-block-b,.ui-block-c,.ui-block-d,.ui-block-e{margin:0;padding:0;border:0;float:left;min-height:1px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.ui-grid-solo .ui-block-a{display:block;float:none}.ui-grid-a .ui-block-a,.ui-grid-a .ui-block-b{width:49.95%}.ui-grid-a >:nth-child(n){width:50%;margin-right:-.5px}.ui-grid-a .ui-block-a{clear:left}.ui-grid-b .ui-block-a,.ui-grid-b .ui-block-b,.ui-grid-b .ui-block-c{width:33.25%}.ui-grid-b >:nth-child(n){width:33.333%;margin-right:-.5px}.ui-grid-b .ui-block-a{clear:left}.ui-grid-c .ui-block-a,.ui-grid-c .ui-block-b,.ui-grid-c .ui-block-c,.ui-grid-c .ui-block-d{width:24.925%}.ui-grid-c >:nth-child(n){width:25%;margin-right:-.5px}.ui-grid-c .ui-block-a{clear:left}.ui-grid-d .ui-block-a,.ui-grid-d .ui-block-b,.ui-grid-d .ui-block-c,.ui-grid-d .ui-block-d,.ui-grid-d .ui-block-e{width:19.925%}.ui-grid-d >:nth-child(n){width:20%}.ui-grid-d .ui-block-a{clear:left}@media all and (max-width:35em){.ui-responsive .ui-block-a,.ui-responsive .ui-block-b,.ui-responsive .ui-block-c,.ui-responsive .ui-block-d,.ui-responsive .ui-block-e{width:100%;float:none}}.ui-header-fixed,.ui-footer-fixed{left:0;right:0;width:100%;position:fixed;z-index:1000}.ui-header-fixed{top:-1px;padding-top:1px}.ui-header-fixed.ui-fixed-hidden{top:0;padding-top:0}.ui-footer-fixed{bottom:-1px;padding-bottom:1px}.ui-footer-fixed.ui-fixed-hidden{bottom:0;padding-bottom:0}.ui-header-fullscreen,.ui-footer-fullscreen{filter:Alpha(Opacity=90);opacity:.9}.ui-page-header-fixed{padding-top:2.6875em}.ui-page-footer-fixed{padding-bottom:2.6875em}.ui-page-header-fullscreen > .ui-content,.ui-page-footer-fullscreen > .ui-content{padding:0}.ui-fixed-hidden{position:absolute}.ui-page-header-fullscreen .ui-fixed-hidden,.ui-page-footer-fullscreen .ui-fixed-hidden{left:-9999px}.ui-header-fixed .ui-btn,.ui-footer-fixed .ui-btn{z-index:10}.ui-android-2x-fixed .ui-li-has-thumb{-webkit-transform:translate3d(0,0,0)}.ui-navbar{max-width:100%}.ui-navbar.ui-mini{margin:0}.ui-navbar ul:before,.ui-navbar ul:after{content:" ";display:table}.ui-navbar ul:after{clear:both}.ui-navbar ul{list-style:none;margin:0;padding:0;position:relative;display:block;border:0;max-width:100%;overflow:visible;zoom:1}.ui-navbar li .ui-btn{display:block;text-align:center;margin:0 -1px 0 0;border-right-width:0}.ui-navbar li .ui-btn-icon-right .ui-icon{right:6px}.ui-navbar li:last-child .ui-btn,.ui-navbar .ui-grid-duo .ui-block-b .ui-btn{margin-right:0;border-right-width:1px}.ui-header .ui-navbar li:last-child .ui-btn,.ui-footer .ui-navbar li:last-child .ui-btn,.ui-header .ui-navbar .ui-grid-duo .ui-block-b .ui-btn,.ui-footer .ui-navbar .ui-grid-duo .ui-block-b .ui-btn{margin-right:-1px;border-right-width:0}.ui-navbar .ui-grid-duo li.ui-block-a:last-child .ui-btn{margin-right:-1px;border-right-width:1px}.ui-header .ui-navbar li .ui-btn,.ui-footer .ui-navbar li .ui-btn{border-top-width:0;border-bottom-width:0}.ui-header .ui-navbar .ui-grid-b li.ui-block-c .ui-btn,.ui-footer .ui-navbar .ui-grid-b li.ui-block-c .ui-btn{margin-right:-5px}.ui-header .ui-navbar .ui-grid-c li.ui-block-d .ui-btn,.ui-footer .ui-navbar .ui-grid-c li.ui-block-d .ui-btn,.ui-header .ui-navbar .ui-grid-d li.ui-block-e .ui-btn,.ui-footer .ui-navbar .ui-grid-d li.ui-block-e .ui-btn{margin-right:-4px}.ui-header .ui-navbar .ui-grid-b li.ui-block-c .ui-btn-icon-right .ui-icon,.ui-footer .ui-navbar .ui-grid-b li.ui-block-c .ui-btn-icon-right .ui-icon,.ui-header .ui-navbar .ui-grid-c li.ui-block-d .ui-btn-icon-right .ui-icon,.ui-footer .ui-navbar .ui-grid-c li.ui-block-d .ui-btn-icon-right .ui-icon,.ui-header .ui-navbar .ui-grid-d li.ui-block-e .ui-btn-icon-right .ui-icon,.ui-footer .ui-navbar .ui-grid-d li.ui-block-e .ui-btn-icon-right .ui-icon{right:8px}.ui-navbar li .ui-btn .ui-btn-inner{padding-top:.7em;padding-bottom:.8em}.ui-navbar li .ui-btn-icon-top .ui-btn-inner{padding-top:30px}.ui-navbar li .ui-btn-icon-bottom .ui-btn-inner{padding-bottom:30px}.ui-btn{display:block;text-align:center;cursor:pointer;position:relative;margin:.5em 0;padding:0}.ui-mini{margin-top:.25em;margin-bottom:.25em}.ui-btn-left,.ui-btn-right,.ui-input-clear,.ui-btn-inline,.ui-grid-a .ui-btn,.ui-grid-b .ui-btn,.ui-grid-c .ui-btn,.ui-grid-d .ui-btn,.ui-grid-e .ui-btn,.ui-grid-solo .ui-btn{margin-right:5px;margin-left:5px}.ui-btn-inner{font-size:16px;padding:.6em 20px;min-width:.75em;display:block;position:relative;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;zoom:1}.ui-btn input,.ui-btn button{z-index:2}.ui-btn-left,.ui-btn-right,.ui-btn-inline{display:inline-block;vertical-align:middle}.ui-mobile .ui-btn-left,.ui-mobile .ui-btn-right,.ui-btn-left > .ui-btn,.ui-btn-right > .ui-btn{margin:0}.ui-btn-block{display:block}.ui-header > .ui-btn,.ui-footer > .ui-btn{display:inline-block;margin:0}.ui-header .ui-btn-block,.ui-footer .ui-btn-block{display:block}.ui-header .ui-btn-inner,.ui-footer .ui-btn-inner,.ui-mini .ui-btn-inner{font-size:12.5px;padding:.55em 11px .5em}.ui-fullsize .ui-btn-inner,.ui-fullsize .ui-btn-inner{font-size:16px;padding:.6em 20px}.ui-btn-icon-notext{width:24px;height:24px}.ui-btn-icon-notext .ui-btn-inner{padding:0;height:100%}.ui-btn-icon-notext .ui-btn-inner .ui-icon{margin:2px 1px 2px 3px;float:left}.ui-btn-text{position:relative;z-index:1;width:100%;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}div.ui-btn-text{width:auto}.ui-btn-icon-notext .ui-btn-text{position:absolute;left:-9999px}.ui-btn-icon-left .ui-btn-inner{padding-left:40px}.ui-btn-icon-right .ui-btn-inner{padding-right:40px}.ui-btn-icon-top .ui-btn-inner{padding-top:40px}.ui-btn-icon-bottom .ui-btn-inner{padding-bottom:40px}.ui-header .ui-btn-icon-left .ui-btn-inner,.ui-footer .ui-btn-icon-left .ui-btn-inner,.ui-mini.ui-btn-icon-left .ui-btn-inner,.ui-mini .ui-btn-icon-left .ui-btn-inner{padding-left:30px}.ui-header .ui-btn-icon-right .ui-btn-inner,.ui-footer .ui-btn-icon-right .ui-btn-inner,.ui-mini.ui-btn-icon-right .ui-btn-inner,.ui-mini .ui-btn-icon-right .ui-btn-inner{padding-right:30px}.ui-header .ui-btn-icon-top .ui-btn-inner,.ui-footer .ui-btn-icon-top .ui-btn-inner{padding:30px 3px .5em 3px}.ui-mini.ui-btn-icon-top .ui-btn-inner,.ui-mini .ui-btn-icon-top .ui-btn-inner{padding-top:30px}.ui-header .ui-btn-icon-bottom .ui-btn-inner,.ui-footer .ui-btn-icon-bottom .ui-btn-inner{padding:.55em 3px 30px 3px}.ui-mini.ui-btn-icon-bottom .ui-btn-inner,.ui-mini .ui-btn-icon-bottom .ui-btn-inner{padding-bottom:30px}.ui-btn-inner,.ui-btn-text{-webkit-border-radius:inherit;border-radius:inherit}.ui-btn-icon-notext .ui-icon{display:block;z-index:0}.ui-btn-icon-left > .ui-btn-inner > .ui-icon,.ui-btn-icon-right > .ui-btn-inner > .ui-icon{position:absolute;top:50%;margin-top:-9px}.ui-btn-icon-top .ui-btn-inner .ui-icon,.ui-btn-icon-bottom .ui-btn-inner .ui-icon{position:absolute;left:50%;margin-left:-9px}.ui-btn-icon-left .ui-icon{left:10px}.ui-btn-icon-right .ui-icon{right:10px}.ui-btn-icon-top .ui-icon{top:10px}.ui-btn-icon-bottom .ui-icon{top:auto;bottom:10px}.ui-header .ui-btn-icon-left .ui-icon,.ui-footer .ui-btn-icon-left .ui-icon,.ui-mini.ui-btn-icon-left .ui-icon,.ui-mini .ui-btn-icon-left .ui-icon{left:5px}.ui-header .ui-btn-icon-right .ui-icon,.ui-footer .ui-btn-icon-right .ui-icon,.ui-mini.ui-btn-icon-right .ui-icon,.ui-mini .ui-btn-icon-right .ui-icon{right:5px}.ui-header .ui-btn-icon-top .ui-icon,.ui-footer .ui-btn-icon-top .ui-icon,.ui-mini.ui-btn-icon-top .ui-icon,.ui-mini .ui-btn-icon-top .ui-icon{top:5px}.ui-header .ui-btn-icon-bottom .ui-icon,.ui-footer .ui-btn-icon-bottom .ui-icon,.ui-mini.ui-btn-icon-bottom .ui-icon,.ui-mini .ui-btn-icon-bottom .ui-icon{bottom:5px}.ui-btn-hidden{position:absolute;top:0;left:0;width:100%;height:100%;-webkit-appearance:none;cursor:pointer;background:#fff;background:rgba(255,255,255,0);filter:Alpha(Opacity=0);opacity:.1;font-size:1px;border:none;text-indent:-9999px}.ui-disabled .ui-btn-hidden{display:none}.ui-disabled{z-index:1}.ui-field-contain .ui-btn.ui-submit{margin:0}label.ui-submit{font-size:16px;line-height:1.4;font-weight:normal;margin:0 0 .3em;display:block}@media all and (min-width:28em){.ui-field-contain label.ui-submit{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain .ui-btn.ui-submit{width:78%;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.ui-hide-label .ui-btn.ui-submit{width:auto;display:block}}.ui-collapsible-inset{margin:.5em 0}.ui-collapsible-heading{font-size:16px;display:block;margin:0 -15px;padding:0;position:relative}.ui-collapsible-inset .ui-collapsible-heading{margin:0}.ui-collapsible-heading .ui-btn{text-align:left;margin:0;border-left-width:0;border-right-width:0}.ui-collapsible-inset .ui-collapsible-heading .ui-btn{border-right-width:1px;border-left-width:1px}.ui-collapsible-collapsed + .ui-collapsible:not(.ui-collapsible-inset) .ui-collapsible-heading .ui-btn{border-top-width:0}.ui-collapsible-set .ui-collapsible:not(.ui-collapsible-inset) .ui-collapsible-heading .ui-btn{border-top-width:1px}.ui-collapsible-heading .ui-btn-inner{padding-left:12px;padding-right:12px}.ui-collapsible-heading .ui-btn-icon-left .ui-btn-inner{padding-left:40px}.ui-collapsible-heading .ui-btn-icon-right .ui-btn-inner{padding-right:40px}.ui-collapsible-heading .ui-btn-icon-top .ui-btn-inner,.ui-collapsible-heading .ui-btn-icon-bottom .ui-btn-inner{text-align:center}.ui-collapsible-heading .ui-btn-icon-left.ui-mini .ui-btn-inner{padding-left:30px}.ui-collapsible-heading .ui-btn-icon-right.ui-mini .ui-btn-inner{padding-right:30px}.ui-collapsible-heading .ui-btn span.ui-btn{position:absolute;left:6px;top:50%;margin:-12px 0 0 0;width:20px;height:20px;padding:1px 0 1px 2px;text-indent:-9999px}.ui-collapsible-heading .ui-btn span.ui-btn .ui-btn-inner{padding:10px 0}.ui-collapsible-heading .ui-btn span.ui-btn .ui-icon{left:0;margin-top:-10px}.ui-collapsible-heading-status{position:absolute;top:-9999px;left:0}.ui-collapsible-content{display:block;margin:0 -15px;padding:10px 15px;border-left-width:0;border-right-width:0;border-top:none;background-image:none}.ui-collapsible-inset .ui-collapsible-content{margin:0;border-right-width:1px;border-left-width:1px}.ui-collapsible-content-collapsed{display:none}.ui-collapsible-set > .ui-collapsible.ui-corner-all{-webkit-border-radius:0;border-radius:0}.ui-collapsible-heading,.ui-collapsible-heading > .ui-btn{-webkit-border-radius:inherit;border-radius:inherit}.ui-collapsible-set .ui-collapsible.ui-first-child{-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit;-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit}.ui-collapsible-content,.ui-collapsible-set .ui-collapsible.ui-last-child{-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit;-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit}.ui-collapsible-themed-content:not(.ui-collapsible-collapsed) > .ui-collapsible-heading{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0}.ui-collapsible-set{margin:.5em 0}.ui-collapsible-set .ui-collapsible{margin:-1px 0 0}.ui-collapsible-set .ui-collapsible.ui-first-child{margin-top:0}.ui-controlgroup,fieldset.ui-controlgroup{padding:0;margin:.5em 0;zoom:1}.ui-controlgroup.ui-mini,fieldset.ui-controlgroup.ui-mini{margin:.25em 0}.ui-field-contain .ui-controlgroup,.ui-field-contain fieldset.ui-controlgroup{margin:0}.ui-bar .ui-controlgroup{margin:0 5px}.ui-controlgroup-label{font-size:16px;line-height:1.4;font-weight:normal;margin:0 0 .4em}.ui-controlgroup-controls label.ui-select,.ui-controlgroup-controls label.ui-submit{position:absolute;left:-9999px}.ui-controlgroup li{list-style:none}.ui-controlgroup .ui-btn{margin:0}.ui-controlgroup .ui-btn-icon-notext{width:auto;height:auto;top:auto}.ui-controlgroup .ui-btn-icon-notext .ui-btn-inner{height:20px;padding:.6em 20px .6em 20px}.ui-controlgroup-horizontal .ui-btn-icon-notext .ui-btn-inner{width:18px}.ui-controlgroup.ui-mini .ui-btn-icon-notext .ui-btn-inner,.ui-header .ui-controlgroup .ui-btn-icon-notext .ui-btn-inner,.ui-footer .ui-controlgroup .ui-btn-icon-notext .ui-btn-inner{height:16px;padding:.55em 11px .5em 11px}.ui-controlgroup .ui-btn-icon-notext .ui-btn-inner .ui-icon{position:absolute;top:50%;right:50%;margin:-9px -9px 0 0}.ui-controlgroup-horizontal .ui-btn-inner{text-align:center}.ui-controlgroup-horizontal.ui-mini .ui-btn-inner{height:16px;line-height:16px}.ui-controlgroup .ui-checkbox label,.ui-controlgroup .ui-radio label{font-size:16px}.ui-controlgroup-horizontal .ui-controlgroup-controls:before,.ui-controlgroup-horizontal .ui-controlgroup-controls:after{content:"";display:table}.ui-controlgroup-horizontal .ui-controlgroup-controls:after{clear:both}.ui-controlgroup-horizontal .ui-controlgroup-controls{display:inline-block;vertical-align:middle;zoom:1}.ui-controlgroup-horizontal .ui-controlgroup-controls > .ui-btn,.ui-controlgroup-horizontal .ui-controlgroup-controls li > .ui-btn,.ui-controlgroup-horizontal .ui-checkbox,.ui-controlgroup-horizontal .ui-radio,.ui-controlgroup-horizontal .ui-select{float:left;clear:none;margin:0}.ui-controlgroup-horizontal .ui-select .ui-btn-text{width:auto}.ui-controlgroup-vertical .ui-btn{border-bottom-width:0}.ui-controlgroup-vertical .ui-btn.ui-last-child{border-bottom-width:1px}.ui-controlgroup-horizontal .ui-btn{border-right-width:0}.ui-controlgroup-horizontal .ui-btn.ui-last-child{border-right-width:1px}.ui-controlgroup .ui-btn-corner-all{-webkit-border-radius:0;border-radius:0}.ui-controlgroup .ui-controlgroup-controls,.ui-controlgroup .ui-radio,.ui-controlgroup .ui-checkbox,.ui-controlgroup .ui-select,.ui-controlgroup li{-webkit-border-radius:inherit;border-radius:inherit}.ui-controlgroup-vertical .ui-btn.ui-first-child{-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit;-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit}.ui-controlgroup-vertical .ui-btn.ui-last-child{-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit;-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit}.ui-controlgroup-horizontal .ui-btn.ui-first-child{-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit;-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit}.ui-controlgroup-horizontal .ui-btn.ui-last-child{-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit;-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit}.ui-controlgroup .ui-shadow:not(.ui-focus){-moz-box-shadow:none;-webkit-box-shadow:none;box-shadow:none}@media all and (min-width:28em){.ui-field-contain .ui-controlgroup-label{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain .ui-controlgroup-controls{width:78%;display:inline-block}.ui-field-contain .ui-controlgroup .ui-select{width:100%;display:block}.ui-field-contain .ui-controlgroup-horizontal .ui-select{width:auto}.ui-hide-label .ui-controlgroup-controls{width:100%}}.ui-dialog{background:none!important}.ui-dialog-contain{width:92.5%;max-width:500px;margin:10% auto 15px auto;padding:0;position:relative;top:-15px}.ui-dialog-contain > .ui-header,.ui-dialog-contain > .ui-content,.ui-dialog-contain > .ui-footer{display:block;position:relative;width:auto;margin:0}.ui-dialog-contain > .ui-header{border:none;overflow:hidden;z-index:10;padding:0}.ui-dialog-contain > .ui-content{padding:15px}.ui-dialog-contain > .ui-footer{z-index:10;padding:0 15px}.ui-popup-open .ui-header-fixed,.ui-popup-open .ui-footer-fixed{position:absolute!important}.ui-popup-screen{background-image:url(data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==);top:0;left:0;right:0;bottom:1px;position:absolute;filter:Alpha(Opacity=0);opacity:0;z-index:1099}.ui-popup-screen.in{opacity:0.5;filter:Alpha(Opacity=50)}.ui-popup-screen.out{opacity:0;filter:Alpha(Opacity=0)}.ui-popup-container{z-index:1100;display:inline-block;position:absolute;padding:0;outline:0}.ui-popup{position:relative}.ui-popup.ui-content,.ui-popup .ui-content{overflow:visible}.ui-popup > p,.ui-popup > h1,.ui-popup > h2,.ui-popup > h3,.ui-popup > h4,.ui-popup > h5,.ui-popup > h6{margin:.5em 7px}.ui-popup > span{display:block;margin:.5em 7px}.ui-popup .ui-title{font-size:16px;font-weight:bold;margin-top:.5em;margin-bottom:.5em}.ui-popup-container .ui-content > p,.ui-popup-container .ui-content > h1,.ui-popup-container .ui-content > h2,.ui-popup-container .ui-content > h3,.ui-popup-container .ui-content > h4,.ui-popup-container .ui-content > h5,.ui-popup-container .ui-content > h6{margin:.5em 0}.ui-popup-container .ui-content > span{margin:0}.ui-popup-container .ui-content > p:first-child,.ui-popup-container .ui-content > h1:first-child,.ui-popup-container .ui-content > h2:first-child,.ui-popup-container .ui-content > h3:first-child,.ui-popup-container .ui-content > h4:first-child,.ui-popup-container .ui-content > h5:first-child,.ui-popup-container .ui-content > h6:first-child{margin-top:0}.ui-popup-container .ui-content > p:last-child,.ui-popup-container .ui-content > h1:last-child,.ui-popup-container .ui-content > h2:last-child,.ui-popup-container .ui-content > h3:last-child,.ui-popup-container .ui-content > h4:last-child,.ui-popup-container .ui-content > h5:last-child,.ui-popup-container .ui-content > h6:last-child{margin-bottom:0}.ui-popup > img{width:auto;height:auto;max-width:100%;max-height:100%;vertical-align:middle}.ui-popup:not(.ui-content) > img:only-child,.ui-popup:not(.ui-content) > .ui-btn-left:first-child + img:last-child,.ui-popup:not(.ui-content) > .ui-btn-right:first-child + img:last-child{-webkit-border-radius:inherit;border-radius:inherit}.ui-popup iframe{vertical-align:middle}@media all and (min-width:28em){.ui-popup .ui-field-contain label.ui-submit,.ui-popup .ui-field-contain .ui-controlgroup-label,.ui-popup .ui-field-contain label.ui-select,.ui-popup .ui-field-contain label.ui-input-text{font-size:16px;line-height:1.4;display:block;font-weight:normal;margin:0 0 .3em}.ui-popup .ui-field-contain .ui-btn.ui-submit,.ui-popup .ui-field-contain .ui-controlgroup-controls,.ui-popup .ui-field-contain .ui-select,.ui-popup .ui-field-contain input.ui-input-text,.ui-popup .ui-field-contain textarea.ui-input-text,.ui-popup .ui-field-contain .ui-input-search{width:100%;display:block}}.ui-popup > .ui-btn-left,.ui-popup > .ui-btn-right{position:absolute;top:-9px;margin:0;z-index:1101}.ui-popup > .ui-btn-left{left:-9px}.ui-popup > .ui-btn-right{right:-9px}.ui-popup-hidden{top:-99999px;left:-9999px}.ui-checkbox,.ui-radio{position:relative;clear:both;margin:0;z-index:1}.ui-checkbox .ui-btn,.ui-radio .ui-btn{text-align:left;z-index:2}.ui-controlgroup .ui-checkbox .ui-btn,.ui-controlgroup .ui-radio .ui-btn{margin:0}.ui-checkbox .ui-btn-inner,.ui-radio .ui-btn-inner{white-space:normal}.ui-checkbox .ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-btn-icon-left .ui-btn-inner{padding-left:45px}.ui-checkbox .ui-mini.ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-mini.ui-btn-icon-left .ui-btn-inner{padding-left:36px}.ui-checkbox .ui-btn-icon-right .ui-btn-inner,.ui-radio .ui-btn-icon-right .ui-btn-inner{padding-right:45px}.ui-checkbox .ui-mini.ui-btn-icon-right .ui-btn-inner,.ui-radio .ui-mini.ui-btn-icon-right .ui-btn-inner{padding-right:36px}.ui-checkbox .ui-btn-icon-top .ui-btn-inner,.ui-radio .ui-btn-icon-top .ui-btn-inner{padding-right:0;padding-left:0;text-align:center}.ui-checkbox .ui-btn-icon-bottom .ui-btn-inner,.ui-radio .ui-btn-icon-bottom .ui-btn-inner{padding-right:0;padding-left:0;text-align:center}.ui-checkbox .ui-icon,.ui-radio .ui-icon{top:1.1em}.ui-checkbox .ui-btn-icon-left .ui-icon,.ui-radio .ui-btn-icon-left .ui-icon{left:15px}.ui-checkbox .ui-mini.ui-btn-icon-left .ui-icon,.ui-radio .ui-mini.ui-btn-icon-left .ui-icon{left:9px}.ui-checkbox .ui-btn-icon-right .ui-icon,.ui-radio .ui-btn-icon-right .ui-icon{right:15px}.ui-checkbox .ui-mini.ui-btn-icon-right .ui-icon,.ui-radio .ui-mini.ui-btn-icon-right .ui-icon{right:9px}.ui-checkbox .ui-btn-icon-top .ui-icon,.ui-radio .ui-btn-icon-top .ui-icon{top:10px}.ui-checkbox .ui-btn-icon-bottom .ui-icon,.ui-radio .ui-btn-icon-bottom .ui-icon{top:auto;bottom:10px}.ui-checkbox .ui-btn-icon-right .ui-icon,.ui-radio .ui-btn-icon-right .ui-icon{right:15px}.ui-checkbox .ui-mini.ui-btn-icon-right .ui-icon,.ui-radio .ui-mini.ui-btn-icon-right .ui-icon{right:9px}.ui-controlgroup-horizontal .ui-checkbox .ui-icon,.ui-controlgroup-horizontal .ui-radio .ui-icon{display:none}.ui-controlgroup-horizontal .ui-checkbox .ui-btn-inner,.ui-controlgroup-horizontal .ui-radio .ui-btn-inner{padding:.6em 20px}.ui-controlgroup-horizontal .ui-checkbox .ui-mini .ui-btn-inner,.ui-controlgroup-horizontal .ui-radio .ui-mini .ui-btn-inner{padding:.55em 11px .5em}.ui-checkbox input,.ui-radio input{position:absolute;left:20px;top:50%;width:10px;height:10px;margin:-5px 0 0 0;outline:0!important;z-index:1}.ui-field-contain,fieldset.ui-field-contain{padding:.8em 0;margin:0;border-width:0 0 1px 0;overflow:visible}.ui-field-contain:last-child{border-bottom-width:0}.ui-field-contain{max-width:100%}@media all and (min-width:28em){.ui-field-contain,.ui-mobile fieldset.ui-field-contain{border-width:0;padding:0;margin:1em 0}}.ui-select{display:block;position:relative}.ui-select select{position:absolute;left:-9999px;top:-9999px}.ui-select .ui-btn{opacity:1}.ui-field-contain .ui-select .ui-btn{margin:0}.ui-select .ui-btn select{cursor:pointer;-webkit-appearance:none;left:0;top:0;width:100%;min-height:1.5em;min-height:100%;height:3em;max-height:100%;filter:Alpha(Opacity=0);opacity:0;z-index:2}.ui-select .ui-disabled{opacity:.3}.ui-select .ui-disabled select{display:none}@-moz-document url-prefix(){.ui-select .ui-btn select{opacity:0.0001}}.ui-select .ui-btn.ui-select-nativeonly{border-radius:0;border:0}.ui-select .ui-btn.ui-select-nativeonly select{opacity:1;text-indent:0;display:block}.ui-select .ui-disabled.ui-select-nativeonly .ui-btn-inner{opacity:0}.ui-select .ui-btn-icon-right .ui-btn-inner,.ui-select .ui-li-has-count .ui-btn-inner{padding-right:45px}.ui-select .ui-mini.ui-btn-icon-right .ui-btn-inner{padding-right:32px}.ui-select .ui-btn-icon-right.ui-li-has-count .ui-btn-inner{padding-right:80px}.ui-select .ui-mini.ui-btn-icon-right.ui-li-has-count .ui-btn-inner{padding-right:67px}.ui-select .ui-btn-icon-right .ui-icon{right:15px}.ui-select .ui-mini.ui-btn-icon-right .ui-icon{right:7px}.ui-select .ui-btn-icon-right.ui-li-has-count .ui-li-count{right:45px}.ui-select .ui-mini.ui-btn-icon-right.ui-li-has-count .ui-li-count{right:32px}label.ui-select{font-size:16px;line-height:1.4;font-weight:normal;margin:0 0 .3em;display:block}.ui-select .ui-btn-text,.ui-selectmenu .ui-btn-text{display:block;min-height:1em;overflow:hidden!important}.ui-select .ui-btn-text{text-overflow:ellipsis}.ui-selectmenu{padding:6px;min-width:160px}.ui-selectmenu .ui-listview{margin:0}.ui-selectmenu .ui-btn.ui-li-divider{cursor:default}.ui-screen-hidden,.ui-selectmenu-list .ui-li .ui-icon{display:none}.ui-selectmenu-list .ui-li .ui-icon{display:block}.ui-li.ui-selectmenu-placeholder{display:none}.ui-selectmenu .ui-header{margin:0;padding:0}.ui-selectmenu.ui-popup .ui-header{-webkit-border-top-left-radius:0;border-top-left-radius:0;-webkit-border-top-right-radius:0;border-top-right-radius:0}.ui-selectmenu .ui-header .ui-title{margin:0.6em 46px 0.8em}@media all and (min-width:28em){.ui-field-contain label.ui-select{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain .ui-select{width:78%;display:inline-block}.ui-hide-label .ui-select{width:100%}}.ui-selectmenu .ui-header h1:after{content:'.';visibility:hidden}label.ui-input-text{font-size:16px;line-height:1.4;display:block;font-weight:normal;margin:0 0 .3em}input.ui-input-text,textarea.ui-input-text{background-image:none;padding:.4em;margin:.5em 0;min-height:1.4em;line-height:1.4em;font-size:16px;display:block;width:100%;outline:0}input.ui-mini,.ui-mini input,textarea.ui-mini{font-size:14px}div.ui-input-text input.ui-input-text,div.ui-input-text textarea.ui-input-text,.ui-input-search input.ui-input-text{border:none;width:100%;padding:.4em 0;margin:0;display:block;background:transparent none;outline:0!important}.ui-input-search,div.ui-input-text{margin:.5em 0;background-image:none;position:relative}.ui-input-search{padding:0 30px}div.ui-input-text{padding:0 .4em}div.ui-input-has-clear{padding:0 30px 0 .4em}input.ui-input-text.ui-mini,textarea.ui-input-text.ui-mini,.ui-input-search.ui-mini,div.ui-input-text.ui-mini{margin:.25em 0}.ui-field-contain input.ui-input-text,.ui-field-contain textarea.ui-input-text,.ui-field-contain .ui-input-search,.ui-field-contain div.ui-input-text{margin:0}textarea.ui-input-text{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}input.ui-input-text{-webkit-appearance:none}textarea.ui-input-text{height:50px;-webkit-transition:height 200ms linear;-moz-transition:height 200ms linear;-o-transition:height 200ms linear;transition:height 200ms linear}textarea.ui-mini{height:45px}.ui-icon-searchfield:after{position:absolute;left:7px;top:50%;margin-top:-9px;content:"";width:18px;height:18px;opacity:.5}.ui-input-search .ui-input-clear,.ui-input-text .ui-input-clear{position:absolute;right:0;top:50%;margin-top:-13px}.ui-mini .ui-input-clear{margin-top:-14px;right:-3px}.ui-input-search .ui-input-clear-hidden,.ui-input-text .ui-input-clear-hidden{display:none}input::-moz-placeholder,textarea::-moz-placeholder{color:#aaa}input[type=number]::-webkit-outer-spin-button{margin:0}@media all and (min-width:28em){.ui-field-contain label.ui-input-text{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain input.ui-input-text,.ui-field-contain textarea.ui-input-text,.ui-field-contain .ui-input-search,.ui-field-contain div.ui-input-text{width:78%;display:inline-block}.ui-field-contain .ui-input-search,.ui-field-contain div.ui-input-text{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.ui-hide-label input.ui-input-text,.ui-hide-label textarea.ui-input-text,.ui-hide-label .ui-input-search,.ui-hide-label div.ui-input-text,.ui-input-search input.ui-input-text,div.ui-input-text input.ui-input-text{width:100%}}.ui-rangeslider{zoom:1;margin:0}.ui-rangeslider:before,.ui-rangeslider:after{content:"";display:table}.ui-rangeslider:after{clear:both}.ui-rangeslider input.ui-input-text.ui-slider-input{margin:.57143em 0}.ui-rangeslider.ui-mini input.ui-slider-input{margin:.28571em 0}.ui-rangeslider input.ui-slider-input.ui-rangeslider-last{float:right}.ui-rangeslider .ui-rangeslider-sliders{position:relative;overflow:visible;height:30px;margin:.5em 68px}.ui-rangeslider.ui-mini .ui-rangeslider-sliders{margin:.25em 68px}.ui-field-contain .ui-rangeslider input.ui-slider-input,.ui-field-contain .ui-rangeslider.ui-mini input.ui-slider-input,.ui-field-contain .ui-rangeslider .ui-rangeslider-sliders,.ui-field-contain .ui-rangeslider.ui-mini .ui-rangeslider-sliders{margin-top:0;margin-bottom:0}.ui-rangeslider .ui-rangeslider-sliders .ui-slider-track{position:absolute;top:6px;right:0;left:0;margin:0}.ui-rangeslider.ui-mini .ui-rangeslider-sliders .ui-slider-track{top:8px}.ui-rangeslider .ui-slider-track:first-child .ui-slider-bg{display:none}.ui-rangeslider .ui-rangeslider-sliders .ui-slider-track:first-child{background-color:transparent;background:none;border-width:0;height:0}html >body .ui-rangeslider.ui-mini .ui-rangeslider-sliders .ui-slider-track:first-child{height:12px}@media all and (min-width:28em){.ui-field-contain .ui-rangeslider label.ui-slider{float:left}.ui-field-contain .ui-rangeslider input.ui-slider-input{position:relative;z-index:1}.ui-field-contain .ui-rangeslider input.ui-slider-input.ui-rangeslider-first,.ui-field-contain .ui-rangeslider.ui-mini input.ui-slider-input.ui-rangeslider-first{margin-right:17px}.ui-field-contain .ui-rangeslider .ui-rangeslider-sliders,.ui-field-contain .ui-rangeslider.ui-mini .ui-rangeslider-sliders{float:left;width:78%;margin:0 -68px}.ui-field-contain .ui-rangeslider .ui-slider-track,.ui-field-contain .ui-rangeslider.ui-mini .ui-slider-track{right:68px;left:68px}.ui-field-contain.ui-hide-label .ui-rangeslider input.ui-slider-input.ui-rangeslider-first{margin:0}.ui-field-contain.ui-hide-label .ui-rangeslider .ui-rangeslider-sliders,.ui-field-contain.ui-hide-label .ui-rangeslider.ui-mini .ui-rangeslider-sliders{width:auto;float:none;margin:0 68px}.ui-field-contain.ui-hide-label .ui-rangeslider .ui-slider-track,.ui-field-contain.ui-hide-label .ui-rangeslider.ui-mini .ui-slider-track{right:0;left:0}}.ui-listview{margin:0}ol.ui-listview,ol.ui-listview .ui-li-divider{counter-reset:listnumbering}.ui-content .ui-listview,.ui-panel-inner > .ui-listview{margin:-15px}.ui-collapsible-content > .ui-listview{margin:-10px -15px}.ui-content .ui-listview-inset,.ui-panel-inner .ui-listview-inset{margin:1em 0}.ui-collapsible-content .ui-listview-inset{margin:.5em 0}.ui-listview,.ui-li{list-style:none;padding:0}.ui-li,.ui-li.ui-field-contain{display:block;margin:0;position:relative;overflow:visible;text-align:left;border-width:0;border-top-width:1px}.ui-li.ui-btn,.ui-li.ui-field-contain,.ui-li-divider,.ui-li-static{margin:0}.ui-listview-inset .ui-li{border-right-width:1px;border-left-width:1px}.ui-li.ui-last-child,.ui-li.ui-field-contain.ui-last-child{border-bottom-width:1px}.ui-collapsible-content > .ui-listview:not(.ui-listview-inset) > .ui-li.ui-first-child{border-top-width:0}.ui-collapsible-themed-content .ui-listview:not(.ui-listview-inset) > .ui-li.ui-last-child{border-bottom-width:0}.ui-li .ui-btn-text a.ui-link-inherit{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-static{background-image:none}.ui-li-divider{padding:.5em 15px;font-size:14px;font-weight:bold}ol.ui-listview .ui-link-inherit:before,ol.ui-listview .ui-li-static:before,.ui-li-dec{font-size:.8em;display:inline-block;padding-right:.3em;font-weight:normal;counter-increment:listnumbering;content:counter(listnumbering) ". "}ol.ui-listview .ui-li-jsnumbering:before{content:""!important}.ui-listview > .ui-li.ui-first-child,.ui-listview .ui-btn.ui-first-child > .ui-li > .ui-btn-text > .ui-link-inherit{-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit;-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit}.ui-listview > .ui-li.ui-last-child,.ui-listview .ui-btn.ui-last-child > .ui-li > .ui-btn-text > .ui-link-inherit,.ui-collapsible-content > .ui-listview:not(.ui-listview-inset),.ui-collapsible-content > .ui-listview:not(.ui-listview-inset) .ui-li.ui-last-child{-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit;-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit}.ui-listview > .ui-li.ui-first-child .ui-li-link-alt{-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit}.ui-listview > .ui-li.ui-last-child .ui-li-link-alt{-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit}.ui-listview > .ui-li.ui-first-child .ui-li-thumb:not(.ui-li-icon){-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit}.ui-listview > .ui-li.ui-last-child .ui-li-thumb:not(.ui-li-icon){-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit}.ui-li>.ui-btn-inner{display:block;position:relative;padding:0}.ui-li .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li{padding:.7em 15px;display:block}.ui-li-has-thumb .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-thumb{min-height:59px;padding-left:100px}.ui-li-has-icon .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-icon{min-height:20px;padding-left:40px}.ui-li-has-count .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-count,.ui-li-divider.ui-li-has-count{padding-right:45px}.ui-li-has-arrow .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-arrow{padding-right:40px}.ui-li-has-arrow.ui-li-has-count .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-arrow.ui-li-has-count{padding-right:75px}.ui-li-heading{font-size:16px;font-weight:bold;display:block;margin:.6em 0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-desc{font-size:12px;font-weight:normal;display:block;margin:-.5em 0 .6em;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-thumb,.ui-listview .ui-li-icon{position:absolute;left:1px;top:0;max-height:80px;max-width:80px}.ui-listview .ui-li-icon{max-height:16px;max-width:16px;left:10px;top:.9em}.ui-li-thumb,.ui-listview .ui-li-icon,.ui-li-content{float:left;margin-right:10px}.ui-li-aside{float:right;width:50%;text-align:right;margin:.3em 0}@media all and (min-width:480px){.ui-li-aside{width:45%}}.ui-li-divider{cursor:default}.ui-li-has-alt .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-alt{padding-right:53px}.ui-li-has-alt.ui-li-has-count .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-alt.ui-li-has-count{padding-right:88px}.ui-li-has-count .ui-li-count{position:absolute;font-size:11px;font-weight:bold;padding:.2em .5em;top:50%;margin-top:-.9em;right:10px}.ui-li-has-count.ui-li-divider .ui-li-count,.ui-li-has-count .ui-link-inherit .ui-li-count{margin-top:-.95em}.ui-li-has-arrow.ui-li-has-count .ui-li-count{right:40px}.ui-li-has-alt.ui-li-has-count .ui-li-count{right:53px}.ui-li-link-alt{position:absolute;width:40px;height:100%;border-width:0;border-left-width:1px;top:0;right:0;margin:0;padding:0;z-index:2}.ui-li-link-alt .ui-btn{overflow:hidden;position:absolute;right:8px;top:50%;margin:-13px 0 0 0;border-bottom-width:1px;z-index:-1}.ui-li-link-alt .ui-btn-inner{padding:0;height:100%;position:absolute;width:100%;top:0;left:0}.ui-li-link-alt .ui-btn .ui-icon{right:50%;margin-right:-9px}.ui-li-link-alt .ui-btn-icon-notext .ui-btn-inner .ui-icon{position:absolute;top:50%;margin-top:-9px}.ui-listview * .ui-btn-inner > .ui-btn > .ui-btn-inner{border-top:0}.ui-listview-filter{border-width:0;overflow:hidden;margin:-15px -15px 15px -15px}.ui-collapsible-content .ui-listview-filter{margin:-10px -15px 10px -15px;border-bottom:inherit}.ui-listview-filter-inset{margin:-15px -5px;background:transparent}.ui-collapsible-content .ui-listview-filter-inset{margin:-5px;border-bottom-width:0}.ui-listview-filter .ui-input-search{margin:5px;width:auto;display:block}.ui-li.ui-screen-hidden{display:none}@media only screen and (min-device-width:768px) and (max-device-width:1024px){.ui-li .ui-btn-text{overflow:visible}}label.ui-slider{font-size:16px;line-height:1.4;font-weight:normal;margin:0;display:block}.ui-field-contain label.ui-slider{margin-bottom:.4em}div.ui-slider{height:30px;margin:.5em 0;zoom:1}div.ui-slider.ui-mini{margin:.25em 0}.ui-field-contain div.ui-slider,.ui-field-contain div.ui-slider.ui-mini{margin:0}div.ui-slider:before,div.ui-slider:after{content:"";display:table}div.ui-slider:after{clear:both}input.ui-input-text.ui-slider-input{display:block;float:left;margin:0;padding:4px;width:40px;height:22px;line-height:22px;font-size:14px;border:none;background-image:none;font-weight:bold;text-align:center;vertical-align:text-bottom;outline:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;-ms-box-sizing:content-box;box-sizing:content-box}.ui-slider-input::-webkit-outer-spin-button,.ui-slider-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.ui-slider-track,.ui-slider-switch{position:relative;overflow:visible;height:15px;margin:0 15px 0 68px;top:6px}.ui-slider-track.ui-mini{height:12px;top:8px}.ui-slider-bg{border:none;height:100%}.ui-slider-track .ui-btn.ui-slider-handle,.ui-slider-switch .ui-btn.ui-slider-handle{position:absolute;z-index:1;top:50%;width:28px;height:28px;margin:-15px 0 0 -15px;outline:0}.ui-slider-track.ui-mini .ui-slider-handle{height:14px;width:14px;margin:-8px 0 0 -7px}.ui-slider-handle .ui-btn-inner{padding:0;height:100%}.ui-slider-track.ui-mini .ui-slider-handle .ui-btn-inner{height:30px;width:30px;padding:0;margin:-9px 0 0 -9px;border-top:none}select.ui-slider-switch{display:none}div.ui-slider-switch{display:inline-block;height:32px;width:5.8em;margin:.5em 0;top:0}div.ui-slider-switch.ui-mini{width:5em;height:29px;margin:.25em 0;top:0}.ui-field-contain .ui-slider-switch,.ui-field-contain .ui-slider-switch.ui-mini{margin:0}.ui-slider-inneroffset{margin:0 16px;position:relative;z-index:1}.ui-slider-switch.ui-mini .ui-slider-inneroffset{margin:0 15px 0 14px}.ui-slider-switch .ui-btn.ui-slider-handle{margin:1px 0 0 -15px}.ui-slider-switch.ui-mini .ui-slider-handle{width:25px;height:25px;margin:1px 0 0 -13px;padding:0}.ui-slider-handle-snapping{-webkit-transition:left 70ms linear;-moz-transition:left 70ms linear}.ui-slider-switch.ui-mini .ui-slider-handle .ui-btn-inner{height:30px;width:30px;padding:0;margin:0;border-top:none}.ui-slider-switch .ui-slider-label{position:absolute;text-align:center;width:100%;overflow:hidden;font-size:16px;top:0;line-height:2;min-height:100%;border-width:0;white-space:nowrap;cursor:pointer}.ui-slider-switch.ui-mini .ui-slider-label{font-size:14px}.ui-slider-switch .ui-slider-label-a{z-index:1;left:0;text-indent:-1.5em}.ui-slider-switch .ui-slider-label-b{z-index:0;right:0;text-indent:1.5em}@media all and (min-width:28em){.ui-field-contain label.ui-slider{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain div.ui-slider{display:inline-block;width:78%}.ui-field-contain.ui-hide-label div.ui-slider{display:block;width:auto}.ui-field-contain div.ui-slider-switch,.ui-field-contain.ui-hide-label div.ui-slider-switch{display:inline-block;width:5.8em}.ui-field-contain div.ui-slider-switch.ui-mini{width:5em}}.ui-table{border:0;border-collapse:collapse;padding:0;width:100%}.ui-table th,.ui-table td{line-height:1.5em;text-align:left;padding:.4em .5em;vertical-align:top}.ui-table th .ui-btn,.ui-table td .ui-btn{line-height:normal}.ui-table th{font-weight:bold}.ui-table caption{text-align:left;margin-bottom:1.4em;opacity:.5}.table-stroke thead th{border-bottom:1px solid #d6d6d6;border-bottom:1px solid rgba(0,0,0,.1)}.table-stroke tbody th,.table-stroke tbody td{border-bottom:1px solid #e6e6e6;border-bottom:1px solid rgba(0,0,0,.05)}.table-stripe tbody tr:nth-child(odd) td,.table-stripe tbody tr:nth-child(odd) th{background-color:#eee;background-color:rgba(0,0,0,0.04)}.table-stripe thead th,.table-stripe tbody tr:last-child{border-bottom:1px solid #d6d6d6;border-bottom:1px solid rgba(0,0,0,.1)}.ui-table-columntoggle-btn{float:right;margin-bottom:.8em}.ui-table-columntoggle-popup fieldset{margin:0}@media only all{th.ui-table-priority-6,td.ui-table-priority-6,th.ui-table-priority-5,td.ui-table-priority-5,th.ui-table-priority-4,td.ui-table-priority-4,th.ui-table-priority-3,td.ui-table-priority-3,th.ui-table-priority-2,td.ui-table-priority-2,th.ui-table-priority-1,td.ui-table-priority-1{display:none}}@media screen and (min-width:20em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-1,.ui-table-columntoggle.ui-responsive td.ui-table-priority-1{display:table-cell}}@media screen and (min-width:30em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-2,.ui-table-columntoggle.ui-responsive td.ui-table-priority-2{display:table-cell}}@media screen and (min-width:40em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-3,.ui-table-columntoggle.ui-responsive td.ui-table-priority-3{display:table-cell}}@media screen and (min-width:50em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-4,.ui-table-columntoggle.ui-responsive td.ui-table-priority-4{display:table-cell}}@media screen and (min-width:60em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-5,.ui-table-columntoggle.ui-responsive td.ui-table-priority-5{display:table-cell}}@media screen and (min-width:70em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-6,.ui-table-columntoggle.ui-responsive td.ui-table-priority-6{display:table-cell}}.ui-table-columntoggle th.ui-table-cell-hidden,.ui-table-columntoggle td.ui-table-cell-hidden,.ui-table-columntoggle.ui-responsive th.ui-table-cell-hidden,.ui-table-columntoggle.ui-responsive td.ui-table-cell-hidden{display:none}.ui-table-columntoggle th.ui-table-cell-visible,.ui-table-columntoggle td.ui-table-cell-visible,.ui-table-columntoggle.ui-responsive th.ui-table-cell-visible,.ui-table-columntoggle.ui-responsive td.ui-table-cell-visible{display:table-cell}.ui-table-reflow td .ui-table-cell-label,.ui-table-reflow th .ui-table-cell-label{display:none}@media only all{.ui-table-reflow thead td,.ui-table-reflow thead th{display:none}.ui-table-reflow td,.ui-table-reflow th{text-align:left;display:block}.ui-table-reflow tbody th{margin-top:3em}.ui-table-reflow td .ui-table-cell-label,.ui-table-reflow th .ui-table-cell-label{display:block;padding:.4em;min-width:30%;display:inline-block;margin:-.4em 1em -.4em -.4em}.ui-table-reflow th .ui-table-cell-label-top,.ui-table-reflow td .ui-table-cell-label-top{display:block;padding:.4em 0;margin:.4em 0;text-transform:uppercase;font-size:.9em;font-weight:normal}}@media ( min-width:35em ){.ui-table-reflow.ui-responsive{display:table-row-group}.ui-table-reflow.ui-responsive td,.ui-table-reflow.ui-responsive th,.ui-table-reflow.ui-responsive tbody th,.ui-table-reflow.ui-responsive tbody td,.ui-table-reflow.ui-responsive thead td,.ui-table-reflow.ui-responsive thead th{display:table-cell;margin:0}.ui-table-reflow.ui-responsive td .ui-table-cell-label,.ui-table-reflow.ui-responsive th .ui-table-cell-label{display:none}}@media ( max-width:35em ){.ui-table-reflow.ui-responsive td,.ui-table-reflow.ui-responsive th{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;clear:left}}.ui-panel{width:17em;min-height:100%;border-width:0;position:absolute;top:0;display:block}.ui-panel-closed{width:0;overflow:hidden}.ui-panel-fixed{position:fixed;bottom:-1px;padding-bottom:1px}.ui-panel-display-overlay{z-index:1001}.ui-panel-display-reveal{z-index:0}.ui-panel-display-push{z-index:999}.ui-panel-inner{padding:15px}.ui-panel-content-wrap{position:relative;left:0;min-height:inherit;border:none;z-index:999}.ui-panel-content-wrap-display-overlay,.ui-panel-animate.ui-panel-content-wrap > .ui-header,.ui-panel-content-wrap-closed{position:static}.ui-panel-dismiss{position:absolute;top:0;left:0;height:100%;width:100%;z-index:1002;display:none}.ui-panel-dismiss-open{display:block}.ui-panel-animate{-webkit-transition:-webkit-transform 350ms ease;-moz-transition:-moz-transform 350ms ease;transition:transform 350ms ease}.ui-panel-animate.ui-panel:not(.ui-panel-display-reveal),.ui-panel-animate.ui-panel:not(.ui-panel-display-reveal) > div,.ui-panel-animate.ui-panel-content-wrap,.ui-panel-animate.ui-panel-content-fixed-toolbar{-webkit-backface-visibility:hidden;-webkit-transform:translate3d(0,0,0)}.ui-panel-position-left{left:-17em}.ui-panel-animate.ui-panel-position-left.ui-panel-display-overlay,.ui-panel-animate.ui-panel-position-left.ui-panel-display-push{left:0;-webkit-transform:translate3d(-17em,0,0);-moz-transform:translate3d(-17em,0,0);transform:translate3d(-17em,0,0)}.ui-panel-position-left.ui-panel-display-reveal,.ui-panel-position-left.ui-panel-open{left:0}.ui-panel-animate.ui-panel-position-left.ui-panel-open.ui-panel-display-overlay,.ui-panel-animate.ui-panel-position-left.ui-panel-open.ui-panel-display-push{-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.ui-panel-position-right{right:-17em}.ui-panel-animate.ui-panel-position-right.ui-panel-display-overlay,.ui-panel-animate.ui-panel-position-right.ui-panel-display-push{right:0;-webkit-transform:translate3d(17em,0,0);-moz-transform:translate3d(17em,0,0);transform:translate3d(17em,0,0)}.ui-panel-position-right.ui-panel-display-reveal,.ui-panel-position-right.ui-panel-open{right:0}.ui-panel-animate.ui-panel-position-right.ui-panel-open.ui-panel-display-overlay,.ui-panel-animate.ui-panel-position-right.ui-panel-open.ui-panel-display-push{-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open,.ui-panel-content-wrap-position-left.ui-panel-content-wrap-open,.ui-panel-dismiss-position-left.ui-panel-dismiss-open{left:17em;right:-17em}.ui-panel-animate.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-reveal,.ui-panel-animate.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push,.ui-panel-animate.ui-panel-content-wrap-position-left.ui-panel-content-wrap-open.ui-panel-content-wrap-display-reveal,.ui-panel-animate.ui-panel-content-wrap-position-left.ui-panel-content-wrap-open.ui-panel-content-wrap-display-push{left:0;right:0;-webkit-transform:translate3d(17em,0,0);-moz-transform:translate3d(17em,0,0);transform:translate3d(17em,0,0)}.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open,.ui-panel-content-wrap-position-right.ui-panel-content-wrap-open,.ui-panel-dismiss-position-right.ui-panel-dismiss-open{left:-17em;right:17em}.ui-panel-animate.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-reveal,.ui-panel-animate.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push,.ui-panel-animate.ui-panel-content-wrap-position-right.ui-panel-content-wrap-open.ui-panel-content-wrap-display-reveal,.ui-panel-animate.ui-panel-content-wrap-position-right.ui-panel-content-wrap-open.ui-panel-content-wrap-display-push{left:0;right:0;-webkit-transform:translate3d(-17em,0,0);-moz-transform:translate3d(-17em,0,0);transform:translate3d(-17em,0,0)}.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-overlay,.ui-panel-content-wrap-open.ui-panel-content-wrap-display-overlay{left:0}.ui-page-active.ui-page-panel{overflow-x:hidden}.ui-panel-display-reveal{-webkit-box-shadow:inset -5px 0 5px rgba(0,0,0,.15);-moz-box-shadow:inset -5px 0 5px rgba(0,0,0,.15);box-shadow:inset -5px 0 5px rgba(0,0,0,.15)}.ui-panel-position-right.ui-panel-display-reveal{-webkit-box-shadow:inset 5px 0 5px rgba(0,0,0,.15);-moz-box-shadow:inset 5px 0 5px rgba(0,0,0,.15);box-shadow:inset 5px 0 5px rgba(0,0,0,.15)}.ui-panel-position-right.ui-panel-display-overlay{-webkit-box-shadow:-5px 0 5px rgba(0,0,0,.15);-moz-box-shadow:-5px 0 5px rgba(0,0,0,.15);box-shadow:-5px 0 5px rgba(0,0,0,.15)}.ui-panel-position-left.ui-panel-display-overlay{-webkit-box-shadow:5px 0 5px rgba(0,0,0,.15);-moz-box-shadow:5px 0 5px rgba(0,0,0,.15);box-shadow:5px 0 5px rgba(0,0,0,.15)}.ui-panel-display-push.ui-panel-open.ui-panel-position-left{border-right-width:1px;margin-right:-1px}.ui-panel-animate.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push{margin-left:1px}.ui-panel-display-push.ui-panel-open.ui-panel-position-right{border-left-width:1px;margin-left:-1px}.ui-panel-animate.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push{margin-right:1px}@media (min-width:55em){.ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-push.ui-panel-content-fixed-toolbar-position-left,.ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-reveal.ui-panel-content-fixed-toolbar-position-left,.ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-push.ui-panel-content-wrap-position-left,.ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-reveal.ui-panel-content-wrap-position-left{margin-right:17em}.ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-push.ui-panel-content-fixed-toolbar-position-right,.ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-reveal.ui-panel-content-fixed-toolbar-position-right,.ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-push.ui-panel-content-wrap-position-right,.ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-reveal.ui-panel-content-wrap-position-right{margin-left:17em}.ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-push,.ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-reveal{width:auto}.ui-responsive-panel .ui-panel-dismiss-display-push{display:none}} \ No newline at end of file diff --git a/www/jquery.mobile-1.3.0/jquery.mobile-1.3.0.min.js b/www/jquery.mobile-1.3.0/jquery.mobile-1.3.0.min.js deleted file mode 100644 index 9363e28..0000000 --- a/www/jquery.mobile-1.3.0/jquery.mobile-1.3.0.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery Mobile vGit Build: SHA1: caa77b258660731d663844fe7867aa2c3a107ab1 <> Date: Wed Feb 20 15:03:27 2013 -0500 jquerymobile.com | jquery.org/license !*/ -(function(a,b,c){typeof define=="function"&&define.amd?define(["jquery"],function(d){return c(d,a,b),d.mobile}):c(a.jQuery,a,b)})(this,document,function(a,b,c,d){(function(a){a.mobile={}})(a),function(a,b,d){var e={};a.mobile=a.extend(a.mobile,{version:"1.3.0",ns:"",subPageUrlKey:"ui-page",activePageClass:"ui-page-active",activeBtnClass:"ui-btn-active",focusClass:"ui-focus",ajaxEnabled:!0,hashListeningEnabled:!0,linkBindingEnabled:!0,defaultPageTransition:"fade",maxTransitionWidth:!1,minScrollBack:250,touchOverflowEnabled:!1,defaultDialogTransition:"pop",pageLoadErrorMessage:"Error Loading Page",pageLoadErrorMessageTheme:"e",phonegapNavigationEnabled:!1,autoInitializePage:!0,pushStateEnabled:!0,ignoreContentEnabled:!1,orientationChangeEnabled:!0,buttonMarkup:{hoverDelay:200},window:a(b),document:a(c),keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91},behaviors:{},silentScroll:function(c){a.type(c)!=="number"&&(c=a.mobile.defaultHomeScroll),a.event.special.scrollstart.enabled=!1,setTimeout(function(){b.scrollTo(0,c),a.mobile.document.trigger("silentscroll",{x:0,y:c})},20),setTimeout(function(){a.event.special.scrollstart.enabled=!0},150)},nsNormalizeDict:e,nsNormalize:function(b){if(!b)return;return e[b]||(e[b]=a.camelCase(a.mobile.ns+b))},getInheritedTheme:function(a,b){var c=a[0],d="",e=/ui-(bar|body|overlay)-([a-z])\b/,f,g;while(c){f=c.className||"";if(f&&(g=e.exec(f))&&(d=g[2]))break;c=c.parentNode}return d||b||"a"},closestPageData:function(a){return a.closest(':jqmData(role="page"), :jqmData(role="dialog")').data("mobile-page")},enhanceable:function(a){return this.haveParents(a,"enhance")},hijackable:function(a){return this.haveParents(a,"ajax")},haveParents:function(b,c){if(!a.mobile.ignoreContentEnabled)return b;var d=b.length,e=a(),f,g,h;for(var i=0;i").text(a(this).text()).html()},a.fn.jqmEnhanceable=function(){return a.mobile.enhanceable(this)},a.fn.jqmHijackable=function(){return a.mobile.hijackable(this)};var f=a.find,g=/:jqmData\(([^)]*)\)/g;a.find=function(b,c,d,e){return b=b.replace(g,"[data-"+(a.mobile.ns||"")+"$1]"),f.call(this,b,c,d,e)},a.extend(a.find,f),a.find.matches=function(b,c){return a.find(b,null,null,c)},a.find.matchesSelector=function(b,c){return a.find(c,null,null,[b]).length>0}}(a,this),function(a,b){var c=0,d=Array.prototype.slice,e=a.cleanData;a.cleanData=function(b){for(var c=0,d;(d=b[c])!=null;c++)try{a(d).triggerHandler("remove")}catch(f){}e(b)},a.widget=function(b,c,d){var e,f,g,h,i=b.split(".")[0];b=b.split(".")[1],e=i+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][e.toLowerCase()]=function(b){return!!a.data(b,e)},a[i]=a[i]||{},f=a[i][b],g=a[i][b]=function(a,b){if(!this._createWidget)return new g(a,b);arguments.length&&this._createWidget(a,b)},a.extend(g,f,{version:d.version,_proto:a.extend({},d),_childConstructors:[]}),h=new c,h.options=a.widget.extend({},h.options),a.each(d,function(b,e){a.isFunction(e)&&(d[b]=function(){var a=function(){return c.prototype[b].apply(this,arguments)},d=function(a){return c.prototype[b].apply(this,a)};return function(){var b=this._super,c=this._superApply,f;return this._super=a,this._superApply=d,f=e.apply(this,arguments),this._super=b,this._superApply=c,f}}())}),g.prototype=a.widget.extend(h,{widgetEventPrefix:f?h.widgetEventPrefix:b},d,{constructor:g,namespace:i,widgetName:b,widgetFullName:e}),f?(a.each(f._childConstructors,function(b,c){var d=c.prototype;a.widget(d.namespace+"."+d.widgetName,g,c._proto)}),delete f._childConstructors):c._childConstructors.push(g),a.widget.bridge(b,g)},a.widget.extend=function(c){var e=d.call(arguments,1),f=0,g=e.length,h,i;for(;f",options:{disabled:!1,create:null},_createWidget:function(b,d){d=a(d||this.defaultElement||this)[0],this.element=a(d),this.uuid=c++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=a.widget.extend({},this.options,this._getCreateOptions(),b),this.bindings=a(),this.hoverable=a(),this.focusable=a(),d!==this&&(a.data(d,this.widgetFullName,this),this._on(!0,this.element,{remove:function(a){a.target===d&&this.destroy()}}),this.document=a(d.style?d.ownerDocument:d.document||d),this.window=a(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:a.noop,_getCreateEventData:a.noop,_create:a.noop,_init:a.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(a.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:a.noop,widget:function(){return this.element},option:function(c,d){var e=c,f,g,h;if(arguments.length===0)return a.widget.extend({},this.options);if(typeof c=="string"){e={},f=c.split("."),c=f.shift();if(f.length){g=e[c]=a.widget.extend({},this.options[c]);for(h=0;h"+""+"

"+"",fakeFixLoader:function(){var b=a("."+a.mobile.activeBtnClass).first();this.element.css({top:a.support.scrollTop&&f.scrollTop()+f.height()/2||b.length&&b.offset().top||100})},checkLoaderPosition:function(){var b=this.element.offset(),c=f.scrollTop(),d=a.mobile.getScreenHeight();if(b.topd)this.element.addClass("ui-loader-fakefix"),this.fakeFixLoader(),f.unbind("scroll",this.checkLoaderPosition).bind("scroll",a.proxy(this.fakeFixLoader,this))},resetHtml:function(){this.element.html(a(this.defaultHtml).html())},show:function(b,g,h){var i,j,k,l;this.resetHtml(),a.type(b)==="object"?(l=a.extend({},this.options,b),b=l.theme||a.mobile.loadingMessageTheme):(l=this.options,b=b||a.mobile.loadingMessageTheme||l.theme),j=g||a.mobile.loadingMessage||l.text,e.addClass("ui-loading");if(a.mobile.loadingMessage!==!1||l.html)a.mobile.loadingMessageTextVisible!==d?i=a.mobile.loadingMessageTextVisible:i=l.textVisible,this.element.attr("class",c+" ui-corner-all ui-body-"+b+" ui-loader-"+(i||g||b.text?"verbose":"default")+(l.textonly||h?" ui-loader-textonly":"")),l.html?this.element.html(l.html):this.element.find("h1").text(j),this.element.appendTo(a.mobile.pageContainer),this.checkLoaderPosition(),f.bind("scroll",a.proxy(this.checkLoaderPosition,this))},hide:function(){e.removeClass("ui-loading"),a.mobile.loadingMessage&&this.element.removeClass("ui-loader-fakefix"),a.mobile.window.unbind("scroll",this.fakeFixLoader),a.mobile.window.unbind("scroll",this.checkLoaderPosition)}}),f.bind("pagecontainercreate",function(){a.mobile.loaderWidget=a.mobile.loaderWidget||a(a.mobile.loader.prototype.defaultHtml).loader()})}(a,this),function(a,b,d){function k(a){return a=a||location.href,"#"+a.replace(/^[^#]*#?(.*)$/,"$1")}var e="hashchange",f=c,g,h=a.event.special,i=f.documentMode,j="on"+e in b&&(i===d||i>7);a.fn[e]=function(a){return a?this.bind(e,a):this.trigger(e)},a.fn[e].delay=50,h[e]=a.extend(h[e],{setup:function(){if(j)return!1;a(g.start)},teardown:function(){if(j)return!1;a(g.stop)}}),g=function(){function n(){var c=k(),d=m(h);c!==h?(l(h=c,d),a(b).trigger(e)):d!==h&&(location.href=location.href.replace(/#.*/,"")+d),g=setTimeout(n,a.fn[e].delay)}var c={},g,h=k(),i=function(a){return a},l=i,m=i;return c.start=function(){g||n()},c.stop=function(){g&&clearTimeout(g),g=d},b.attachEvent&&!b.addEventListener&&!j&&function(){var b,d;c.start=function(){b||(d=a.fn[e].src,d=d&&d+k(),b=a('