summaryrefslogtreecommitdiff
path: root/StoneIsland/platforms/ios/CordovaLib/Classes/Private
diff options
context:
space:
mode:
authorJules Laplace <jules@okfoc.us>2016-11-08 11:46:59 -0500
committerJules Laplace <jules@okfoc.us>2016-11-08 11:46:59 -0500
commit5fa81da81260d65113f57a293b6256d334fe8e2d (patch)
tree01d3dd7ab7a1febccd20de1756d0801a64ae64e9 /StoneIsland/platforms/ios/CordovaLib/Classes/Private
parente5652e9cd560ccda249819857c207643820b075f (diff)
parent7773d1d0686de69504e9b820efdb3e94d72eff04 (diff)
le build
Diffstat (limited to 'StoneIsland/platforms/ios/CordovaLib/Classes/Private')
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVDebug.h25
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.h31
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.m91
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVPlugin+Private.h24
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.h26
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.m74
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.h27
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.m86
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.h34
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.m142
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLocalStorage/CDVLocalStorage.h50
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLocalStorage/CDVLocalStorage.m487
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.h41
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m400
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.h27
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.m202
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.h29
-rw-r--r--StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.m151
18 files changed, 1947 insertions, 0 deletions
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVDebug.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVDebug.h
new file mode 100644
index 00000000..4a0d9f92
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVDebug.h
@@ -0,0 +1,25 @@
+/*
+ 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.
+ */
+
+#ifdef DEBUG
+ #define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
+#else
+ #define DLog(...)
+#endif
+#define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.h
new file mode 100644
index 00000000..afb5cc66
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.h
@@ -0,0 +1,31 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+@interface NSArray (CDVJSONSerializingPrivate)
+- (NSString*)cdv_JSONString;
+@end
+
+@interface NSDictionary (CDVJSONSerializingPrivate)
+- (NSString*)cdv_JSONString;
+@end
+
+@interface NSString (CDVJSONSerializingPrivate)
+- (id)cdv_JSONObject;
+- (id)cdv_JSONFragment;
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.m
new file mode 100644
index 00000000..53856806
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.m
@@ -0,0 +1,91 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVJSON_private.h"
+#import <Foundation/NSJSONSerialization.h>
+
+@implementation NSArray (CDVJSONSerializingPrivate)
+
+- (NSString*)cdv_JSONString
+{
+ NSError* error = nil;
+ NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self
+ options:0
+ error:&error];
+
+ if (error != nil) {
+ NSLog(@"NSArray JSONString error: %@", [error localizedDescription]);
+ return nil;
+ } else {
+ return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
+ }
+}
+
+@end
+
+@implementation NSDictionary (CDVJSONSerializingPrivate)
+
+- (NSString*)cdv_JSONString
+{
+ NSError* error = nil;
+ NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self
+ options:NSJSONWritingPrettyPrinted
+ error:&error];
+
+ if (error != nil) {
+ NSLog(@"NSDictionary JSONString error: %@", [error localizedDescription]);
+ return nil;
+ } else {
+ return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
+ }
+}
+
+@end
+
+@implementation NSString (CDVJSONSerializingPrivate)
+
+- (id)cdv_JSONObject
+{
+ NSError* error = nil;
+ id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding]
+ options:NSJSONReadingMutableContainers
+ error:&error];
+
+ if (error != nil) {
+ NSLog(@"NSString JSONObject error: %@", [error localizedDescription]);
+ }
+
+ return object;
+}
+
+- (id)cdv_JSONFragment
+{
+ NSError* error = nil;
+ id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding]
+ options:NSJSONReadingAllowFragments
+ error:&error];
+
+ if (error != nil) {
+ NSLog(@"NSString JSONObject error: %@", [error localizedDescription]);
+ }
+
+ return object;
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVPlugin+Private.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVPlugin+Private.h
new file mode 100644
index 00000000..f88638c2
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/CDVPlugin+Private.h
@@ -0,0 +1,24 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+@interface CDVPlugin (Private)
+
+- (instancetype)initWithWebViewEngine:(id <CDVWebViewEngineProtocol>)theWebViewEngine;
+
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.h
new file mode 100644
index 00000000..510b6ebf
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.h
@@ -0,0 +1,26 @@
+/*
+ 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 CDVGestureHandler : CDVPlugin
+
+@property (nonatomic, strong) UILongPressGestureRecognizer* lpgr;
+
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.m
new file mode 100644
index 00000000..242ac55b
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.m
@@ -0,0 +1,74 @@
+/*
+ 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 "CDVGestureHandler.h"
+
+@implementation CDVGestureHandler
+
+- (void)pluginInitialize
+{
+ [self applyLongPressFix];
+}
+
+- (void)applyLongPressFix
+{
+ // You can't suppress 3D Touch and still have regular longpress,
+ // so if this is false, let's not consider the 3D Touch setting at all.
+ if (![self.commandDelegate.settings objectForKey:@"suppresseslongpressgesture"] ||
+ ![[self.commandDelegate.settings objectForKey:@"suppresseslongpressgesture"] boolValue]) {
+ return;
+ }
+
+ self.lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressGestures:)];
+ self.lpgr.minimumPressDuration = 0.45f;
+ self.lpgr.allowableMovement = 100.0f;
+
+ // 0.45 is ok for 'regular longpress', 0.05-0.08 is required for '3D Touch longpress',
+ // but since this will also kill onclick handlers (not ontouchend) it's optional.
+ if ([self.commandDelegate.settings objectForKey:@"suppresses3dtouchgesture"] &&
+ [[self.commandDelegate.settings objectForKey:@"suppresses3dtouchgesture"] boolValue]) {
+ self.lpgr.minimumPressDuration = 0.05f;
+ }
+
+ NSArray *views = self.webView.subviews;
+ if (views.count == 0) {
+ NSLog(@"No webview subviews found, not applying the longpress fix.");
+ return;
+ }
+ for (int i=0; i<views.count; i++) {
+ UIView *webViewScrollView = views[i];
+ if ([webViewScrollView isKindOfClass:[UIScrollView class]]) {
+ NSArray *webViewScrollViewSubViews = webViewScrollView.subviews;
+ UIView *browser = webViewScrollViewSubViews[0];
+ [browser addGestureRecognizer:self.lpgr];
+ break;
+ }
+ }
+}
+
+- (void)handleLongPressGestures:(UILongPressGestureRecognizer*)sender
+{
+ if ([sender isEqual:self.lpgr]) {
+ if (sender.state == UIGestureRecognizerStateBegan) {
+ NSLog(@"Ignoring a longpress in order to suppress the magnifying glass.");
+ }
+ }
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.h
new file mode 100644
index 00000000..f9b0bffa
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.h
@@ -0,0 +1,27 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVPlugin.h"
+
+@interface CDVHandleOpenURL : CDVPlugin
+
+@property (nonatomic, strong) NSURL* url;
+@property (nonatomic, assign) BOOL pageLoaded;
+
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.m
new file mode 100644
index 00000000..72199b9c
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.m
@@ -0,0 +1,86 @@
+/*
+ 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 "CDVHandleOpenURL.h"
+#import "CDV.h"
+
+@implementation CDVHandleOpenURL
+
+- (void)pluginInitialize
+{
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationLaunchedWithUrl:) name:CDVPluginHandleOpenURLNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationPageDidLoad:) name:CDVPageDidLoadNotification object:nil];
+}
+
+- (void)applicationLaunchedWithUrl:(NSNotification*)notification
+{
+ NSURL* url = [notification object];
+
+ self.url = url;
+
+ // warm-start handler
+ if (self.pageLoaded) {
+ [self processOpenUrl:self.url pageLoaded:YES];
+ self.url = nil;
+ }
+}
+
+- (void)applicationPageDidLoad:(NSNotification*)notification
+{
+ // cold-start handler
+
+ self.pageLoaded = YES;
+
+ if (self.url) {
+ [self processOpenUrl:self.url pageLoaded:YES];
+ self.url = nil;
+ }
+}
+
+- (void)processOpenUrl:(NSURL*)url pageLoaded:(BOOL)pageLoaded
+{
+ __weak __typeof(self) weakSelf = self;
+
+ dispatch_block_t handleOpenUrl = ^(void) {
+ // calls into javascript global function 'handleOpenURL'
+ NSString* jsString = [NSString stringWithFormat:@"document.addEventListener('deviceready',function(){if (typeof handleOpenURL === 'function') { handleOpenURL(\"%@\");}});", url.absoluteString];
+
+ [weakSelf.webViewEngine evaluateJavaScript:jsString completionHandler:nil];
+ };
+
+ if (!pageLoaded) {
+ NSString* jsString = @"document.readystate";
+ [self.webViewEngine evaluateJavaScript:jsString
+ completionHandler:^(id object, NSError* error) {
+ if ((error == nil) && [object isKindOfClass:[NSString class]]) {
+ NSString* readyState = (NSString*)object;
+ BOOL ready = [readyState isEqualToString:@"loaded"] || [readyState isEqualToString:@"complete"];
+ if (ready) {
+ handleOpenUrl();
+ } else {
+ self.url = url;
+ }
+ }
+ }];
+ } else {
+ handleOpenUrl();
+ }
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.h
new file mode 100644
index 00000000..ee89e1a8
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.h
@@ -0,0 +1,34 @@
+/*
+ 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 "CDVWhitelist.h"
+
+typedef NS_ENUM(NSInteger, CDVIntentAndNavigationFilterValue) {
+ CDVIntentAndNavigationFilterValueIntentAllowed,
+ CDVIntentAndNavigationFilterValueNavigationAllowed,
+ CDVIntentAndNavigationFilterValueNoneAllowed
+};
+
+@interface CDVIntentAndNavigationFilter : CDVPlugin <NSXMLParserDelegate>
+
++ (CDVIntentAndNavigationFilterValue) filterUrl:(NSURL*)url intentsWhitelist:(CDVWhitelist*)intentsWhitelist navigationsWhitelist:(CDVWhitelist*)navigationsWhitelist;
++ (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType filterValue:(CDVIntentAndNavigationFilterValue)filterValue;
++ (BOOL)shouldOpenURLRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType;
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.m
new file mode 100644
index 00000000..bc8f7200
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.m
@@ -0,0 +1,142 @@
+/*
+ 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 "CDVIntentAndNavigationFilter.h"
+#import <Cordova/CDV.h>
+
+@interface CDVIntentAndNavigationFilter ()
+
+@property (nonatomic, readwrite) NSMutableArray* allowIntents;
+@property (nonatomic, readwrite) NSMutableArray* allowNavigations;
+@property (nonatomic, readwrite) CDVWhitelist* allowIntentsWhitelist;
+@property (nonatomic, readwrite) CDVWhitelist* allowNavigationsWhitelist;
+
+@end
+
+@implementation CDVIntentAndNavigationFilter
+
+#pragma mark NSXMLParserDelegate
+
+- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributeDict
+{
+ if ([elementName isEqualToString:@"allow-navigation"]) {
+ [self.allowNavigations addObject:attributeDict[@"href"]];
+ }
+ if ([elementName isEqualToString:@"allow-intent"]) {
+ [self.allowIntents addObject:attributeDict[@"href"]];
+ }
+}
+
+- (void)parserDidStartDocument:(NSXMLParser*)parser
+{
+ // file: url <allow-navigations> are added by default
+ self.allowNavigations = [[NSMutableArray alloc] initWithArray:@[ @"file://" ]];
+ // no intents are added by default
+ self.allowIntents = [[NSMutableArray alloc] init];
+}
+
+- (void)parserDidEndDocument:(NSXMLParser*)parser
+{
+ self.allowIntentsWhitelist = [[CDVWhitelist alloc] initWithArray:self.allowIntents];
+ self.allowNavigationsWhitelist = [[CDVWhitelist alloc] initWithArray:self.allowNavigations];
+}
+
+- (void)parser:(NSXMLParser*)parser parseErrorOccurred:(NSError*)parseError
+{
+ NSAssert(NO, @"config.xml parse error line %ld col %ld", (long)[parser lineNumber], (long)[parser columnNumber]);
+}
+
+#pragma mark CDVPlugin
+
+- (void)pluginInitialize
+{
+ if ([self.viewController isKindOfClass:[CDVViewController class]]) {
+ [(CDVViewController*)self.viewController parseSettingsWithParser:self];
+ }
+}
+
++ (CDVIntentAndNavigationFilterValue) filterUrl:(NSURL*)url intentsWhitelist:(CDVWhitelist*)intentsWhitelist navigationsWhitelist:(CDVWhitelist*)navigationsWhitelist
+{
+ // a URL can only allow-intent OR allow-navigation, if both are specified,
+ // only allow-navigation is allowed
+
+ BOOL allowNavigationsPass = [navigationsWhitelist URLIsAllowed:url logFailure:NO];
+ BOOL allowIntentPass = [intentsWhitelist URLIsAllowed:url logFailure:NO];
+
+ if (allowNavigationsPass && allowIntentPass) {
+ return CDVIntentAndNavigationFilterValueNavigationAllowed;
+ } else if (allowNavigationsPass) {
+ return CDVIntentAndNavigationFilterValueNavigationAllowed;
+ } else if (allowIntentPass) {
+ return CDVIntentAndNavigationFilterValueIntentAllowed;
+ }
+
+ return CDVIntentAndNavigationFilterValueNoneAllowed;
+}
+
+- (CDVIntentAndNavigationFilterValue) filterUrl:(NSURL*)url
+{
+ return [[self class] filterUrl:url intentsWhitelist:self.allowIntentsWhitelist navigationsWhitelist:self.allowNavigationsWhitelist];
+}
+
++ (BOOL)shouldOpenURLRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
+{
+ return (UIWebViewNavigationTypeLinkClicked == navigationType ||
+ (UIWebViewNavigationTypeOther == navigationType &&
+ [[request.mainDocumentURL absoluteString] isEqualToString:[request.URL absoluteString]]
+ )
+ );
+}
+
++ (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType filterValue:(CDVIntentAndNavigationFilterValue)filterValue
+{
+ NSString* allowIntents_whitelistRejectionFormatString = @"ERROR External navigation rejected - <allow-intent> not set for url='%@'";
+ NSString* allowNavigations_whitelistRejectionFormatString = @"ERROR Internal navigation rejected - <allow-navigation> not set for url='%@'";
+
+ NSURL* url = [request URL];
+
+ switch (filterValue) {
+ case CDVIntentAndNavigationFilterValueNavigationAllowed:
+ return YES;
+ case CDVIntentAndNavigationFilterValueIntentAllowed:
+ // only allow-intent if it's a UIWebViewNavigationTypeLinkClicked (anchor tag) OR
+ // it's a UIWebViewNavigationTypeOther, and it's an internal link
+ if ([[self class] shouldOpenURLRequest:request navigationType:navigationType]){
+ [[UIApplication sharedApplication] openURL:url];
+ }
+
+ // consume the request (i.e. no error) if it wasn't handled above
+ return NO;
+ case CDVIntentAndNavigationFilterValueNoneAllowed:
+ // allow-navigation attempt failed for sure
+ NSLog(@"%@", [NSString stringWithFormat:allowNavigations_whitelistRejectionFormatString, [url absoluteString]]);
+ // anchor tag link means it was an allow-intent attempt that failed as well
+ if (UIWebViewNavigationTypeLinkClicked == navigationType) {
+ NSLog(@"%@", [NSString stringWithFormat:allowIntents_whitelistRejectionFormatString, [url absoluteString]]);
+ }
+ return NO;
+ }
+}
+
+- (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
+{
+ return [[self class] shouldOverrideLoadWithRequest:request navigationType:navigationType filterValue:[self filterUrl:request.URL]];
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLocalStorage/CDVLocalStorage.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLocalStorage/CDVLocalStorage.h
new file mode 100644
index 00000000..dec6ab3b
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLocalStorage/CDVLocalStorage.h
@@ -0,0 +1,50 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVPlugin.h"
+
+#define kCDVLocalStorageErrorDomain @"kCDVLocalStorageErrorDomain"
+#define kCDVLocalStorageFileOperationError 1
+
+@interface CDVLocalStorage : CDVPlugin
+
+@property (nonatomic, readonly, strong) NSMutableArray* backupInfo;
+
+- (BOOL)shouldBackup;
+- (BOOL)shouldRestore;
+- (void)backup:(CDVInvokedUrlCommand*)command;
+- (void)restore:(CDVInvokedUrlCommand*)command;
+
++ (void)__fixupDatabaseLocationsWithBackupType:(NSString*)backupType;
+// Visible for testing.
++ (BOOL)__verifyAndFixDatabaseLocationsWithAppPlistDict:(NSMutableDictionary*)appPlistDict
+ bundlePath:(NSString*)bundlePath
+ fileManager:(NSFileManager*)fileManager;
+@end
+
+@interface CDVBackupInfo : NSObject
+
+@property (nonatomic, copy) NSString* original;
+@property (nonatomic, copy) NSString* backup;
+@property (nonatomic, copy) NSString* label;
+
+- (BOOL)shouldBackup;
+- (BOOL)shouldRestore;
+
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLocalStorage/CDVLocalStorage.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLocalStorage/CDVLocalStorage.m
new file mode 100644
index 00000000..252dfaf1
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLocalStorage/CDVLocalStorage.m
@@ -0,0 +1,487 @@
+/*
+ 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 "CDVLocalStorage.h"
+#import "CDV.h"
+
+@interface CDVLocalStorage ()
+
+@property (nonatomic, readwrite, strong) NSMutableArray* backupInfo; // array of CDVBackupInfo objects
+@property (nonatomic, readwrite, weak) id <UIWebViewDelegate> webviewDelegate;
+
+@end
+
+@implementation CDVLocalStorage
+
+@synthesize backupInfo, webviewDelegate;
+
+- (void)pluginInitialize
+{
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResignActive)
+ name:UIApplicationWillResignActiveNotification object:nil];
+ BOOL cloudBackup = [@"cloud" isEqualToString : self.commandDelegate.settings[[@"BackupWebStorage" lowercaseString]]];
+
+ self.backupInfo = [[self class] createBackupInfoWithCloudBackup:cloudBackup];
+}
+
+#pragma mark -
+#pragma mark Plugin interface methods
+
++ (NSMutableArray*)createBackupInfoWithTargetDir:(NSString*)targetDir backupDir:(NSString*)backupDir targetDirNests:(BOOL)targetDirNests backupDirNests:(BOOL)backupDirNests rename:(BOOL)rename
+{
+ /*
+ This "helper" does so much work and has so many options it would probably be clearer to refactor the whole thing.
+ Basically, there are three database locations:
+
+ 1. "Normal" dir -- LIB/<nested dires WebKit/LocalStorage etc>/<normal filenames>
+ 2. "Caches" dir -- LIB/Caches/<normal filenames>
+ 3. "Backup" dir -- DOC/Backups/<renamed filenames>
+
+ And between these three, there are various migration paths, most of which only consider 2 of the 3, which is why this helper is based on 2 locations and has a notion of "direction".
+ */
+ NSMutableArray* backupInfo = [NSMutableArray arrayWithCapacity:3];
+
+ NSString* original;
+ NSString* backup;
+ CDVBackupInfo* backupItem;
+
+ // ////////// LOCALSTORAGE
+
+ original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/file__0.localstorage":@"file__0.localstorage"];
+ backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")];
+ backup = [backup stringByAppendingPathComponent:(rename ? @"localstorage.appdata.db" : @"file__0.localstorage")];
+
+ backupItem = [[CDVBackupInfo alloc] init];
+ backupItem.backup = backup;
+ backupItem.original = original;
+ backupItem.label = @"localStorage database";
+
+ [backupInfo addObject:backupItem];
+
+ // ////////// WEBSQL MAIN DB
+
+ original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/Databases.db":@"Databases.db"];
+ backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")];
+ backup = [backup stringByAppendingPathComponent:(rename ? @"websqlmain.appdata.db" : @"Databases.db")];
+
+ backupItem = [[CDVBackupInfo alloc] init];
+ backupItem.backup = backup;
+ backupItem.original = original;
+ backupItem.label = @"websql main database";
+
+ [backupInfo addObject:backupItem];
+
+ // ////////// WEBSQL DATABASES
+
+ original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/file__0":@"file__0"];
+ backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")];
+ backup = [backup stringByAppendingPathComponent:(rename ? @"websqldbs.appdata.db" : @"file__0")];
+
+ backupItem = [[CDVBackupInfo alloc] init];
+ backupItem.backup = backup;
+ backupItem.original = original;
+ backupItem.label = @"websql databases";
+
+ [backupInfo addObject:backupItem];
+
+ return backupInfo;
+}
+
++ (NSMutableArray*)createBackupInfoWithCloudBackup:(BOOL)cloudBackup
+{
+ // create backup info from backup folder to caches folder
+ NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+ NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+ NSString* cacheFolder = [appLibraryFolder stringByAppendingPathComponent:@"Caches"];
+ NSString* backupsFolder = [appDocumentsFolder stringByAppendingPathComponent:@"Backups"];
+
+ // create the backups folder, if needed
+ [[NSFileManager defaultManager] createDirectoryAtPath:backupsFolder withIntermediateDirectories:YES attributes:nil error:nil];
+
+ [self addSkipBackupAttributeToItemAtURL:[NSURL fileURLWithPath:backupsFolder] skip:!cloudBackup];
+
+ return [self createBackupInfoWithTargetDir:cacheFolder backupDir:backupsFolder targetDirNests:NO backupDirNests:NO rename:YES];
+}
+
++ (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL*)URL skip:(BOOL)skip
+{
+ NSError* error = nil;
+ BOOL success = [URL setResourceValue:[NSNumber numberWithBool:skip] forKey:NSURLIsExcludedFromBackupKey error:&error];
+
+ if (!success) {
+ NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
+ }
+ return success;
+}
+
++ (BOOL)copyFrom:(NSString*)src to:(NSString*)dest error:(NSError* __autoreleasing*)error
+{
+ NSFileManager* fileManager = [NSFileManager defaultManager];
+
+ if (![fileManager fileExistsAtPath:src]) {
+ NSString* errorString = [NSString stringWithFormat:@"%@ file does not exist.", src];
+ if (error != NULL) {
+ (*error) = [NSError errorWithDomain:kCDVLocalStorageErrorDomain
+ code:kCDVLocalStorageFileOperationError
+ userInfo:[NSDictionary dictionaryWithObject:errorString
+ forKey:NSLocalizedDescriptionKey]];
+ }
+ return NO;
+ }
+
+ // generate unique filepath in temp directory
+ CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
+ CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
+ NSString* tempBackup = [[NSTemporaryDirectory() stringByAppendingPathComponent:(__bridge NSString*)uuidString] stringByAppendingPathExtension:@"bak"];
+ CFRelease(uuidString);
+ CFRelease(uuidRef);
+
+ BOOL destExists = [fileManager fileExistsAtPath:dest];
+
+ // backup the dest
+ if (destExists && ![fileManager copyItemAtPath:dest toPath:tempBackup error:error]) {
+ return NO;
+ }
+
+ // remove the dest
+ if (destExists && ![fileManager removeItemAtPath:dest error:error]) {
+ return NO;
+ }
+
+ // create path to dest
+ if (!destExists && ![fileManager createDirectoryAtPath:[dest stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:error]) {
+ return NO;
+ }
+
+ // copy src to dest
+ if ([fileManager copyItemAtPath:src toPath:dest error:error]) {
+ // success - cleanup - delete the backup to the dest
+ if ([fileManager fileExistsAtPath:tempBackup]) {
+ [fileManager removeItemAtPath:tempBackup error:error];
+ }
+ return YES;
+ } else {
+ // failure - we restore the temp backup file to dest
+ [fileManager copyItemAtPath:tempBackup toPath:dest error:error];
+ // cleanup - delete the backup to the dest
+ if ([fileManager fileExistsAtPath:tempBackup]) {
+ [fileManager removeItemAtPath:tempBackup error:error];
+ }
+ return NO;
+ }
+}
+
+- (BOOL)shouldBackup
+{
+ for (CDVBackupInfo* info in self.backupInfo) {
+ if ([info shouldBackup]) {
+ return YES;
+ }
+ }
+
+ return NO;
+}
+
+- (BOOL)shouldRestore
+{
+ for (CDVBackupInfo* info in self.backupInfo) {
+ if ([info shouldRestore]) {
+ return YES;
+ }
+ }
+
+ return NO;
+}
+
+/* copy from webkitDbLocation to persistentDbLocation */
+- (void)backup:(CDVInvokedUrlCommand*)command
+{
+ NSString* callbackId = command.callbackId;
+
+ NSError* __autoreleasing error = nil;
+ CDVPluginResult* result = nil;
+ NSString* message = nil;
+
+ for (CDVBackupInfo* info in self.backupInfo) {
+ if ([info shouldBackup]) {
+ [[self class] copyFrom:info.original to:info.backup error:&error];
+
+ if (callbackId) {
+ if (error == nil) {
+ message = [NSString stringWithFormat:@"Backed up: %@", info.label];
+ NSLog(@"%@", message);
+
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:message];
+ [self.commandDelegate sendPluginResult:result callbackId:callbackId];
+ } else {
+ message = [NSString stringWithFormat:@"Error in CDVLocalStorage (%@) backup: %@", info.label, [error localizedDescription]];
+ NSLog(@"%@", message);
+
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:message];
+ [self.commandDelegate sendPluginResult:result callbackId:callbackId];
+ }
+ }
+ }
+ }
+}
+
+/* copy from persistentDbLocation to webkitDbLocation */
+- (void)restore:(CDVInvokedUrlCommand*)command
+{
+ NSError* __autoreleasing error = nil;
+ CDVPluginResult* result = nil;
+ NSString* message = nil;
+
+ for (CDVBackupInfo* info in self.backupInfo) {
+ if ([info shouldRestore]) {
+ [[self class] copyFrom:info.backup to:info.original error:&error];
+
+ if (error == nil) {
+ message = [NSString stringWithFormat:@"Restored: %@", info.label];
+ NSLog(@"%@", message);
+
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:message];
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } else {
+ message = [NSString stringWithFormat:@"Error in CDVLocalStorage (%@) restore: %@", info.label, [error localizedDescription]];
+ NSLog(@"%@", message);
+
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:message];
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ }
+ }
+ }
+}
+
++ (void)__fixupDatabaseLocationsWithBackupType:(NSString*)backupType
+{
+ [self __verifyAndFixDatabaseLocations];
+ [self __restoreLegacyDatabaseLocationsWithBackupType:backupType];
+}
+
++ (void)__verifyAndFixDatabaseLocations
+{
+ NSBundle* mainBundle = [NSBundle mainBundle];
+ NSString* bundlePath = [[mainBundle bundlePath] stringByDeletingLastPathComponent];
+ NSString* bundleIdentifier = [[mainBundle infoDictionary] objectForKey:@"CFBundleIdentifier"];
+ NSString* appPlistPath = [bundlePath stringByAppendingPathComponent:[NSString stringWithFormat:@"Library/Preferences/%@.plist", bundleIdentifier]];
+
+ NSMutableDictionary* appPlistDict = [NSMutableDictionary dictionaryWithContentsOfFile:appPlistPath];
+ BOOL modified = [[self class] __verifyAndFixDatabaseLocationsWithAppPlistDict:appPlistDict
+ bundlePath:bundlePath
+ fileManager:[NSFileManager defaultManager]];
+
+ if (modified) {
+ BOOL ok = [appPlistDict writeToFile:appPlistPath atomically:YES];
+ [[NSUserDefaults standardUserDefaults] synchronize];
+ NSLog(@"Fix applied for database locations?: %@", ok ? @"YES" : @"NO");
+ }
+}
+
++ (BOOL)__verifyAndFixDatabaseLocationsWithAppPlistDict:(NSMutableDictionary*)appPlistDict
+ bundlePath:(NSString*)bundlePath
+ fileManager:(NSFileManager*)fileManager
+{
+ NSString* libraryCaches = @"Library/Caches";
+ NSString* libraryWebKit = @"Library/WebKit";
+
+ NSArray* keysToCheck = [NSArray arrayWithObjects:
+ @"WebKitLocalStorageDatabasePathPreferenceKey",
+ @"WebDatabaseDirectory",
+ nil];
+
+ BOOL dirty = NO;
+
+ for (NSString* key in keysToCheck) {
+ NSString* value = [appPlistDict objectForKey:key];
+ // verify key exists, and path is in app bundle, if not - fix
+ if ((value != nil) && ![value hasPrefix:bundlePath]) {
+ // the pathSuffix to use may be wrong - OTA upgrades from < 5.1 to 5.1 do keep the old path Library/WebKit,
+ // while Xcode synced ones do change the storage location to Library/Caches
+ NSString* newBundlePath = [bundlePath stringByAppendingPathComponent:libraryCaches];
+ if (![fileManager fileExistsAtPath:newBundlePath]) {
+ newBundlePath = [bundlePath stringByAppendingPathComponent:libraryWebKit];
+ }
+ [appPlistDict setValue:newBundlePath forKey:key];
+ dirty = YES;
+ }
+ }
+
+ return dirty;
+}
+
++ (void)__restoreLegacyDatabaseLocationsWithBackupType:(NSString*)backupType
+{
+ // on iOS 6, if you toggle between cloud/local backup, you must move database locations. Default upgrade from iOS5.1 to iOS6 is like a toggle from local to cloud.
+ NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+ NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+
+ 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]];
+ } else {
+ // For ios6 local backups we also want to restore from Backups dir -- but we don't need to do that here, since the plugin will do that itself.
+ [backupInfo addObjectsFromArray:[self createBackupInfoWithTargetDir:[appLibraryFolder stringByAppendingPathComponent:@"Caches"] backupDir:appLibraryFolder targetDirNests:NO backupDirNests:YES rename:NO]];
+ }
+
+ NSFileManager* manager = [NSFileManager defaultManager];
+
+ for (CDVBackupInfo* info in backupInfo) {
+ if ([manager fileExistsAtPath:info.backup]) {
+ if ([info shouldRestore]) {
+ NSLog(@"Restoring old webstorage backup. From: '%@' To: '%@'.", info.backup, info.original);
+ [self copyFrom:info.backup to:info.original error:nil];
+ }
+ NSLog(@"Removing old webstorage backup: '%@'.", info.backup);
+ [manager removeItemAtPath:info.backup error:nil];
+ }
+ }
+
+ [[NSUserDefaults standardUserDefaults] setBool:[backupType isEqualToString:@"cloud"] forKey:@"WebKitStoreWebDataForBackup"];
+}
+
+#pragma mark -
+#pragma mark Notification handlers
+
+- (void)onResignActive
+{
+ UIDevice* device = [UIDevice currentDevice];
+ NSNumber* exitsOnSuspend = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIApplicationExitsOnSuspend"];
+
+ BOOL isMultitaskingSupported = [device respondsToSelector:@selector(isMultitaskingSupported)] && [device isMultitaskingSupported];
+
+ if (exitsOnSuspend == nil) { // if it's missing, it should be NO (i.e. multi-tasking on by default)
+ exitsOnSuspend = [NSNumber numberWithBool:NO];
+ }
+
+ if (exitsOnSuspend) {
+ [self backup:nil];
+ } else if (isMultitaskingSupported) {
+ __block UIBackgroundTaskIdentifier backgroundTaskID = UIBackgroundTaskInvalid;
+
+ backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
+ [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID];
+ backgroundTaskID = UIBackgroundTaskInvalid;
+ NSLog(@"Background task to backup WebSQL/LocalStorage expired.");
+ }];
+ CDVLocalStorage __weak* weakSelf = self;
+ [self.commandDelegate runInBackground:^{
+ [weakSelf backup:nil];
+
+ [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID];
+ backgroundTaskID = UIBackgroundTaskInvalid;
+ }];
+ }
+}
+
+- (void)onAppTerminate
+{
+ [self onResignActive];
+}
+
+- (void)onReset
+{
+ [self restore:nil];
+}
+
+@end
+
+#pragma mark -
+#pragma mark CDVBackupInfo implementation
+
+@implementation CDVBackupInfo
+
+@synthesize original, backup, label;
+
+- (BOOL)file:(NSString*)aPath isNewerThanFile:(NSString*)bPath
+{
+ NSFileManager* fileManager = [NSFileManager defaultManager];
+ NSError* __autoreleasing error = nil;
+
+ NSDictionary* aPathAttribs = [fileManager attributesOfItemAtPath:aPath error:&error];
+ NSDictionary* bPathAttribs = [fileManager attributesOfItemAtPath:bPath error:&error];
+
+ NSDate* aPathModDate = [aPathAttribs objectForKey:NSFileModificationDate];
+ NSDate* bPathModDate = [bPathAttribs objectForKey:NSFileModificationDate];
+
+ if ((nil == aPathModDate) && (nil == bPathModDate)) {
+ return NO;
+ }
+
+ return [aPathModDate compare:bPathModDate] == NSOrderedDescending || bPathModDate == nil;
+}
+
+- (BOOL)item:(NSString*)aPath isNewerThanItem:(NSString*)bPath
+{
+ NSFileManager* fileManager = [NSFileManager defaultManager];
+
+ BOOL aPathIsDir = NO, bPathIsDir = NO;
+ BOOL aPathExists = [fileManager fileExistsAtPath:aPath isDirectory:&aPathIsDir];
+
+ [fileManager fileExistsAtPath:bPath isDirectory:&bPathIsDir];
+
+ if (!aPathExists) {
+ return NO;
+ }
+
+ if (!(aPathIsDir && bPathIsDir)) { // just a file
+ return [self file:aPath isNewerThanFile:bPath];
+ }
+
+ // essentially we want rsync here, but have to settle for our poor man's implementation
+ // we get the files in aPath, and see if it is newer than the file in bPath
+ // (it is newer if it doesn't exist in bPath) if we encounter the FIRST file that is newer,
+ // we return YES
+ NSDirectoryEnumerator* directoryEnumerator = [fileManager enumeratorAtPath:aPath];
+ NSString* path;
+
+ while ((path = [directoryEnumerator nextObject])) {
+ NSString* aPathFile = [aPath stringByAppendingPathComponent:path];
+ NSString* bPathFile = [bPath stringByAppendingPathComponent:path];
+
+ BOOL isNewer = [self file:aPathFile isNewerThanFile:bPathFile];
+ if (isNewer) {
+ return YES;
+ }
+ }
+
+ return NO;
+}
+
+- (BOOL)shouldBackup
+{
+ return [self item:self.original isNewerThanItem:self.backup];
+}
+
+- (BOOL)shouldRestore
+{
+ return [self item:self.backup isNewerThanItem:self.original];
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.h
new file mode 100644
index 00000000..d77f1913
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.h
@@ -0,0 +1,41 @@
+/*
+ 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 <UIKit/UIKit.h>
+#import "CDVAvailability.h"
+
+/**
+ * Distinguishes top-level navigations from sub-frame navigations.
+ * shouldStartLoadWithRequest is called for every request, but didStartLoad
+ * and didFinishLoad is called only for top-level navigations.
+ * Relevant bug: CB-2389
+ */
+@interface CDVUIWebViewDelegate : NSObject <UIWebViewDelegate>{
+ __weak NSObject <UIWebViewDelegate>* _delegate;
+ NSInteger _loadCount;
+ NSInteger _state;
+ NSInteger _curLoadToken;
+ NSInteger _loadStartPollCount;
+}
+
+- (id)initWithDelegate:(NSObject <UIWebViewDelegate>*)delegate;
+
+- (BOOL)request:(NSURLRequest*)newRequest isEqualToRequestAfterStrippingFragments:(NSURLRequest*)originalRequest;
+
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m
new file mode 100644
index 00000000..0af97dfb
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m
@@ -0,0 +1,400 @@
+/*
+ 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.
+ */
+
+//
+// Testing shows:
+//
+// In all cases, webView.request.URL is the previous page's URL (or empty) during the didStartLoad callback.
+// When loading a page with a redirect:
+// 1. shouldStartLoading (requestURL is target page)
+// 2. didStartLoading
+// 3. shouldStartLoading (requestURL is redirect target)
+// 4. didFinishLoad (request.URL is redirect target)
+//
+// Note the lack of a second didStartLoading **
+//
+// When loading a page with iframes:
+// 1. shouldStartLoading (requestURL is main page)
+// 2. didStartLoading
+// 3. shouldStartLoading (requestURL is one of the iframes)
+// 4. didStartLoading
+// 5. didFinishLoad
+// 6. didFinishLoad
+//
+// Note there is no way to distinguish which didFinishLoad maps to which didStartLoad **
+//
+// Loading a page by calling window.history.go(-1):
+// 1. didStartLoading
+// 2. didFinishLoad
+//
+// Note the lack of a shouldStartLoading call **
+// Actually - this is fixed on iOS6. iOS6 has a shouldStart. **
+//
+// Loading a page by calling location.reload()
+// 1. shouldStartLoading
+// 2. didStartLoading
+// 3. didFinishLoad
+//
+// Loading a page with an iframe that fails to load:
+// 1. shouldStart (main page)
+// 2. didStart
+// 3. shouldStart (iframe)
+// 4. didStart
+// 5. didFailWithError
+// 6. didFinish
+//
+// Loading a page with an iframe that fails to load due to an invalid URL:
+// 1. shouldStart (main page)
+// 2. didStart
+// 3. shouldStart (iframe)
+// 5. didFailWithError
+// 6. didFinish
+//
+// This case breaks our logic since there is a missing didStart. To prevent this,
+// we check URLs in shouldStart and return NO if they are invalid.
+//
+// Loading a page with an invalid URL
+// 1. shouldStart (main page)
+// 2. didFailWithError
+//
+// TODO: Record order when page is re-navigated before the first navigation finishes.
+//
+
+#import "CDVUIWebViewDelegate.h"
+
+// #define VerboseLog NSLog
+#define VerboseLog(...) do { \
+} while (0)
+
+typedef enum {
+ 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 CDVUIWebViewDelegate
+
+- (id)initWithDelegate:(NSObject <UIWebViewDelegate>*)delegate
+{
+ self = [super init];
+ if (self != nil) {
+ _delegate = delegate;
+ _loadCount = -1;
+ _state = STATE_IDLE;
+ }
+ return self;
+}
+
+- (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"];
+
+ return [readyState isEqualToString:@"loaded"] || [readyState isEqualToString:@"complete"];
+}
+
+- (BOOL)isJsLoadTokenSet:(UIWebView*)webView
+{
+ NSString* loadToken = [webView stringByEvaluatingJavaScriptFromString:@"window.__cordovaLoadToken"];
+
+ return [[NSString stringWithFormat:@"%ld", (long)_curLoadToken] isEqualToString:loadToken];
+}
+
+- (void)setLoadToken:(UIWebView*)webView
+{
+ _curLoadToken += 1;
+ [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.__cordovaLoadToken=%ld", (long)_curLoadToken]];
+}
+
+- (NSString*)evalForCurrentURL:(UIWebView*)webView
+{
+ return [webView stringByEvaluatingJavaScriptFromString:@"location.href"];
+}
+
+- (void)pollForPageLoadStart:(UIWebView*)webView
+{
+ if (_state != STATE_IOS5_POLLING_FOR_LOAD_START) {
+ return;
+ }
+ if (![self isJsLoadTokenSet:webView]) {
+ VerboseLog(@"Polled for page load start. result = YES!");
+ _state = STATE_IOS5_POLLING_FOR_LOAD_FINISH;
+ [self setLoadToken:webView];
+ if ([_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
+ [_delegate webViewDidStartLoad:webView];
+ }
+ [self pollForPageLoadFinish:webView];
+ } else {
+ VerboseLog(@"Polled for page load start. result = NO");
+ // Poll only for 1 second, and then fall back on checking only when delegate methods are called.
+ ++_loadStartPollCount;
+ if (_loadStartPollCount < (1000 * .05)) {
+ [self performSelector:@selector(pollForPageLoadStart:) withObject:webView afterDelay:.05];
+ }
+ }
+}
+
+- (void)pollForPageLoadFinish:(UIWebView*)webView
+{
+ if (_state != STATE_IOS5_POLLING_FOR_LOAD_FINISH) {
+ return;
+ }
+ if ([self isPageLoaded:webView]) {
+ VerboseLog(@"Polled for page load finish. result = YES!");
+ _state = STATE_IDLE;
+ if ([_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
+ [_delegate webViewDidFinishLoad:webView];
+ }
+ } else {
+ VerboseLog(@"Polled for page load finish. result = NO");
+ [self performSelector:@selector(pollForPageLoadFinish:) withObject:webView afterDelay:.05];
+ }
+}
+
+- (BOOL)shouldLoadRequest:(NSURLRequest*)request
+{
+ NSString* scheme = [[request URL] scheme];
+ NSArray* allowedSchemes = [NSArray arrayWithObjects:@"mailto",@"tel",@"blob",@"sms",@"data", nil];
+ if([allowedSchemes containsObject:scheme]) {
+ return YES;
+ }
+ else {
+ return [NSURLConnection canHandleRequest:request];
+ }
+}
+
+- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
+{
+ BOOL shouldLoad = YES;
+
+ if ([_delegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) {
+ shouldLoad = [_delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
+ }
+
+ VerboseLog(@"webView shouldLoad=%d (before) state=%d loadCount=%d URL=%@", shouldLoad, _state, _loadCount, request.URL);
+
+ if (shouldLoad) {
+ // 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=%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:
+ {
+ NSString* description = [NSString stringWithFormat:@"CDVWebViewDelegate: Navigation started when state=%ld", (long)_state];
+ NSLog(@"%@", description);
+ _loadCount = 0;
+ _state = STATE_WAITING_FOR_LOAD_START;
+ if ([_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
+ NSDictionary* errorDictionary = @{NSLocalizedDescriptionKey : description};
+ NSError* error = [[NSError alloc] initWithDomain:@"CDVUIWebViewDelegate" 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 && [self shouldLoadRequest:request];
+ }
+ VerboseLog(@"webView shouldLoad=%d (after) isTopLevelNavigation=%d state=%d loadCount=%d", shouldLoad, isTopLevelNavigation, _state, _loadCount);
+ }
+ return shouldLoad;
+}
+
+- (void)webViewDidStartLoad:(UIWebView*)webView
+{
+ VerboseLog(@"webView didStartLoad (before). state=%d loadCount=%d", _state, _loadCount);
+ BOOL fireCallback = NO;
+ switch (_state) {
+ case STATE_IDLE:
+ 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=%ld", (long)_loadCount);
+ }
+ fireCallback = YES;
+ _state = STATE_WAITING_FOR_LOAD_FINISH;
+ _loadCount = 1;
+ break;
+
+ case STATE_WAITING_FOR_LOAD_FINISH:
+ _loadCount += 1;
+ break;
+
+ case STATE_IOS5_POLLING_FOR_LOAD_START:
+ [self pollForPageLoadStart:webView];
+ break;
+
+ case STATE_IOS5_POLLING_FOR_LOAD_FINISH:
+ [self pollForPageLoadFinish:webView];
+ break;
+
+ default:
+ 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:)]) {
+ [_delegate webViewDidStartLoad:webView];
+ }
+}
+
+- (void)webViewDidFinishLoad:(UIWebView*)webView
+{
+ VerboseLog(@"webView didFinishLoad (before). state=%d loadCount=%d", _state, _loadCount);
+ BOOL fireCallback = NO;
+ switch (_state) {
+ case STATE_IDLE:
+ break;
+
+ case STATE_WAITING_FOR_LOAD_START:
+ NSLog(@"CDVWebViewDelegate: Unexpected didFinish while waiting for load start.");
+ break;
+
+ case STATE_WAITING_FOR_LOAD_FINISH:
+ if (_loadCount == 1) {
+ fireCallback = YES;
+ _state = STATE_IDLE;
+ }
+ _loadCount -= 1;
+ break;
+
+ case STATE_IOS5_POLLING_FOR_LOAD_START:
+ [self pollForPageLoadStart:webView];
+ break;
+
+ case STATE_IOS5_POLLING_FOR_LOAD_FINISH:
+ [self pollForPageLoadFinish:webView];
+ break;
+ }
+ VerboseLog(@"webView didFinishLoad (after). state=%d loadCount=%d fireCallback=%d", _state, _loadCount, fireCallback);
+ if (fireCallback && [_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
+ [_delegate webViewDidFinishLoad:webView];
+ }
+}
+
+- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error
+{
+ VerboseLog(@"webView didFailLoad (before). state=%d loadCount=%d", _state, _loadCount);
+ BOOL fireCallback = NO;
+
+ switch (_state) {
+ case STATE_IDLE:
+ break;
+
+ case STATE_WAITING_FOR_LOAD_START:
+ if ([error code] == NSURLErrorCancelled) {
+ _state = STATE_CANCELLED;
+ } else {
+ _state = STATE_IDLE;
+ }
+ fireCallback = YES;
+ break;
+
+ case STATE_WAITING_FOR_LOAD_FINISH:
+ if ([error code] != NSURLErrorCancelled) {
+ if (_loadCount == 1) {
+ _state = STATE_IDLE;
+ fireCallback = YES;
+ }
+ _loadCount = -1;
+ } else {
+ fireCallback = YES;
+ _state = STATE_CANCELLED;
+ _loadCount -= 1;
+ }
+ break;
+
+ case STATE_IOS5_POLLING_FOR_LOAD_START:
+ [self pollForPageLoadStart:webView];
+ break;
+
+ case STATE_IOS5_POLLING_FOR_LOAD_FINISH:
+ [self pollForPageLoadFinish:webView];
+ break;
+ }
+ VerboseLog(@"webView didFailLoad (after). state=%d loadCount=%d, fireCallback=%d", _state, _loadCount, fireCallback);
+ if (fireCallback && [_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
+ [_delegate webView:webView didFailLoadWithError:error];
+ }
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.h
new file mode 100644
index 00000000..6a9ee77e
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.h
@@ -0,0 +1,27 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVPlugin.h"
+#import "CDVWebViewEngineProtocol.h"
+
+@interface CDVUIWebViewEngine : CDVPlugin <CDVWebViewEngineProtocol>
+
+@property (nonatomic, strong, readonly) id <UIWebViewDelegate> uiWebViewDelegate;
+
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.m
new file mode 100644
index 00000000..f571d80a
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.m
@@ -0,0 +1,202 @@
+/*
+ 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 "CDVUIWebViewEngine.h"
+#import "CDVUIWebViewDelegate.h"
+#import "CDVUIWebViewNavigationDelegate.h"
+#import "NSDictionary+CordovaPreferences.h"
+
+#import <objc/message.h>
+
+@interface CDVUIWebViewEngine ()
+
+@property (nonatomic, strong, readwrite) UIView* engineWebView;
+@property (nonatomic, strong, readwrite) id <UIWebViewDelegate> uiWebViewDelegate;
+@property (nonatomic, strong, readwrite) CDVUIWebViewNavigationDelegate* navWebViewDelegate;
+
+@end
+
+@implementation CDVUIWebViewEngine
+
+@synthesize engineWebView = _engineWebView;
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ self = [super init];
+ if (self) {
+ self.engineWebView = [[UIWebView alloc] initWithFrame:frame];
+ NSLog(@"Using UIWebView");
+ }
+
+ return self;
+}
+
+- (void)pluginInitialize
+{
+ // viewController would be available now. we attempt to set all possible delegates to it, by default
+
+ UIWebView* uiWebView = (UIWebView*)_engineWebView;
+
+ if ([self.viewController conformsToProtocol:@protocol(UIWebViewDelegate)]) {
+ self.uiWebViewDelegate = [[CDVUIWebViewDelegate alloc] initWithDelegate:(id <UIWebViewDelegate>)self.viewController];
+ uiWebView.delegate = self.uiWebViewDelegate;
+ } else {
+ self.navWebViewDelegate = [[CDVUIWebViewNavigationDelegate alloc] initWithEnginePlugin:self];
+ self.uiWebViewDelegate = [[CDVUIWebViewDelegate alloc] initWithDelegate:self.navWebViewDelegate];
+ uiWebView.delegate = self.uiWebViewDelegate;
+ }
+
+ [self updateSettings:self.commandDelegate.settings];
+}
+
+- (void)evaluateJavaScript:(NSString*)javaScriptString completionHandler:(void (^)(id, NSError*))completionHandler
+{
+ NSString* ret = [(UIWebView*)_engineWebView stringByEvaluatingJavaScriptFromString:javaScriptString];
+
+ if (completionHandler) {
+ completionHandler(ret, nil);
+ }
+}
+
+- (id)loadRequest:(NSURLRequest*)request
+{
+ [(UIWebView*)_engineWebView loadRequest:request];
+ return nil;
+}
+
+- (id)loadHTMLString:(NSString*)string baseURL:(NSURL*)baseURL
+{
+ [(UIWebView*)_engineWebView loadHTMLString:string baseURL:baseURL];
+ return nil;
+}
+
+- (NSURL*)URL
+{
+ return [[(UIWebView*)_engineWebView request] URL];
+}
+
+- (BOOL) canLoadRequest:(NSURLRequest*)request
+{
+ return (request != nil);
+}
+
+- (void)updateSettings:(NSDictionary*)settings
+{
+ UIWebView* uiWebView = (UIWebView*)_engineWebView;
+
+ uiWebView.scalesPageToFit = [settings cordovaBoolSettingForKey:@"EnableViewportScale" defaultValue:NO];
+ uiWebView.allowsInlineMediaPlayback = [settings cordovaBoolSettingForKey:@"AllowInlineMediaPlayback" defaultValue:NO];
+ uiWebView.mediaPlaybackRequiresUserAction = [settings cordovaBoolSettingForKey:@"MediaPlaybackRequiresUserAction" defaultValue:YES];
+ uiWebView.mediaPlaybackAllowsAirPlay = [settings cordovaBoolSettingForKey:@"MediaPlaybackAllowsAirPlay" defaultValue:YES];
+ uiWebView.keyboardDisplayRequiresUserAction = [settings cordovaBoolSettingForKey:@"KeyboardDisplayRequiresUserAction" defaultValue:YES];
+ uiWebView.suppressesIncrementalRendering = [settings cordovaBoolSettingForKey:@"SuppressesIncrementalRendering" defaultValue:NO];
+ uiWebView.gapBetweenPages = [settings cordovaFloatSettingForKey:@"GapBetweenPages" defaultValue:0.0];
+ uiWebView.pageLength = [settings cordovaFloatSettingForKey:@"PageLength" defaultValue:0.0];
+
+ id prefObj = nil;
+
+ // By default, DisallowOverscroll is false (thus bounce is allowed)
+ BOOL bounceAllowed = !([settings cordovaBoolSettingForKey:@"DisallowOverscroll" defaultValue:NO]);
+
+ // prevent webView from bouncing
+ if (!bounceAllowed) {
+ if ([uiWebView respondsToSelector:@selector(scrollView)]) {
+ ((UIScrollView*)[uiWebView scrollView]).bounces = NO;
+ } else {
+ for (id subview in self.webView.subviews) {
+ if ([[subview class] isSubclassOfClass:[UIScrollView class]]) {
+ ((UIScrollView*)subview).bounces = NO;
+ }
+ }
+ }
+ }
+
+ NSString* decelerationSetting = [settings cordovaSettingForKey:@"UIWebViewDecelerationSpeed"];
+ if (![@"fast" isEqualToString:decelerationSetting]) {
+ [uiWebView.scrollView setDecelerationRate:UIScrollViewDecelerationRateNormal];
+ }
+
+ NSInteger paginationBreakingMode = 0; // default - UIWebPaginationBreakingModePage
+ prefObj = [settings cordovaSettingForKey:@"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;
+ }
+ }
+ uiWebView.paginationBreakingMode = paginationBreakingMode;
+
+ NSInteger paginationMode = 0; // default - UIWebPaginationModeUnpaginated
+ prefObj = [settings cordovaSettingForKey:@"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;
+ }
+ }
+ uiWebView.paginationMode = paginationMode;
+}
+
+- (void)updateWithInfo:(NSDictionary*)info
+{
+ UIWebView* uiWebView = (UIWebView*)_engineWebView;
+
+ id <UIWebViewDelegate> uiWebViewDelegate = [info objectForKey:kCDVWebViewEngineUIWebViewDelegate];
+ NSDictionary* settings = [info objectForKey:kCDVWebViewEngineWebViewPreferences];
+
+ if (uiWebViewDelegate &&
+ [uiWebViewDelegate conformsToProtocol:@protocol(UIWebViewDelegate)]) {
+ self.uiWebViewDelegate = [[CDVUIWebViewDelegate alloc] initWithDelegate:(id <UIWebViewDelegate>)self.viewController];
+ uiWebView.delegate = self.uiWebViewDelegate;
+ }
+
+ if (settings && [settings isKindOfClass:[NSDictionary class]]) {
+ [self updateSettings:settings];
+ }
+}
+
+// This forwards the methods that are in the header that are not implemented here.
+// Both WKWebView and UIWebView implement the below:
+// loadHTMLString:baseURL:
+// loadRequest:
+- (id)forwardingTargetForSelector:(SEL)aSelector
+{
+ return _engineWebView;
+}
+
+- (UIView*)webView
+{
+ return self.engineWebView;
+}
+
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.h b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.h
new file mode 100644
index 00000000..9138deba
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.h
@@ -0,0 +1,29 @@
+/*
+ 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 <UIKit/UIKit.h>
+#import "CDVUIWebViewEngine.h"
+
+@interface CDVUIWebViewNavigationDelegate : NSObject <UIWebViewDelegate>
+
+@property (nonatomic, weak) CDVPlugin* enginePlugin;
+
+- (instancetype)initWithEnginePlugin:(CDVPlugin*)enginePlugin;
+
+@end
diff --git a/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.m b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.m
new file mode 100644
index 00000000..6e316595
--- /dev/null
+++ b/StoneIsland/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.m
@@ -0,0 +1,151 @@
+/*
+ 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 "CDVUIWebViewNavigationDelegate.h"
+#import <Cordova/CDVViewController.h>
+#import <Cordova/CDVCommandDelegateImpl.h>
+#import <Cordova/CDVUserAgentUtil.h>
+#import <objc/message.h>
+
+@implementation CDVUIWebViewNavigationDelegate
+
+- (instancetype)initWithEnginePlugin:(CDVPlugin*)theEnginePlugin
+{
+ self = [super init];
+ if (self) {
+ self.enginePlugin = theEnginePlugin;
+ }
+
+ return self;
+}
+
+/**
+ When web application loads Add stuff to the DOM, mainly the user-defined settings from the Settings.plist file, and
+ the device's data such as device ID, platform version, etc.
+ */
+- (void)webViewDidStartLoad:(UIWebView*)theWebView
+{
+ NSLog(@"Resetting plugins due to page load.");
+ CDVViewController* vc = (CDVViewController*)self.enginePlugin.viewController;
+
+ [vc.commandQueue resetRequestId];
+ [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginResetNotification object:self.enginePlugin.webView]];
+}
+
+/**
+ Called when the webview finishes loading. This stops the activity view.
+ */
+- (void)webViewDidFinishLoad:(UIWebView*)theWebView
+{
+ NSLog(@"Finished load of: %@", theWebView.request.URL);
+ CDVViewController* vc = (CDVViewController*)self.enginePlugin.viewController;
+
+ // It's safe to release the lock even if this is just a sub-frame that's finished loading.
+ [CDVUserAgentUtil releaseLock:vc.userAgentLockToken];
+
+ /*
+ * Hide the Top Activity THROBBER in the Battery Bar
+ */
+ [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
+
+ [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:self.enginePlugin.webView]];
+}
+
+- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error
+{
+ CDVViewController* vc = (CDVViewController*)self.enginePlugin.viewController;
+
+ [CDVUserAgentUtil releaseLock:vc.userAgentLockToken];
+
+ NSString* message = [NSString stringWithFormat:@"Failed to load webpage with error: %@", [error localizedDescription]];
+ NSLog(@"%@", message);
+
+ NSURL* errorUrl = vc.errorURL;
+ if (errorUrl) {
+ errorUrl = [NSURL URLWithString:[NSString stringWithFormat:@"?error=%@", [message stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] relativeToURL:errorUrl];
+ NSLog(@"%@", [errorUrl absoluteString]);
+ [theWebView loadRequest:[NSURLRequest requestWithURL:errorUrl]];
+ }
+}
+
+- (BOOL)defaultResourcePolicyForURL:(NSURL*)url
+{
+ /*
+ * If a URL is being loaded that's a file url, just load it internally
+ */
+ if ([url isFileURL]) {
+ return YES;
+ }
+
+ return NO;
+}
+
+- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
+{
+ NSURL* url = [request URL];
+ CDVViewController* vc = (CDVViewController*)self.enginePlugin.viewController;
+
+ /*
+ * Execute any commands queued with cordova.exec() on the JS side.
+ * The part of the URL after gap:// is irrelevant.
+ */
+ if ([[url scheme] isEqualToString:@"gap"]) {
+ [vc.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.
+ [vc.commandQueue executePending];
+ return NO;
+ }
+
+ /*
+ * Give plugins the chance to handle the url
+ */
+ BOOL anyPluginsResponded = NO;
+ BOOL shouldAllowRequest = NO;
+
+ for (NSString* pluginName in vc.pluginObjects) {
+ CDVPlugin* plugin = [vc.pluginObjects objectForKey:pluginName];
+ SEL selector = NSSelectorFromString(@"shouldOverrideLoadWithRequest:navigationType:");
+ if ([plugin respondsToSelector:selector]) {
+ anyPluginsResponded = YES;
+ shouldAllowRequest = (((BOOL (*)(id, SEL, id, int))objc_msgSend)(plugin, selector, request, navigationType));
+ if (!shouldAllowRequest) {
+ break;
+ }
+ }
+ }
+
+ if (anyPluginsResponded) {
+ return shouldAllowRequest;
+ }
+
+ /*
+ * Handle all other types of urls (tel:, sms:), and requests to load a url in the main webview.
+ */
+ BOOL shouldAllowNavigation = [self defaultResourcePolicyForURL:url];
+ if (shouldAllowNavigation) {
+ return YES;
+ } else {
+ [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]];
+ }
+
+ return NO;
+}
+
+@end