diff options
| author | Rene Ae <aehtyb@gmail.com> | 2015-12-01 00:51:02 -0600 |
|---|---|---|
| committer | Rene Ae <aehtyb@gmail.com> | 2015-12-01 00:51:02 -0600 |
| commit | 6415f506034262dd7151be2e35e1e1c1e97f4dfa (patch) | |
| tree | c6e564e374967725a40fd87f7c5f3a1ba8019089 /StoneIsland/platforms/ios | |
| parent | 5e07e273e18a609978253c45f3c5f702b0de4991 (diff) | |
| parent | 9497b50fa02f3cfa9cb263ce3a96fa725282d60d (diff) | |
Merge branch 'master' of https://github.com/okfocus/stone-island
Diffstat (limited to 'StoneIsland/platforms/ios')
41 files changed, 1510 insertions, 109 deletions
diff --git a/StoneIsland/platforms/ios/StoneIsland.xcodeproj/project.pbxproj b/StoneIsland/platforms/ios/StoneIsland.xcodeproj/project.pbxproj index e75b8393..53038bdc 100644 --- a/StoneIsland/platforms/ios/StoneIsland.xcodeproj/project.pbxproj +++ b/StoneIsland/platforms/ios/StoneIsland.xcodeproj/project.pbxproj @@ -55,6 +55,9 @@ C2BF0352F9A246A886C16676 /* CDVViewController+SplashScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 58B5B2F329484022BEE14D58 /* CDVViewController+SplashScreen.m */; }; 4A80D26AF40046D7AD4979A9 /* AppDelegate+notification.m in Sources */ = {isa = PBXBuildFile; fileRef = EE6BC93769C04564BA35B9B4 /* AppDelegate+notification.m */; }; 4ABEABC16E324DEEB7A72E3B /* PushPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 450F6AEB11F34A6080834666 /* PushPlugin.m */; }; + 6084459294A8473FB8AA20F3 /* SocialSharing.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D2A7B40020F4AAEBE6DCEB1 /* SocialSharing.m */; }; + 98F1852ABB5E4B118CC6C27B /* Social.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88275732925E4321970403F3 /* Social.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 4C059853D8B843F88F01C944 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A186FB94DE714DEC95EA29D9 /* MessageUI.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -148,6 +151,10 @@ 450F6AEB11F34A6080834666 /* PushPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "PushPlugin.m"; path = "phonegap-plugin-push/PushPlugin.m"; sourceTree = "<group>"; fileEncoding = 4; }; 9F746E936D46499681DECD6E /* AppDelegate+notification.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "AppDelegate+notification.h"; path = "phonegap-plugin-push/AppDelegate+notification.h"; sourceTree = "<group>"; fileEncoding = 4; }; A3C287A7B1C74C02A8585FC2 /* PushPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "PushPlugin.h"; path = "phonegap-plugin-push/PushPlugin.h"; sourceTree = "<group>"; fileEncoding = 4; }; + 0D2A7B40020F4AAEBE6DCEB1 /* SocialSharing.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "SocialSharing.m"; path = "cordova-plugin-x-socialsharing/SocialSharing.m"; sourceTree = "<group>"; fileEncoding = 4; }; + 8A80AE176DAB4F84AC8031D7 /* SocialSharing.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SocialSharing.h"; path = "cordova-plugin-x-socialsharing/SocialSharing.h"; sourceTree = "<group>"; fileEncoding = 4; }; + 88275732925E4321970403F3 /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "Social.framework"; path = "System/Library/Frameworks/Social.framework"; sourceTree = SDKROOT; fileEncoding = 4; }; + A186FB94DE714DEC95EA29D9 /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "MessageUI.framework"; path = "System/Library/Frameworks/MessageUI.framework"; sourceTree = SDKROOT; fileEncoding = 4; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -162,6 +169,8 @@ 05EBE3ED6EA64212BCC52906 /* AudioToolbox.framework in Frameworks */, 85552B118FDD4F9286C3D33C /* CoreLocation.framework in Frameworks */, 28FA0D2F417F4E6891D4A2A3 /* SystemConfiguration.framework in Frameworks */, + 98F1852ABB5E4B118CC6C27B /* Social.framework in Frameworks */, + 4C059853D8B843F88F01C944 /* MessageUI.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -238,6 +247,8 @@ 270ADA31CA7B4A42B185E451 /* AudioToolbox.framework */, 88109882DED84831BEC5BBB0 /* CoreLocation.framework */, E63CFDA045E649E8A2E41A6E /* SystemConfiguration.framework */, + 88275732925E4321970403F3 /* Social.framework */, + A186FB94DE714DEC95EA29D9 /* MessageUI.framework */, ); name = Frameworks; sourceTree = "<group>"; @@ -277,6 +288,8 @@ 450F6AEB11F34A6080834666 /* PushPlugin.m */, 9F746E936D46499681DECD6E /* AppDelegate+notification.h */, A3C287A7B1C74C02A8585FC2 /* PushPlugin.h */, + 0D2A7B40020F4AAEBE6DCEB1 /* SocialSharing.m */, + 8A80AE176DAB4F84AC8031D7 /* SocialSharing.h */, ); name = Plugins; path = "StoneIsland/Plugins"; @@ -474,6 +487,7 @@ C2BF0352F9A246A886C16676 /* CDVViewController+SplashScreen.m in Sources */, 4A80D26AF40046D7AD4979A9 /* AppDelegate+notification.m in Sources */, 4ABEABC16E324DEEB7A72E3B /* PushPlugin.m in Sources */, + 6084459294A8473FB8AA20F3 /* SocialSharing.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/StoneIsland/platforms/ios/StoneIsland/Plugins/cordova-plugin-x-socialsharing/SocialSharing.h b/StoneIsland/platforms/ios/StoneIsland/Plugins/cordova-plugin-x-socialsharing/SocialSharing.h new file mode 100755 index 00000000..b51474d3 --- /dev/null +++ b/StoneIsland/platforms/ios/StoneIsland/Plugins/cordova-plugin-x-socialsharing/SocialSharing.h @@ -0,0 +1,27 @@ +#import <Cordova/CDV.h> +#import <MessageUI/MFMailComposeViewController.h> + +@interface SocialSharing : CDVPlugin <UIPopoverControllerDelegate, MFMailComposeViewControllerDelegate, UIDocumentInteractionControllerDelegate> + +@property (nonatomic, strong) MFMailComposeViewController *globalMailComposer; +@property (retain) UIDocumentInteractionController * documentInteractionController; +@property (retain) NSString * tempStoredFile; +@property (retain) CDVInvokedUrlCommand * command; + +- (void)available:(CDVInvokedUrlCommand*)command; +- (void)setIPadPopupCoordinates:(CDVInvokedUrlCommand*)command; +- (void)share:(CDVInvokedUrlCommand*)command; +- (void)canShareVia:(CDVInvokedUrlCommand*)command; +- (void)canShareViaEmail:(CDVInvokedUrlCommand*)command; +- (void)shareVia:(CDVInvokedUrlCommand*)command; +- (void)shareViaTwitter:(CDVInvokedUrlCommand*)command; +- (void)shareViaFacebook:(CDVInvokedUrlCommand*)command; +- (void)shareViaFacebookWithPasteMessageHint:(CDVInvokedUrlCommand*)command; +- (void)shareViaWhatsApp:(CDVInvokedUrlCommand*)command; +- (void)shareViaSMS:(CDVInvokedUrlCommand*)command; +- (void)shareViaEmail:(CDVInvokedUrlCommand*)command; +- (void)shareViaInstagram:(CDVInvokedUrlCommand*)command; + +- (void)saveToPhotoAlbum:(CDVInvokedUrlCommand*)command; + +@end diff --git a/StoneIsland/platforms/ios/StoneIsland/Plugins/cordova-plugin-x-socialsharing/SocialSharing.m b/StoneIsland/platforms/ios/StoneIsland/Plugins/cordova-plugin-x-socialsharing/SocialSharing.m new file mode 100755 index 00000000..cd0913a4 --- /dev/null +++ b/StoneIsland/platforms/ios/StoneIsland/Plugins/cordova-plugin-x-socialsharing/SocialSharing.m @@ -0,0 +1,715 @@ +#import "SocialSharing.h" +#import <Cordova/CDV.h> +#import <Social/Social.h> +#import <Foundation/NSException.h> +#import <MessageUI/MFMessageComposeViewController.h> +#import <MessageUI/MFMailComposeViewController.h> +#import <MobileCoreServices/MobileCoreServices.h> + +@implementation SocialSharing { + UIPopoverController *_popover; + NSString *_popupCoordinates; +} + +- (void)pluginInitialize { + if ([self isEmailAvailable]) { + [self cycleTheGlobalMailComposer]; + } +} + +- (void)available:(CDVInvokedUrlCommand*)command { + BOOL avail = NO; + if (NSClassFromString(@"UIActivityViewController")) { + avail = YES; + } + CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:avail]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; +} + +- (NSString*)getIPadPopupCoordinates { + if (_popupCoordinates != nil) { + return _popupCoordinates; + } + if ([self.webView respondsToSelector:@selector(stringByEvaluatingJavaScriptFromString:)]) { + return [(UIWebView*)self.webView stringByEvaluatingJavaScriptFromString:@"window.plugins.socialsharing.iPadPopupCoordinates();"]; + } else { + // prolly a wkwebview, ignoring for now + return nil; + } +} + +- (void)setIPadPopupCoordinates:(CDVInvokedUrlCommand*)command { + _popupCoordinates = [command.arguments objectAtIndex:0]; +} + +- (CGRect)getPopupRectFromIPadPopupCoordinates:(NSArray*)comps { + CGRect rect = CGRectZero; + if ([comps count] == 4) { + rect = CGRectMake([[comps objectAtIndex:0] integerValue], [[comps objectAtIndex:1] integerValue], [[comps objectAtIndex:2] integerValue], [[comps objectAtIndex:3] integerValue]); + } + return rect; +} + +- (void)share:(CDVInvokedUrlCommand*)command { + [self.commandDelegate runInBackground:^{ //avoid main thread block especially if sharing big files from url + if (!NSClassFromString(@"UIActivityViewController")) { + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"not available"]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + return; + } + + NSString *message = [command.arguments objectAtIndex:0]; + NSString *subject = [command.arguments objectAtIndex:1]; + NSArray *filenames = [command.arguments objectAtIndex:2]; + NSString *urlString = [command.arguments objectAtIndex:3]; + + NSMutableArray *activityItems = [[NSMutableArray alloc] init]; + [activityItems addObject:message]; + + NSMutableArray *files = [[NSMutableArray alloc] init]; + if (filenames != (id)[NSNull null] && filenames.count > 0) { + for (NSString* filename in filenames) { + NSObject *file = [self getImage:filename]; + if (file == nil) { + file = [self getFile:filename]; + } + if (file != nil) { + [files addObject:file]; + } + } + [activityItems addObjectsFromArray:files]; + } + + if (urlString != (id)[NSNull null]) { + [activityItems addObject:[NSURL URLWithString:urlString]]; + } + + UIActivity *activity = [[UIActivity alloc] init]; + NSArray *applicationActivities = [[NSArray alloc] initWithObjects:activity, nil]; + UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:applicationActivities]; + if (subject != (id)[NSNull null]) { + [activityVC setValue:subject forKey:@"subject"]; + } + + // TODO deprecated in iOS 8.0, change this some day + [activityVC setCompletionHandler:^(NSString *activityType, BOOL completed) { + [self cleanupStoredFiles]; + NSLog(@"SocialSharing app selected: %@", activityType); + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:completed]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + }]; + + NSArray * socialSharingExcludeActivities = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"SocialSharingExcludeActivities"]; + if (socialSharingExcludeActivities!=nil && [socialSharingExcludeActivities count] > 0) { + activityVC.excludedActivityTypes = socialSharingExcludeActivities; + } + + dispatch_async(dispatch_get_main_queue(), ^(void){ + // iPad on iOS >= 8 needs a different approach + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { + NSString* iPadCoords = [self getIPadPopupCoordinates]; + if (iPadCoords != nil && ![iPadCoords isEqual:@"-1,-1,-1,-1"]) { + NSArray *comps = [iPadCoords componentsSeparatedByString:@","]; + CGRect rect = [self getPopupRectFromIPadPopupCoordinates:comps]; + if ([activityVC respondsToSelector:@selector(popoverPresentationController)]) { +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 // iOS 8.0 supported + activityVC.popoverPresentationController.sourceView = self.webView; + activityVC.popoverPresentationController.sourceRect = rect; +#endif + } else { + _popover = [[UIPopoverController alloc] initWithContentViewController:activityVC]; + _popover.delegate = self; + [_popover presentPopoverFromRect:rect inView:self.webView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; + } + } else if ([activityVC respondsToSelector:@selector(popoverPresentationController)]) { +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 // iOS 8.0 supported + activityVC.popoverPresentationController.sourceView = self.webView; + // position the popup at the bottom, just like iOS < 8 did (and iPhone still does on iOS 8) + NSArray *comps = [NSArray arrayWithObjects: + [NSNumber numberWithInt:(self.viewController.view.frame.size.width/2)-200], + [NSNumber numberWithInt:self.viewController.view.frame.size.height], + [NSNumber numberWithInt:400], + [NSNumber numberWithInt:400], + nil]; + CGRect rect = [self getPopupRectFromIPadPopupCoordinates:comps]; + activityVC.popoverPresentationController.sourceRect = rect; +#endif + } + } + [[self getTopMostViewController] presentViewController:activityVC animated:YES completion:nil]; + }); + }]; +} + +- (void)shareViaTwitter:(CDVInvokedUrlCommand*)command { + [self shareViaInternal:command type:SLServiceTypeTwitter]; +} + +- (void)shareViaFacebook:(CDVInvokedUrlCommand*)command { + [self shareViaInternal:command type:SLServiceTypeFacebook]; +} + +- (void)shareViaFacebookWithPasteMessageHint:(CDVInvokedUrlCommand*)command { + // If Fb app is installed a message is not prefilled. + // When shared through the default iOS widget (iOS Settings > Facebook) the message is prefilled already. + NSString *message = [command.arguments objectAtIndex:0]; + if (message != (id)[NSNull null]) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1000 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{ + BOOL fbAppInstalled = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"fb://"]]; // requires whitelisting on iOS9 + if (fbAppInstalled) { + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + [pasteboard setValue:message forPasteboardType:@"public.text"]; + NSString *hint = [command.arguments objectAtIndex:4]; + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:hint delegate:nil cancelButtonTitle:nil otherButtonTitles:nil]; + [alert show]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2800 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{ + [alert dismissWithClickedButtonIndex:-1 animated:YES]; + }); + } + }); + } + [self shareViaInternal:command type:SLServiceTypeFacebook]; +} + +- (void)shareVia:(CDVInvokedUrlCommand*)command { + [self shareViaInternal:command type:[command.arguments objectAtIndex:4]]; +} + +- (void)canShareVia:(CDVInvokedUrlCommand*)command { + NSString *via = [command.arguments objectAtIndex:4]; + CDVPluginResult * pluginResult; + if ([@"sms" caseInsensitiveCompare:via] == NSOrderedSame && [self canShareViaSMS]) { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + } else if ([@"email" caseInsensitiveCompare:via] == NSOrderedSame && [self isEmailAvailable]) { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + } else if ([@"whatsapp" caseInsensitiveCompare:via] == NSOrderedSame && [self canShareViaWhatsApp]) { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + } else if ([@"instagram" caseInsensitiveCompare:via] == NSOrderedSame && [self canShareViaInstagram]) { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + } else if ([self isAvailableForSharing:command type:via]) { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + } else { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"not available"]; + } + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; +} + +- (void)canShareViaEmail:(CDVInvokedUrlCommand*)command { + if ([self isEmailAvailable]) { + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + } else { + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"not available"]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + } +} + +- (bool)isEmailAvailable { + Class messageClass = (NSClassFromString(@"MFMailComposeViewController")); + return messageClass != nil && [messageClass canSendMail]; +} + +- (bool)isAvailableForSharing:(CDVInvokedUrlCommand*)command + type:(NSString *) type { + // isAvailableForServiceType returns true if you pass it a type that is not + // in the defined constants, this is probably a bug on apples part + if(!([type isEqualToString:SLServiceTypeFacebook] + || [type isEqualToString:SLServiceTypeTwitter] + || [type isEqualToString:SLServiceTypeTencentWeibo] + || [type isEqualToString:SLServiceTypeSinaWeibo])) { + return false; + } + // wrapped in try-catch, because isAvailableForServiceType may crash if an invalid type is passed + @try { + return [SLComposeViewController isAvailableForServiceType:type]; + } + @catch (NSException* exception) { + return false; + } +} + +- (void)shareViaInternal:(CDVInvokedUrlCommand*)command + type:(NSString *) type { + + NSString *message = [command.arguments objectAtIndex:0]; + // subject is not supported by the SLComposeViewController + NSArray *filenames = [command.arguments objectAtIndex:2]; + NSString *urlString = [command.arguments objectAtIndex:3]; + + // boldly invoke the target app, because the phone will display a nice message asking to configure the app + SLComposeViewController *composeViewController = [SLComposeViewController composeViewControllerForServiceType:type]; + if (message != (id)[NSNull null]) { + [composeViewController setInitialText:message]; + } + + for (NSString* filename in filenames) { + UIImage* image = [self getImage:filename]; + if (image != nil) { + [composeViewController addImage:image]; + } + } + + if (urlString != (id)[NSNull null]) { + [composeViewController addURL:[NSURL URLWithString:urlString]]; + } + + [composeViewController setCompletionHandler:^(SLComposeViewControllerResult result) { + if (SLComposeViewControllerResultCancelled == result) { + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"cancelled"]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + } else if ([self isAvailableForSharing:command type:type]) { + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:SLComposeViewControllerResultDone == result]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + } else { + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"not available"]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + } + // required for iOS6 (issues #162 and #167) + [self.viewController dismissViewControllerAnimated:YES completion:nil]; + }]; + [[self getTopMostViewController] presentViewController:composeViewController animated:YES completion:nil]; +} + +- (void)shareViaEmail:(CDVInvokedUrlCommand*)command { + if ([self isEmailAvailable]) { + + if (TARGET_IPHONE_SIMULATOR && IsAtLeastiOSVersion(@"8.0")) { + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"SocialSharing plugin" + message:@"Sharing via email is not supported on the iOS 8 simulator." + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + [alert show]; + return; + } + + self.globalMailComposer.mailComposeDelegate = self; + + if ([command.arguments objectAtIndex:0] != (id)[NSNull null]) { + NSString *message = [command.arguments objectAtIndex:0]; + BOOL isHTML = [message rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch].location != NSNotFound; + [self.globalMailComposer setMessageBody:message isHTML:isHTML]; + } + + if ([command.arguments objectAtIndex:1] != (id)[NSNull null]) { + [self.globalMailComposer setSubject: [command.arguments objectAtIndex:1]]; + } + + if ([command.arguments objectAtIndex:2] != (id)[NSNull null]) { + [self.globalMailComposer setToRecipients:[command.arguments objectAtIndex:2]]; + } + + if ([command.arguments objectAtIndex:3] != (id)[NSNull null]) { + [self.globalMailComposer setCcRecipients:[command.arguments objectAtIndex:3]]; + } + + if ([command.arguments objectAtIndex:4] != (id)[NSNull null]) { + [self.globalMailComposer setBccRecipients:[command.arguments objectAtIndex:4]]; + } + + if ([command.arguments objectAtIndex:5] != (id)[NSNull null]) { + NSArray* attachments = [command.arguments objectAtIndex:5]; + NSFileManager* fileManager = [NSFileManager defaultManager]; + for (NSString* path in attachments) { + NSURL *file = [self getFile:path]; + NSData* data = [fileManager contentsAtPath:file.path]; + + NSString* fileName; + NSString* mimeType; + NSString* basename = [self getBasenameFromAttachmentPath:path]; + + if ([basename hasPrefix:@"data:"]) { + mimeType = (NSString*)[[[basename substringFromIndex:5] componentsSeparatedByString: @";"] objectAtIndex:0]; + fileName = @"attachment."; + fileName = [fileName stringByAppendingString:(NSString*)[[mimeType componentsSeparatedByString: @"/"] lastObject]]; + NSString *base64content = (NSString*)[[basename componentsSeparatedByString: @","] lastObject]; + data = [SocialSharing dataFromBase64String:base64content]; + } else { + fileName = [basename pathComponents].lastObject; + mimeType = [self getMimeTypeFromFileExtension:[basename pathExtension]]; + } + [self.globalMailComposer addAttachmentData:data mimeType:mimeType fileName:fileName]; + } + } + + // remember the command, because we need it in the didFinishWithResult method + _command = command; + + [self.commandDelegate runInBackground:^{ + [[self getTopMostViewController] presentViewController:self.globalMailComposer animated:YES completion:nil]; + }]; + + } else { + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"not available"]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + } +} + +- (UIViewController*) getTopMostViewController { + UIViewController *presentingViewController = [[[UIApplication sharedApplication] delegate] window].rootViewController; + while (presentingViewController.presentedViewController != nil) { + presentingViewController = presentingViewController.presentedViewController; + } + return presentingViewController; +} + +- (NSString*) getBasenameFromAttachmentPath:(NSString*)path { + if ([path hasPrefix:@"base64:"]) { + NSString* pathWithoutPrefix = [path stringByReplacingOccurrencesOfString:@"base64:" withString:@""]; + return [pathWithoutPrefix substringToIndex:[pathWithoutPrefix rangeOfString:@"//"].location]; + } + return path; +} + +- (NSString*) getMimeTypeFromFileExtension:(NSString*)extension { + if (!extension) { + return nil; + } + // Get the UTI from the file's extension + CFStringRef ext = (CFStringRef)CFBridgingRetain(extension); + CFStringRef type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext, NULL); + // Converting UTI to a mime type + NSString *result = (NSString*)CFBridgingRelease(UTTypeCopyPreferredTagWithClass(type, kUTTagClassMIMEType)); + CFRelease(ext); + CFRelease(type); + return result; +} + +/** + * Delegate will be called after the mail composer did finish an action + * to dismiss the view. + */ +- (void) mailComposeController:(MFMailComposeViewController*)controller + didFinishWithResult:(MFMailComposeResult)result + error:(NSError*)error { + bool ok = result == MFMailComposeResultSent; + [self.globalMailComposer dismissViewControllerAnimated:YES completion:^{[self cycleTheGlobalMailComposer];}]; + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:ok]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:_command.callbackId]; +} + +-(void)cycleTheGlobalMailComposer { + // we are cycling the damned GlobalMailComposer: http://stackoverflow.com/questions/25604552/i-have-real-misunderstanding-with-mfmailcomposeviewcontroller-in-swift-ios8-in/25604976#25604976 + self.globalMailComposer = nil; + self.globalMailComposer = [[MFMailComposeViewController alloc] init]; +} + +- (bool)canShareViaSMS { + Class messageClass = (NSClassFromString(@"MFMessageComposeViewController")); + return messageClass != nil && [messageClass canSendText]; +} + +- (void)shareViaSMS:(CDVInvokedUrlCommand*)command { + if ([self canShareViaSMS]) { + NSDictionary* options = [command.arguments objectAtIndex:0]; + NSString *phonenumbers = [command.arguments objectAtIndex:1]; + NSString *message = [options objectForKey:@"message"]; + NSString *subject = [options objectForKey:@"subject"]; + NSString *image = [options objectForKey:@"image"]; + + MFMessageComposeViewController *picker = [[MFMessageComposeViewController alloc] init]; + picker.messageComposeDelegate = (id) self; + if (message != (id)[NSNull null]) { + picker.body = message; + } + if (subject != (id)[NSNull null]) { + [picker setSubject:subject]; + } + if (image != nil && image != (id)[NSNull null]) { + BOOL canSendAttachments = [[MFMessageComposeViewController class] respondsToSelector:@selector(canSendAttachments)]; + if (canSendAttachments) { + NSURL *file = [self getFile:image]; + if (file != nil) { + [picker addAttachmentURL:file withAlternateFilename:nil]; + } + } + } + + if (phonenumbers != (id)[NSNull null]) { + [picker setRecipients:[phonenumbers componentsSeparatedByString:@","]]; + } + // remember the command, because we need it in the didFinishWithResult method + _command = command; + [self.commandDelegate runInBackground:^{ + picker.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; + [[self getTopMostViewController] presentViewController:picker animated:YES completion:nil]; + }]; + } else { + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"not available"]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + } +} + +// Dismisses the SMS composition interface when users taps Cancel or Send +- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result { + bool ok = result == MessageComposeResultSent; + [[self getTopMostViewController] dismissViewControllerAnimated:YES completion:nil]; + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:ok]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:_command.callbackId]; +} + +- (bool)canShareViaInstagram { + return [[UIApplication sharedApplication] canOpenURL: [NSURL URLWithString:@"instagram://app"]]; // requires whitelisting on iOS9 +} + +- (bool)canShareViaWhatsApp { + return [[UIApplication sharedApplication] canOpenURL: [NSURL URLWithString:@"whatsapp://app"]]; // requires whitelisting on iOS9 +} + +// this is only an internal test method for now, can be used to open a share sheet with 'Open in xx' links for tumblr, drive, dropbox, .. +- (void)openImage:(NSString *)imageName { + UIImage* image =[self getImage:imageName]; + if (image != nil) { + NSString * savePath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/myTempImage.jpg"]; + [UIImageJPEGRepresentation(image, 1.0) writeToFile:savePath atomically:YES]; + _documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:savePath]]; + _documentInteractionController.UTI = @""; // TODO find the scheme for google drive and create a shareViaGoogleDrive function + [_documentInteractionController presentOpenInMenuFromRect:CGRectZero inView:self.viewController.view animated: YES]; + } +} + +- (void)shareViaInstagram:(CDVInvokedUrlCommand*)command { + + // on iOS9 canShareVia('instagram'..) will only work if instagram:// is whitelisted. + // If it's not, this method will ask permission to the user on iOS9 for opening the app, + // which is of course better than Instagram sharing not working at all because you forgot to whitelist it. + // Tradeoff: on iOS9 this method will always return true, so make sure to whitelist it and call canShareVia('instagram'..) + if (!IsAtLeastiOSVersion(@"9.0")) { + if (![self canShareViaInstagram]) { + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"not available"]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + return; + } + } + + NSString *message = [command.arguments objectAtIndex:0]; + // subject is not supported by the SLComposeViewController + NSArray *filenames = [command.arguments objectAtIndex:2]; + + // only use the first image (for now.. maybe we can share in a loop?) + UIImage* image = nil; + for (NSString* filename in filenames) { + image = [self getImage:filename]; + break; + } + +// NSData *imageObj = [NSData dataFromBase64String:objectAtIndex0]; + NSString *tmpDir = NSTemporaryDirectory(); + NSString *path = [tmpDir stringByAppendingPathComponent:@"instagram.igo"]; + [UIImageJPEGRepresentation(image, 1.0) writeToFile:path atomically:YES]; + + _documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]]; + _documentInteractionController.delegate = self; + _documentInteractionController.UTI = @"com.instagram.exclusivegram"; + + if (message != (id)[NSNull null]) { + // no longer working, so .. + _documentInteractionController.annotation = @{@"InstagramCaption" : message}; + + // .. we put the message on the clipboard (you app can prompt the user to paste it) + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + [pasteboard setValue:message forPasteboardType:@"public.text"]; + } + + // remember the command for the delegate method + _command = command; + [_documentInteractionController presentOpenInMenuFromRect:CGRectZero inView:self.webView animated:YES]; +} + +- (void)shareViaWhatsApp:(CDVInvokedUrlCommand*)command { + + // on iOS9 canShareVia('whatsapp'..) will only work if whatsapp:// is whitelisted. + // If it's not, this method will ask permission to the user on iOS9 for opening the app, + // which is of course better than WhatsApp sharing not working at all because you forgot to whitelist it. + // Tradeoff: on iOS9 this method will always return true, so make sure to whitelist it and call canShareVia('whatsapp'..) + if (!IsAtLeastiOSVersion(@"9.0")) { + if (![self canShareViaWhatsApp]) { + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"not available"]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + return; + } + } + + NSString *message = [command.arguments objectAtIndex:0]; + // subject is not supported by the SLComposeViewController + NSArray *filenames = [command.arguments objectAtIndex:2]; + NSString *urlString = [command.arguments objectAtIndex:3]; + + // only use the first image (for now.. maybe we can share in a loop?) + UIImage* image = nil; + for (NSString* filename in filenames) { + image = [self getImage:filename]; + break; + } + + // with WhatsApp, we can share an image OR text+url.. image wins if set + if (image != nil) { + NSString * savePath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/whatsAppTmp.wai"]; + [UIImageJPEGRepresentation(image, 1.0) writeToFile:savePath atomically:YES]; + _documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:savePath]]; + _documentInteractionController.UTI = @"net.whatsapp.image"; + _documentInteractionController.delegate = self; + _command = command; + [_documentInteractionController presentOpenInMenuFromRect:CGRectZero inView:self.viewController.view animated: YES]; + } else { + // append an url to a message, if both are passed + NSString * shareString = @""; + if (message != (id)[NSNull null]) { + shareString = message; + } + if (urlString != (id)[NSNull null]) { + if ([shareString isEqual: @""]) { + shareString = urlString; + } else { + shareString = [NSString stringWithFormat:@"%@ %@", shareString, urlString]; + } + } + NSString * encodedShareString = [shareString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + // also encode the '=' character + encodedShareString = [encodedShareString stringByReplacingOccurrencesOfString:@"=" withString:@"%3D"]; + encodedShareString = [encodedShareString stringByReplacingOccurrencesOfString:@"&" withString:@"%26"]; + NSString * encodedShareStringForWhatsApp = [NSString stringWithFormat:@"whatsapp://send?text=%@", encodedShareString]; + + NSURL *whatsappURL = [NSURL URLWithString:encodedShareStringForWhatsApp]; + [[UIApplication sharedApplication] openURL: whatsappURL]; + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + } +} + +- (void)saveToPhotoAlbum:(CDVInvokedUrlCommand*)command { + self.command = command; + NSArray *filenames = [command.arguments objectAtIndex:0]; + [self.commandDelegate runInBackground:^{ + bool shared = false; + for (NSString* filename in filenames) { + UIImage* image = [self getImage:filename]; + if (image != nil) { + shared = true; + UIImageWriteToSavedPhotosAlbum(image, self, @selector(thisImage:wasSavedToPhotoAlbumWithError:contextInfo:), nil); + } + } + if (!shared) { + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no valid image was passed"]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:self.command.callbackId]; + } + }]; +} + +// called from saveToPhotoAlbum, note that we only send feedback for the first image that's being saved (not keeping the callback) +// but since the UIImageWriteToSavedPhotosAlbum function is only called with valid images that should not be a problem +- (void)thisImage:(UIImage *)image wasSavedToPhotoAlbumWithError:(NSError *)error contextInfo:(void*)ctxInfo { + if (error) { + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:error.localizedDescription]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:self.command.callbackId]; + } else { + CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:self.command.callbackId]; + } +} + +-(UIImage*)getImage: (NSString *)imageName { + UIImage *image = nil; + if (imageName != (id)[NSNull null]) { + if ([imageName hasPrefix:@"http"]) { + image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageName]]]; + } else if ([imageName hasPrefix:@"www/"]) { + image = [UIImage imageNamed:imageName]; + } else if ([imageName hasPrefix:@"file://"]) { + image = [UIImage imageWithData:[NSData dataWithContentsOfFile:[[NSURL URLWithString:imageName] path]]]; + } else if ([imageName hasPrefix:@"data:"]) { + // using a base64 encoded string + NSURL *imageURL = [NSURL URLWithString:imageName]; + NSData *imageData = [NSData dataWithContentsOfURL:imageURL]; + image = [UIImage imageWithData:imageData]; + } else if ([imageName hasPrefix:@"assets-library://"]) { + // use assets-library + NSURL *imageURL = [NSURL URLWithString:imageName]; + NSData *imageData = [NSData dataWithContentsOfURL:imageURL]; + image = [UIImage imageWithData:imageData]; + } else { + // assume anywhere else, on the local filesystem + image = [UIImage imageWithData:[NSData dataWithContentsOfFile:imageName]]; + } + } + return image; +} + +-(NSURL*)getFile: (NSString *)fileName { + NSURL *file = nil; + if (fileName != (id)[NSNull null]) { + if ([fileName hasPrefix:@"http"]) { + NSURL *url = [NSURL URLWithString:fileName]; + NSData *fileData = [NSData dataWithContentsOfURL:url]; + file = [NSURL fileURLWithPath:[self storeInFile:(NSString*)[[fileName componentsSeparatedByString: @"/"] lastObject] fileData:fileData]]; + } else if ([fileName hasPrefix:@"www/"]) { + NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; + NSString *fullPath = [NSString stringWithFormat:@"%@/%@", bundlePath, fileName]; + file = [NSURL fileURLWithPath:fullPath]; + } else if ([fileName hasPrefix:@"file://"]) { + // stripping the first 6 chars, because the path should start with / instead of file:// + file = [NSURL fileURLWithPath:[fileName substringFromIndex:6]]; + } else if ([fileName hasPrefix:@"data:"]) { + // using a base64 encoded string + // extract some info from the 'fileName', which is for example: data:text/calendar;base64,<encoded stuff here> + NSString *fileType = (NSString*)[[[fileName substringFromIndex:5] componentsSeparatedByString: @";"] objectAtIndex:0]; + fileType = (NSString*)[[fileType componentsSeparatedByString: @"/"] lastObject]; + NSString *base64content = (NSString*)[[fileName componentsSeparatedByString: @","] lastObject]; + NSData *fileData = [SocialSharing dataFromBase64String:base64content]; + file = [NSURL fileURLWithPath:[self storeInFile:[NSString stringWithFormat:@"%@.%@", @"file", fileType] fileData:fileData]]; + } else { + // assume anywhere else, on the local filesystem + file = [NSURL fileURLWithPath:fileName]; + } + } + return file; +} + +-(NSString*) storeInFile: (NSString*) fileName + fileData: (NSData*) fileData { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + NSString *filePath = [documentsDirectory stringByAppendingPathComponent:fileName]; + [fileData writeToFile:filePath atomically:YES]; + _tempStoredFile = filePath; + return filePath; +} + +- (void) cleanupStoredFiles { + if (_tempStoredFile != nil) { + NSError *error; + [[NSFileManager defaultManager]removeItemAtPath:_tempStoredFile error:&error]; + } +} + ++ (NSData*) dataFromBase64String:(NSString*)aString { + return [[NSData alloc] initWithBase64EncodedString:aString options:0]; +} + +#pragma mark - UIPopoverControllerDelegate methods + +- (void)popoverController:(UIPopoverController *)popoverController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView **)view { + NSArray *comps = [[self getIPadPopupCoordinates] componentsSeparatedByString:@","]; + CGRect newRect = [self getPopupRectFromIPadPopupCoordinates:comps]; + rect->origin = newRect.origin; +} + +- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController { + _popover = nil; +} + +#pragma mark - UIDocumentInteractionControllerDelegate methods + +- (void) documentInteractionController: (UIDocumentInteractionController *) controller willBeginSendingToApplication: (NSString *) application { + // note that the application actually contains the app bundle id which was picked (for whatsapp and instagram only) + NSLog(@"SocialSharing app selected: %@", application); +} + +- (void) documentInteractionControllerDidDismissOpenInMenu: (UIDocumentInteractionController *) controller { + if (self.command != nil) { + CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + [self.commandDelegate sendPluginResult:result callbackId: self.command.callbackId]; + } +} + +@end diff --git a/StoneIsland/platforms/ios/StoneIsland/StoneIsland-Info.plist b/StoneIsland/platforms/ios/StoneIsland/StoneIsland-Info.plist index 160c02b8..1e1baf13 100644 --- a/StoneIsland/platforms/ios/StoneIsland/StoneIsland-Info.plist +++ b/StoneIsland/platforms/ios/StoneIsland/StoneIsland-Info.plist @@ -182,5 +182,20 @@ <array> <string>remote-notification</string> </array> + <key>CFBundleURLTypes</key> + <array> + <dict> + <key>CFBundleURLSchemes</key> + <array> + <string>stoneisland</string> + </array> + </dict> + <dict> + <key>CFBundleURLSchemes</key> + <array> + <string>stoneisland</string> + </array> + </dict> + </array> </dict> </plist>
\ No newline at end of file diff --git a/StoneIsland/platforms/ios/StoneIsland/config.xml b/StoneIsland/platforms/ios/StoneIsland/config.xml index 3eaf2fb1..2fccdd54 100755 --- a/StoneIsland/platforms/ios/StoneIsland/config.xml +++ b/StoneIsland/platforms/ios/StoneIsland/config.xml @@ -36,6 +36,13 @@ <param name="ios-package" value="CDVSplashScreen" /> <param name="onload" value="true" /> </feature> + <feature name="PushNotification"> + <param name="ios-package" value="PushPlugin" /> + </feature> + <feature name="SocialSharing"> + <param name="ios-package" value="SocialSharing" /> + <param name="onload" value="true" /> + </feature> <allow-intent href="itms:*" /> <allow-intent href="itms-apps:*" /> <preference name="KeyboardDisplayRequiresUserAction" value="false" /> @@ -63,7 +70,4 @@ <preference name="StatusBarOverlaysWebView" value="false" /> <preference name="StatusBarBackgroundColor" value="#000000" /> <preference name="StatusBarStyle" value="lightcontent" /> - <feature name="PushNotification"> - <param name="ios-package" value="PushPlugin" /> - </feature> </widget> diff --git a/StoneIsland/platforms/ios/www/cordova_plugins.js b/StoneIsland/platforms/ios/www/cordova_plugins.js index fbdc76c9..f3038524 100644 --- a/StoneIsland/platforms/ios/www/cordova_plugins.js +++ b/StoneIsland/platforms/ios/www/cordova_plugins.js @@ -91,6 +91,20 @@ module.exports = [ "clobbers": [ "PushNotification" ] + }, + { + "file": "plugins/cordova-plugin-customurlscheme/www/ios/LaunchMyApp.js", + "id": "cordova-plugin-customurlscheme.LaunchMyApp", + "clobbers": [ + "window.plugins.launchmyapp" + ] + }, + { + "file": "plugins/cordova-plugin-x-socialsharing/www/SocialSharing.js", + "id": "cordova-plugin-x-socialsharing.SocialSharing", + "clobbers": [ + "window.plugins.socialsharing" + ] } ]; module.exports.metadata = @@ -104,7 +118,9 @@ module.exports.metadata = "cordova-plugin-geolocation": "1.0.1", "cordova-plugin-network-information": "1.0.1", "cordova-plugin-splashscreen": "2.1.0", - "phonegap-plugin-push": "1.4.4" + "phonegap-plugin-push": "1.4.4", + "cordova-plugin-customurlscheme": "4.0.0", + "cordova-plugin-x-socialsharing": "5.0.7" } // BOTTOM OF METADATA });
\ No newline at end of file diff --git a/StoneIsland/platforms/ios/www/css/account.css b/StoneIsland/platforms/ios/www/css/account.css index 31433871..3c04e1b1 100644 --- a/StoneIsland/platforms/ios/www/css/account.css +++ b/StoneIsland/platforms/ios/www/css/account.css @@ -38,15 +38,17 @@ #orders { display: none; } - -#orders.list { +#orders #order_list { + display: block; } -#orders.single { +#orders #single_order { + display: none; } - -#order_list { +#orders.single #order_list { + display: none; } -#single_order { +#orders.single #single_order { + display: block; } .settings #settings { display: block } @@ -403,4 +405,16 @@ input.switch:checked + label:after { color: #a9a9a9; padding-top: 9px; font-size: 14px; +} + +.container-row input:first-child { +margin-top:10px +} + +.container-row .half-input input { +margin-top:0px +} + +#login .container-row input:first-child { +margin-bottom:9px!important }
\ No newline at end of file diff --git a/StoneIsland/platforms/ios/www/css/blogs.css b/StoneIsland/platforms/ios/www/css/blogs.css index 0dd14166..0b9f8eed 100644 --- a/StoneIsland/platforms/ios/www/css/blogs.css +++ b/StoneIsland/platforms/ios/www/css/blogs.css @@ -53,18 +53,23 @@ padding: 10px; } -#content .content .body { +#hub .content .body { letter-spacing:0.35px; font-size:12px; width:calc(100vw - 40px); box-sizing:border-box; margin:10px auto 20px; + clear:both } -#content .content .body:last-child { +#hub .content .body:last-child { margin:10px auto 100px; } +.hub_item { + position: relative; +} + .content-header { width:calc(100vw - 40px); box-sizing:border-box; @@ -221,6 +226,10 @@ ul.links { transform: translateZ(0) translateX(-50%) translateY(-50%); } +#archive .menu .items { + border-top: 1px solid transparent; +} + #archive.menu .menu { opacity: 1; pointer-events: auto; @@ -237,6 +246,7 @@ ul.links { } #archive .menu .items { width: 100%; + } #archive .menu .item:first-of-type { border-top: 1px solid black; @@ -246,6 +256,9 @@ ul.links { text-align: center; border-bottom: 1px solid black; background: white; + padding:12px 0; + font-size:14px; + letter-spacing:0.7px } #archive .scroll { @@ -266,3 +279,32 @@ ul.links { #archive .row .text { width: 80%; } + +.gallery-video-post { +position:relative; +} + +.gallery-video-post .play { +width:60px; +height:60px; +border-radius:100px; +background:white; +box-shadow:0px 0px 2px #000; +position:absolute; +transform:translateY(-50%) translateX(-50%); +top:50%; +left:50%; +} + +.gallery-video-post .play:before { +content:''; + width: 0; + height: 0; + border-top: 8px solid transparent; + border-bottom: 8px solid transparent; + border-left: 8px solid black; + position:absolute; + top:50%; + left:50%; + transform:translateY(-50%) translateX(-50%); +}
\ No newline at end of file diff --git a/StoneIsland/platforms/ios/www/css/cart.css b/StoneIsland/platforms/ios/www/css/cart.css index a927f511..52b2a4cb 100644 --- a/StoneIsland/platforms/ios/www/css/cart.css +++ b/StoneIsland/platforms/ios/www/css/cart.css @@ -128,6 +128,42 @@ padding-bottom:5px; padding-left:5px; } +.cart_item_price .remove { +display:block; +width:20px; +height:20px; +border:1px solid #d2d2d2; +float:right; +margin-bottom:10px; +position:relative; +} + +.cart_item_price .remove:after { +content:''; +width:1px; +height:22px; +background:#bbb; +position:absolute; +top:50%; +left:50%; +z-index:3; +transform-origin:top left; +transform:rotate(45deg) translateX(-50%) translateY(-50%) +} + +.cart_item_price .remove:before { +content:''; +width:1px; +height:22px; +background:#bbb; +position:absolute; +top:50%; +left:50%; +z-index:3; +transform-origin:top left; +transform:rotate(-45deg) translateX(-50%) translateY(-50%) +} + .cart_item_price .price { font-size:11px; font-weight:bold; @@ -251,3 +287,7 @@ color:#000; .address .save_as_default { display: none; } + +#cart_shipping h3 { +margin-left:5px; +} diff --git a/StoneIsland/platforms/ios/www/css/nav.css b/StoneIsland/platforms/ios/www/css/nav.css index 3d2278d4..61834f8b 100644 --- a/StoneIsland/platforms/ios/www/css/nav.css +++ b/StoneIsland/platforms/ios/www/css/nav.css @@ -58,13 +58,15 @@ padding-bottom:45px!important; } -#nav .main_menu { display: block; } +#nav .main_menu { display: block; animation: mfadein 0.3s; } #nav .account_menu { display: none; } #nav .faq_menu { display: none; } #nav.faq .main_menu, #nav.account .main_menu { display: none; } #nav.account .account_menu { display: block; } -#nav.faq .faq_menu { display: block; } +#nav.faq .faq_menu { display: block; animation: mfadein 0.3s; } + +@keyframes mfadein { 0% { display: none; opacity: 0; } 1% { display:block; opacity: 0; } 100% { opacity: 1; } } #nav .submenu { position: absolute; diff --git a/StoneIsland/platforms/ios/www/css/products.css b/StoneIsland/platforms/ios/www/css/products.css index 2e9ead53..78d02811 100644 --- a/StoneIsland/platforms/ios/www/css/products.css +++ b/StoneIsland/platforms/ios/www/css/products.css @@ -12,6 +12,9 @@ width: 49vw; height: 63vw; } +#collection.gray { + background: rgba(245,245,245,1.0); +} .product #product { display: block } #product { @@ -170,7 +173,12 @@ letter-spacing:0.5px; text-decoration:underline; text-transform:uppercase; - padding:12px 0 2px; + padding:12px 0 0; + +} + +.product .content .fit { + } #product #gallery::before { @@ -215,3 +223,15 @@ display:block; } +#product .content .body { + letter-spacing:0.35px; + font-size:12px; + box-sizing:border-box; + margin:0px auto 20px; + clear:both; + padding:13px 0; +} + +#collection h1 { +background:white +} diff --git a/StoneIsland/platforms/ios/www/img/compass-logo.png b/StoneIsland/platforms/ios/www/img/compass-logo.png Binary files differindex d280a7fa..bdc8d946 100644..100755 --- a/StoneIsland/platforms/ios/www/img/compass-logo.png +++ b/StoneIsland/platforms/ios/www/img/compass-logo.png diff --git a/StoneIsland/platforms/ios/www/img/compass-logo.png.old b/StoneIsland/platforms/ios/www/img/compass-logo.png.old Binary files differnew file mode 100644 index 00000000..d280a7fa --- /dev/null +++ b/StoneIsland/platforms/ios/www/img/compass-logo.png.old diff --git a/StoneIsland/platforms/ios/www/img/spinner.gif b/StoneIsland/platforms/ios/www/img/spinner.gif Binary files differnew file mode 100644 index 00000000..d9e986d3 --- /dev/null +++ b/StoneIsland/platforms/ios/www/img/spinner.gif diff --git a/StoneIsland/platforms/ios/www/index.html b/StoneIsland/platforms/ios/www/index.html index 1f5a8f55..03d4a958 100644 --- a/StoneIsland/platforms/ios/www/index.html +++ b/StoneIsland/platforms/ios/www/index.html @@ -138,8 +138,10 @@ <h1>HUB</h1> <div class="content"> <script type="text/html" class="template"> - <div> + <div class="hub_item"> <div class="gallery gallery-{{id}}"></div> + <div class="gallery-left"></div> + <div class="gallery-right"></div> <div class="content-header"> <div class="content-share"> SHARE + @@ -252,6 +254,8 @@ <div class="item" style="background-image:url({{image}})"></div> </script> </div> + <div class="gallery-left"></div> + <div class="gallery-right"></div> <div class="content"> <div class="product-header"> <span class="num"></span> @@ -301,7 +305,7 @@ <form> <div class="container"> <div class="container-row"> - <input style="margin-bottom:10px" type="email" name="Email" placeholder="EMAIL ADDRESS" required> + <input type="email" name="Email" placeholder="EMAIL ADDRESS" required> <input type="password" name="Password" placeholder="PASSWORD" required> </div> <div class="container-fill"> @@ -342,14 +346,6 @@ <input type="email" name="ConfirmEmail" placeholder="CONFIRM EMAIL ADDRESS" required> <input type="date" name="BirthDay" placeholder="BIRTHDAY (MM/DD/YYYY)" required> - <div class="select-wrapper"> - <span>GENDER</span> - <select name="Gender"> - <option value="NONE">Gender</option> - <option value="U">Male</option> - <option value="D">Female</option> - </select> - </div> <h2>PASSWORD</h2> <input type="password" name="Password" placeholder="PASSWORD (7 CHARACTERS OR MORE)" required> <input type="password" name="Password2" placeholder="CONFIRM PASSWORD" required> @@ -403,15 +399,6 @@ <input type="email" name="Email" placeholder="EMAIL ADDRESS" required> <input type="date" name="BirthDay" placeholder="BIRTHDAY (MM/DD/YYYY)" required> - <div class="select-wrapper"> - <span>GENDER</span> - <select name="Gender"> - <option value="NONE">Gender</option> - <option value="U">Male</option> - <option value="D">Female</option> - </select> - </div> - <h2>CHANGE PASSWORD</h2> <input type="password" name="CurrentPassword" placeholder="CURRENT PASSWORD" required> <input type="password" name="NewPassword" placeholder="NEW PASSWORD (7 CHARACTERS OR MORE)" required> @@ -514,31 +501,75 @@ </div> <div id="orders"> - <h1>ORDERS</h1> - <div id="order_list"> - <div class="scroll"> - <script type="text/html" class="template"> - <div class="item"> + <div class="scroll"> + <h1>ORDERS</h1> + <div id="order_list"> + <div class="list"></div> + <div class="empty">You have no orders.</div> + <script type="text/html" class="list_template"> + <div class="item" data-id="{{id}}"> <div class="details"> Details > </div> <div class="txt"> {{date}}<br> - {{order_id}}<br> + {{id}}<br> {{total}} </div> - <div id="images"> + <div class="images"> </div> </div> </script> </div> - </div> - <div id="single_order"> - <div class="scroll"> - <div class="content"> + + <div id="single_order"> + <div class="order_section"> + <h2>ORDER SUMMARY</h2> + + <div class="rows"> + <script type="text/html" class="item_template"> + <div class="cart_item_info"> + <span class="sku">{{sku}}</span> + <span class="title">{{title}}</span> + <span class="type">{{type}}</span> + <div class="meta"> + <div class="meta-size"><b>SIZE:</b> {{size}}</div> + <div class="meta-color"><b>COLOR:</b> {{color}}</div> + <div class="meta-quantity"><b>QUANTITY:</b> {{quantity}}</div> + </div> + </div> + <div class="cart_item_price"> + <span class="price">{{price}}</span> + </div> + </script> + </div> + <div class="cart-summary"> + <div class="cart-summary-row"> + <span class="label">SUB TOTAL</span> + <span class="subtotal"></span> + </div> + <div class="cart-summary-row"> + <span class="label">ESTIMATED SHIPPING<br>& HANDLING</span> + <span class="shipping"></span> + </div> + <div class="cart-summary-row"> + <span class="label">TAX</span> + <span class="tax"></span> + </div> + <div class="cart-summary-row"> + <span class="label">TOTAL</span> + <span class="total"></span> + </div> + </div> </div> - <script type="text/html" class="template"> - </script> + + <div class="order_section"> + <h2>SHIP TO</h2> + + <div class="shipping_address"></div> + <div class="shipping_method"></div> + </div> + </div> </div> </div> @@ -582,7 +613,7 @@ </div> </div> <div class="cart_item_price"> - <span class="remove">x Remove from cart</span> + <span class="remove"></span> <span class="price">{{price}}</span> </div> </script> @@ -753,6 +784,10 @@ <div class="cc"></div> + <div class="cc_confirm"> + <h3>PLEASE ENTER YOUR SECURITY CODE TO CONFIRM</h3> + <input type="number" name="CvvConfirm" placeholder="SECURITY CODE" required> + </div> </div> <div class="container-fill"> @@ -764,6 +799,7 @@ </div> </div> </div> + <br><br><br><br> </form> </div> @@ -958,13 +994,27 @@ <option value="WV">West Virginia</option> <option value="WI">Wisconsin</option> <option value="WY">Wyoming</option> + <option disabled>_________________</option> + <option value="AB">Alberta</option> + <option value="BC">British Columbia</option> + <option value="MB">Manitoba</option> + <option value="NB">New Brunswick</option> + <option value="NL">Newfoundland and Labrador</option> + <option value="NS">Nova Scotia</option> + <option value="NT">Northwest Territories</option> + <option value="NU">Nunavut</option> + <option value="ON">Ontario</option> + <option value="PE">Prince Edward Island</option> + <option value="SK">Saskatchewan</option> + <option value="QC">Quebec</option> + <option value="YT">Yukon</option> </select> </div> </div> <div class="half-input"> <input type="text" name="ZipCode" placeholder="ZIP" required> <div class="country-wrapper-static"> - UNITED STATES + <span class="country-label">UNITED STATES</span> <!-- <div id="country-select"> <input type="text" name="Country" placeholder="UNITED STATES" required> @@ -1013,6 +1063,10 @@ <script src="js/sdk/product.js"></script> <script src="js/sdk/shipping.js"></script> +<script src="js/lib/etc/push.js"></script> +<script src="js/lib/etc/deeplink.js"></script> +<script src="js/lib/etc/geo.js"></script> + <script src="js/lib/view/View.js"></script> <script src="js/lib/view/Router.js"></script> <script src="js/lib/view/Scrollable.js"></script> @@ -1044,8 +1098,6 @@ <script src="js/lib/account/ShippingView.js"></script> <script src="js/lib/account/SettingsView.js"></script> <script src="js/lib/account/OrdersView.js"></script> -<script src="js/lib/account/orders/OrderList.js"></script> -<script src="js/lib/account/orders/SingleOrder.js"></script> <script src="js/lib/products/CollectionView.js"></script> <script src="js/lib/products/filters/CategoryFilter.js"></script> diff --git a/StoneIsland/platforms/ios/www/js/index.js b/StoneIsland/platforms/ios/www/js/index.js index 546bd637..e6bdf49f 100644 --- a/StoneIsland/platforms/ios/www/js/index.js +++ b/StoneIsland/platforms/ios/www/js/index.js @@ -63,12 +63,13 @@ var app = (function(){ app.ready = function(){ if (window.cordova) { - // cordova.plugins.Keyboard.disableScroll(true) + cordova.plugins.Keyboard.disableScroll(true) + geo.fetch() } app.view = null app.router = new SiteRouter () - app.account.connect( app.router.route.bind(app.router) ) + app.account.connect( app.router.launch.bind(app.router) ) $("body").removeClass("loading") } diff --git a/StoneIsland/platforms/ios/www/js/lib/_router.js b/StoneIsland/platforms/ios/www/js/lib/_router.js index b70d9be8..23daf4c7 100644 --- a/StoneIsland/platforms/ios/www/js/lib/_router.js +++ b/StoneIsland/platforms/ios/www/js/lib/_router.js @@ -47,6 +47,17 @@ var SiteRouter = Router.extend({ } } }, + + initial_route: null, + launch: function(){ + if (this.initial_route) { + this.parseRoute( this.initial_route ) + } + else { + this.route() + } + this.initial_route = null + }, go: function(url){ if (app.view && app.view.hide) { diff --git a/StoneIsland/platforms/ios/www/js/lib/account/OrdersView.js b/StoneIsland/platforms/ios/www/js/lib/account/OrdersView.js index 7283b65c..49901daa 100644 --- a/StoneIsland/platforms/ios/www/js/lib/account/OrdersView.js +++ b/StoneIsland/platforms/ios/www/js/lib/account/OrdersView.js @@ -1,29 +1,188 @@ -var OrdersView = View.extend({ +var OrdersView = ScrollableView.extend({ el: "#orders", + + loaded: false, + + list_template: $("#orders .list_template").html(), + item_template: $("#orders .item_template").html(), events: { "click .back": "back", - "click .details": "load_single", + "click .item": "load_single", }, initialize: function(){ - this.single = new SingleOrder ({ parent: this }) - this.list = new OrderList ({ parent: this }) + this.$list = this.$(".list") + this.$empty = this.$(".empty") + this.$single_order = this.$("#single_order") + + this.$rows = this.$(".rows") + this.$subtotal = this.$(".subtotal") + this.$shipping = this.$(".shipping") + this.$tax = this.$(".tax") + this.$total = this.$(".total") + + this.$shipping_address = this.$(".shipping_address") + this.$shipping_method = this.$(".shipping_method") + + this.scroller = new IScroll('#orders', app.iscroll_options) }, show: function(){ if (! auth.logged_in()) { return app.router.go("intro") } + app.header.set_back(false) app.footer.hide() document.body.className = "orders" - this.el.className = "list" + this.el.className = "" + + if (this.loaded) { + this.populate() + } + else { + this.fetch() + } + }, + + orders: null, + orderLookup: {}, + + fetch: function(){ + this.$list.empty() + this.$empty.hide() + this.loader = new Loader(this.ready.bind(this)) + app.curtain.show("loading") + sdk.account.fetch_orders({ + success: function(data){ + this.loader.register("orders") + this.orders = data.OrderDetails + data.OrderDetails.forEach(function(row){ + this.loader.register(row.OrderNumber) + sdk.account.fetch_single_order({ + id: row.OrderNumber, + success: function(row_data){ + this.orderLookup[ row.OrderNumber ] = row_data.OrderFullDetails + this.loader.ready(row.OrderNumber) + }.bind(this), + error: function(){ + this.orderLookup[ row.OrderNumber ] = null + this.loader.ready(row.OrderNumber) + }.bind(this), + }) + }.bind(this)) + this.loader.ready("orders") + }.bind(this), + error: function(){ + console.log("error fetching orders") + }.bind(this), + }) + }, + + ready: function(){ + this.populate() + app.curtain.hide("loading") + }, + + populate: function(){ + this.$list.empty() + + if (! this.orders.length) { + this.$empty.show() + return + } + else { + this.$empty.hide() + } + this.orders.forEach(function(row){ + var order = this.orderLookup[ row.OrderNumber ] + if (! order) { return } + var t = this.list_template.replace(/{{date}}/g, moment(order['Date']).format("ddd MM/DD/YYYY").toUpperCase()) + .replace(/{{id}}/g, row.OrderNumber) + .replace(/{{total}}/g, as_cash( order.TotalAmount )) + var $t = $(t), $images = $t.find(".images") + order.Items.forEach(function(item){ + var img = new Image () + img.src = sdk.image(item['Code10'], "11_f") + $images.append(img) + }.bind(this)) + this.$list.append($t) + }.bind(this)) + + this.refreshScroller() }, + + load_single: function(e){ + var id = $(e.currentTarget).data("id") + var order = this.orderLookup[ id ] + if (! order) { return } + + console.log(order) + + this.$rows.empty() + + order.Items.forEach(function(item){ + var $el = $("<div class='item'><img src='img/spinner.gif'></div>") + this.$rows.append($el) + var code_ten = item.Code10 + + var code = code_ten.substr(0, 8) + app.product.find(code, function(data, details){ + var descriptions = app.product.get_descriptions( details ) + + var name_partz = descriptions['ModelNames'].split(' ') + var num = name_partz.shift() + var title = name_partz.join(' ') + var type = title_case( descriptions['MicroCategory'] ) + + var color_name, size_name - load_single: function(){ + details.Item.ModelColors.some(function(color){ + if (color['Code10'] == code_ten) { + color_name = color['ColorDescription'] + return true + } + return false + }) + size_name = item.DefaultSize + " " + item.DefaultSizeClassFamily + + var t = this.item_template + .replace(/{{image}}/, sdk.image(item['Code10'], '11_f')) + .replace(/{{sku}}/, num) + .replace(/{{title}}/, title) + .replace(/{{type}}/, type) + .replace(/{{size}}/, size_name || "DEFAULT") + .replace(/{{color}}/, color_name || "DEFAULT") + .replace(/{{quantity}}/, 1) + .replace(/{{price}}/, as_cash(details.Item.Price.DiscountedPrice)) + $el.data("price", details.Item.Price.DiscountedPrice) + $el.html(t) + this.refreshScroller() + }.bind(this)) + }.bind(this)) + + var subtotal = order.ItemsTotalAmount + var shipping_cost = order.Delivery.Amount + var tax = order.SalesTaxAmount + var total = order.TotalToPay + + this.$subtotal.html( as_cash(subtotal) ) + this.$shipping.html( as_cash(shipping_cost) ) + this.$tax.html( as_cash(tax) ) + this.$total.html( as_cash(total) ) + + var street = order.Delivery.Address.replace(/\n$/,"").replace("\n","<br>") + var address = order.Delivery.Name + "<br>" + street + "<br>" + order.Delivery.City + " " + order.Delivery.ZipCode + this.$shipping_address.html(address) + this.$shipping_method.html(order.Delivery.Type + " - " + order.Delivery.Time) + + app.header.set_back(true) + this.$el.addClass("single") }, back: function(){ - this.list.show() + app.header.set_back(false) + this.el.className = "" }, }) + diff --git a/StoneIsland/platforms/ios/www/js/lib/account/ProfileView.js b/StoneIsland/platforms/ios/www/js/lib/account/ProfileView.js index 999e8d65..da25fefc 100644 --- a/StoneIsland/platforms/ios/www/js/lib/account/ProfileView.js +++ b/StoneIsland/platforms/ios/www/js/lib/account/ProfileView.js @@ -5,6 +5,8 @@ var ProfileView = FormView.extend({ events: { }, + action: sdk.account.update, + initialize: function(){ this.$form = this.$("form") this.$msg = this.$(".msg") @@ -30,7 +32,7 @@ var ProfileView = FormView.extend({ if (! data.CurrentPassword && (data.NewPassword || data.Email !== auth.user.Email)) { errors.push([ "CurrentPassword", "Please enter your current password." ]) } if (data.CurrentPassword && ! data.NewPassword) { errors.push([ "NewPassword", "Please enter your new password." ]) } if (data.NewPassword && data.NewPassword.length < 7) { errors.push([ "CurrentPassword", "New password must be 7 characters or more." ]) } - if (data.Gender === "NONE") { errors.push([ "Gender", "Please supply your gender." ]) } + // if (data.Gender === "NONE") { errors.push([ "Gender", "Please supply your gender." ]) } }, finalize: function(data){ @@ -50,7 +52,8 @@ var ProfileView = FormView.extend({ }) } - var submissible_data = _.pick(data, "Name Surname BirthDay Gender YooxLetter".split(" ")) + var submissible_data = _.pick(data, "Name Surname BirthDay YooxLetter".split(" ")) + submissible_data.Gender = "U" // submissible_data.idUser = auth.user_id // submissible_data.AccessToken = auth.access_token // submissible_data.Premium = "false" diff --git a/StoneIsland/platforms/ios/www/js/lib/account/orders/OrderList.js b/StoneIsland/platforms/ios/www/js/lib/account/orders/OrderList.js deleted file mode 100644 index 876f609e..00000000 --- a/StoneIsland/platforms/ios/www/js/lib/account/orders/OrderList.js +++ /dev/null @@ -1,17 +0,0 @@ -var OrderList = ScrollableView.extend({ - - el: "#order_list", - - template: $("#order_list .template"), - - initialize: function(opt){ - this.parent = opt.parent - this.scroller = new IScroll('#order_list', app.iscroll_options) - }, - - show: function(){ - document.body.className = "orders" - app.orders.el.className = "list" - }, - -}) diff --git a/StoneIsland/platforms/ios/www/js/lib/account/orders/SingleOrder.js b/StoneIsland/platforms/ios/www/js/lib/account/orders/SingleOrder.js deleted file mode 100644 index 21416401..00000000 --- a/StoneIsland/platforms/ios/www/js/lib/account/orders/SingleOrder.js +++ /dev/null @@ -1,18 +0,0 @@ -var SingleOrder = ScrollableView.extend({ - - el: "#single_order", - - template: $("#single_order .template"), - - initialize: function(opt){ - this.parent = opt.parent - this.scroller = new IScroll('#single_order', app.iscroll_options) - }, - - show: function(id){ - document.body.className = "orders" - app.orders.el.className = "single" - this.deferScrollToTop() - }, - -}) diff --git a/StoneIsland/platforms/ios/www/js/lib/auth/SignupView.js b/StoneIsland/platforms/ios/www/js/lib/auth/SignupView.js index 7e6fc04d..22b310de 100644 --- a/StoneIsland/platforms/ios/www/js/lib/auth/SignupView.js +++ b/StoneIsland/platforms/ios/www/js/lib/auth/SignupView.js @@ -57,7 +57,7 @@ var SignupView = FormView.extend({ if (data.Password !== data.Password2) { errors.push([ "Password2", "Passwords don't match." ]) } if (! data.Email.match("@")) { errors.push([ "Email", "Email address is not valid." ]) } if (data.Email.toLowerCase() !== data.ConfirmEmail.toLowerCase()) { errors.push([ "ConfirmEmail", "Email addresses don't match." ]) } - if (data.Gender === "NONE") { errors.push([ "Gender", "Please supply your gender." ]) } + // if (data.Gender === "NONE") { errors.push([ "Gender", "Please supply your gender." ]) } if (data.DataProfiling !== "true") { errors.push([ "DataProfiling", "You must consent to use this service." ]) } if (data.DataProfiling2 !== "true") { errors.push([ "DataProfiling2", "You must consent to use this service." ]) } if (! data.YooxLetter) { data.YooxLetter = false } @@ -67,6 +67,7 @@ var SignupView = FormView.extend({ delete data.DataProfiling2 delete data.ConfirmEmail + data.Gender = "U" data.BirthDay += "T00:00:00Z" this.last_data = data diff --git a/StoneIsland/platforms/ios/www/js/lib/blogs/ArchiveView.js b/StoneIsland/platforms/ios/www/js/lib/blogs/ArchiveView.js index 3db5c8da..f0a796bf 100644 --- a/StoneIsland/platforms/ios/www/js/lib/blogs/ArchiveView.js +++ b/StoneIsland/platforms/ios/www/js/lib/blogs/ArchiveView.js @@ -33,6 +33,8 @@ var ArchiveView = ScrollableView.extend({ }, populate: function(data){ + if (this.loaded) { return } + this.loaded = true this.data = data this.$loader.hide() this.$content.empty() diff --git a/StoneIsland/platforms/ios/www/js/lib/blogs/BlogView.js b/StoneIsland/platforms/ios/www/js/lib/blogs/BlogView.js index 19666f8b..3ea35418 100644 --- a/StoneIsland/platforms/ios/www/js/lib/blogs/BlogView.js +++ b/StoneIsland/platforms/ios/www/js/lib/blogs/BlogView.js @@ -42,6 +42,19 @@ var BlogView = View.extend({ if (data.store[0].StoreIsOpen !== "true") { app.closed.storeIsClosed = true } + var fits_large = (data.store[0].FitsLarge === "true") + + app.product.$fit.toggle( fits_large ) + app.product.$sizing.toggle( fits_large ) + + if (data.store[0].BackgroundIsGray === "true") { + app.collection.$el.addClass("gray") + app.product.gallery.$el.addClass("gray") + } + + app.gallery_id = data.store[0].CollectionId + + app.collection.fetch() }, })
\ No newline at end of file diff --git a/StoneIsland/platforms/ios/www/js/lib/blogs/HubView.js b/StoneIsland/platforms/ios/www/js/lib/blogs/HubView.js index 3b2900ad..a6ae958e 100644 --- a/StoneIsland/platforms/ios/www/js/lib/blogs/HubView.js +++ b/StoneIsland/platforms/ios/www/js/lib/blogs/HubView.js @@ -5,6 +5,8 @@ var HubView = ScrollableView.extend({ events: { "click .store": "store_link", + "click .gallery-left": "gallery_left", + "click .gallery-right": "gallery_right", }, initialize: function(){ @@ -73,6 +75,8 @@ var HubView = ScrollableView.extend({ play.className = "play" $(".gallery-" + row.id).append(play) } + $t.find("gallery-left").remove() + $t.find("gallery-right").remove() } }.bind(this)) @@ -83,5 +87,12 @@ var HubView = ScrollableView.extend({ store_link: function(){ app.router.go("store") }, + + gallery_prev: function(e){ + $(e.currentTarget).closest("hub_item").flickity('prev') + }, + gallery_next: function(e){ + $(e.currentTarget).closest("hub_item").flickity('next') + }, })
\ No newline at end of file diff --git a/StoneIsland/platforms/ios/www/js/lib/cart/CartShipping.js b/StoneIsland/platforms/ios/www/js/lib/cart/CartShipping.js index 1a9653e1..9b8205c1 100644 --- a/StoneIsland/platforms/ios/www/js/lib/cart/CartShipping.js +++ b/StoneIsland/platforms/ios/www/js/lib/cart/CartShipping.js @@ -101,7 +101,7 @@ var CartShipping = FormView.extend({ shipping_info.City = address_data.City shipping_info.Province = address_data.Province shipping_info.Region = address_data.Province - shipping_info.CountryCode = "US" + shipping_info.CountryCode = CANADIAN_LOOKUP[ address_data.Province ] ? "CA" : "US" return shipping_info }, diff --git a/StoneIsland/platforms/ios/www/js/lib/cart/CartSummary.js b/StoneIsland/platforms/ios/www/js/lib/cart/CartSummary.js index 9a24afa5..72c44405 100644 --- a/StoneIsland/platforms/ios/www/js/lib/cart/CartSummary.js +++ b/StoneIsland/platforms/ios/www/js/lib/cart/CartSummary.js @@ -64,6 +64,7 @@ var CartSummary = ScrollableView.extend({ var size_id = item['Size'] var $el = $("<div>").addClass("cart_item_row") + $el.html("<img src='img/spinner.gif'>") $el.data({ code: code_ten, size: size_id, @@ -95,6 +96,10 @@ var CartSummary = ScrollableView.extend({ // console.log(size) size_name = size['Default']['Text'] size_name = SIZE_LOOKUP[ size_name ] || size_name + if (! size_name && ! size['Default']['Labeled']) { + size_name = size['Default']['Text'] + " " + size['Default']['ClassFamily'] + } + return true } return false @@ -109,7 +114,6 @@ var CartSummary = ScrollableView.extend({ .replace(/{{color}}/, color_name) .replace(/{{quantity}}/, 1) .replace(/{{price}}/, as_cash(details.Item.Price.DiscountedPrice)) - $el.data("price", details.Item.Price.DiscountedPrice) $el.html(t) this.refreshScroller() }.bind(this)) diff --git a/StoneIsland/platforms/ios/www/js/lib/cart/CartThanks.js b/StoneIsland/platforms/ios/www/js/lib/cart/CartThanks.js index 993fd9ac..eb95197b 100644 --- a/StoneIsland/platforms/ios/www/js/lib/cart/CartThanks.js +++ b/StoneIsland/platforms/ios/www/js/lib/cart/CartThanks.js @@ -14,6 +14,8 @@ var CartThanks = View.extend({ app.cart.el.className = "thanks" app.footer.show("< BACK TO COLLECTION") app.footer.hide() + + app.orders.loaded = false }, ok: function(){ diff --git a/StoneIsland/platforms/ios/www/js/lib/etc/deeplink.js b/StoneIsland/platforms/ios/www/js/lib/etc/deeplink.js new file mode 100644 index 00000000..648dd167 --- /dev/null +++ b/StoneIsland/platforms/ios/www/js/lib/etc/deeplink.js @@ -0,0 +1,3 @@ +function handleOpenURL (url) { + app.router.initial_route = url +}
\ No newline at end of file diff --git a/StoneIsland/platforms/ios/www/js/lib/etc/geo.js b/StoneIsland/platforms/ios/www/js/lib/etc/geo.js new file mode 100644 index 00000000..0270d681 --- /dev/null +++ b/StoneIsland/platforms/ios/www/js/lib/etc/geo.js @@ -0,0 +1,33 @@ +var geo = (function(){ + var geo = {} + + geo.fetch = function(){ + navigator.geolocation.getCurrentPosition(geo.success, geo.error, {timeout: 15000}) + } + + geo.success = function(position){ + var lat_str = as_degrees( position.coords.latitude ) + var lng_str = as_degrees( position.coords.longitude ) + } + + geo.error = function(error){ + $(".latlng").html( "+40° 58' 90\" -74° 04' 46\"" ) + } + + function as_degrees (n) { + var s = "" + if (n >= 0) s += "+" + s += Math.floor(n) + "° " + + n %= 1 + n *= 60 + s += Math.floor(n) + "'" + + n %= 1 + n *= 60 + + s += Math.floor(n) + '"' + } + + return geo +})()
\ No newline at end of file diff --git a/StoneIsland/platforms/ios/www/js/lib/etc/push.js b/StoneIsland/platforms/ios/www/js/lib/etc/push.js new file mode 100644 index 00000000..ab0c0141 --- /dev/null +++ b/StoneIsland/platforms/ios/www/js/lib/etc/push.js @@ -0,0 +1 @@ +//
\ No newline at end of file diff --git a/StoneIsland/platforms/ios/www/js/lib/nav/AddressView.js b/StoneIsland/platforms/ios/www/js/lib/nav/AddressView.js index 31e9d802..ad5745fb 100644 --- a/StoneIsland/platforms/ios/www/js/lib/nav/AddressView.js +++ b/StoneIsland/platforms/ios/www/js/lib/nav/AddressView.js @@ -6,6 +6,7 @@ var AddressView = SerializableView.extend({ disabled: false, events: { + "change [name=Province]": 'update_country', }, initialize: function(opt){ @@ -22,6 +23,7 @@ var AddressView = SerializableView.extend({ data.Address2 = address[1] this.$(".address input").val("") this.load_data(data) + this.update_country() }, validate_presence: { @@ -43,8 +45,22 @@ var AddressView = SerializableView.extend({ delete data.Address2 }, + update_country: function(){ + var state = this.$("[name=Province]").val() + console.log(state) + if (CANADIAN_LOOKUP[state]) { + this.$(".country-label").html("CANADA") + } + else { + this.$(".country-label").html("UNITED STATES") + } + }, + }) +var CANADIAN_PROVINCES = "AB BC MB NB NL NS NT NU ON PE SK QC YT".split(" ") +var CANADIAN_LOOKUP = {} +CANADIAN_PROVINCES.forEach(function(k){ CANADIAN_LOOKUP[k] = true }) var COUNTRIES = [ ['Country Name', 'NONE'], diff --git a/StoneIsland/platforms/ios/www/js/lib/nav/CreditCardView.js b/StoneIsland/platforms/ios/www/js/lib/nav/CreditCardView.js index 1855b7a9..ba3ac54a 100644 --- a/StoneIsland/platforms/ios/www/js/lib/nav/CreditCardView.js +++ b/StoneIsland/platforms/ios/www/js/lib/nav/CreditCardView.js @@ -4,7 +4,7 @@ var CreditCardView = SerializableView.extend({ template: $("#creditcard_template").html(), cardOptions: { - accept: ['visa', 'mastercard', 'amex'], + accept: ['visa', 'mastercard', 'amex', 'jcb'], }, events: { @@ -46,8 +46,15 @@ var CreditCardView = SerializableView.extend({ if (! data.ExpirationYear || data.ExpirationYear == "NONE") { errors.push([ "ExpirationYear", "Please select the expiration month." ]) } data.UserId = auth.user_id if (card.valid) { - data.Type = card.card_type.name + data.Type = YOOX_CREDIT_CARD_NAME_LOOKUP[ card.card_type.name ] } }, }) + +var YOOX_CREDIT_CARD_NAME_LOOKUP = { + "visa": "Visa", + "mastercard": "Mastercard", + "amex": "AmericanExpress", + "jcb": "JCB", +} diff --git a/StoneIsland/platforms/ios/www/js/lib/products/CollectionView.js b/StoneIsland/platforms/ios/www/js/lib/products/CollectionView.js index e35b789d..056f2a52 100644 --- a/StoneIsland/platforms/ios/www/js/lib/products/CollectionView.js +++ b/StoneIsland/platforms/ios/www/js/lib/products/CollectionView.js @@ -33,7 +33,7 @@ var CollectionView = ScrollableView.extend({ if (this.loaded) { return this.populate(this.data) } - this.fetch() + // this.fetch() }, save: function(){ @@ -44,7 +44,7 @@ var CollectionView = ScrollableView.extend({ if (this.loaded) return this.$loader.show() sdk.product.collection({ - gallery_id: 32780, + gallery_id: app.gallery_id, success: this.populate.bind(this) }) }, @@ -65,6 +65,7 @@ var CollectionView = ScrollableView.extend({ this.deferScrollToTop() } this.afterFetchCallback && this.afterFetchCallback() + app.collection.deferRefresh() }, append: function(item){ diff --git a/StoneIsland/platforms/ios/www/js/lib/products/GalleryView.js b/StoneIsland/platforms/ios/www/js/lib/products/GalleryView.js index ea4637eb..b36c5df2 100644 --- a/StoneIsland/platforms/ios/www/js/lib/products/GalleryView.js +++ b/StoneIsland/platforms/ios/www/js/lib/products/GalleryView.js @@ -31,7 +31,7 @@ var GalleryView = View.extend({ valid_styles[style] = size } }) - Object.keys(valid_styles).forEach(function(style){ + Object.keys(valid_styles).sort(sort_image_styles).forEach(function(style){ var id = valid_styles[style] + "_" + style var t = this.template.replace(/{{image}}/, sdk.image(code, id)) this.$el.append(t) @@ -62,4 +62,8 @@ var GalleryView = View.extend({ touchend: function(e){ }, -})
\ No newline at end of file +}) + +var YOOX_IMAGE_STYLE_ORDER = "ZZZ d f".split(" ") + +function sort_image_styles (b,a){ return (YOOX_IMAGE_STYLE_ORDER.indexOf(a)) - (YOOX_IMAGE_STYLE_ORDER.indexOf(b)) }
\ No newline at end of file diff --git a/StoneIsland/platforms/ios/www/js/lib/products/ProductView.js b/StoneIsland/platforms/ios/www/js/lib/products/ProductView.js index e151c208..92a0e0f7 100644 --- a/StoneIsland/platforms/ios/www/js/lib/products/ProductView.js +++ b/StoneIsland/platforms/ios/www/js/lib/products/ProductView.js @@ -4,9 +4,12 @@ var ProductView = ScrollableView.extend({ el: "#product", events: { + "click .fit": "scroll_to_bottom", "click .size": "select_size", "click .color": "select_color", "click .share": "share", + "click .gallery-left": "gallery_left", + "click .gallery-right": "gallery_right", }, initialize: function(){ @@ -20,6 +23,8 @@ var ProductView = ScrollableView.extend({ this.$size = this.$(".size") this.$color = this.$(".color") this.$body = this.$(".body") + this.$fit = this.$(".fit") + this.$sizing = this.$(".sizing") }, show: function(){ @@ -41,8 +46,15 @@ var ProductView = ScrollableView.extend({ cache: {}, + gallery_prev: function(){ + this.gallery.gallery.flickity('prev') + }, + gallery_right: function(){ + this.gallery.gallery.flickity('next') + }, + find: function(code, cb){ - data = app.collection.items[code] + data = app.collection.items[code] || {} if (code in this.cache) { return cb(data, this.cache[code]) } @@ -165,9 +177,14 @@ var ProductView = ScrollableView.extend({ sizes: {}, } }) + details['Item']['ModelSizes'].forEach(function(size){ var label = SIZE_LOOKUP[ size['Default']['Text'] ] + if (! label && ! size['Default']['Labeled']) { + label = size['Default']['Text'] + " " + size['Default']['ClassFamily'] + } size_lookup[ label ] = size['SizeId'] + console.log( label ) sizes[ size['SizeId'] ] = { id: label, label: label.toUpperCase(), @@ -242,6 +259,9 @@ var ProductView = ScrollableView.extend({ app.router.go('store') }, + scroll_to_bottom: function(){ + }, + share: function(){ }, diff --git a/StoneIsland/platforms/ios/www/js/lib/view/Scrollable.js b/StoneIsland/platforms/ios/www/js/lib/view/Scrollable.js index 7cd96f89..d06ed590 100644 --- a/StoneIsland/platforms/ios/www/js/lib/view/Scrollable.js +++ b/StoneIsland/platforms/ios/www/js/lib/view/Scrollable.js @@ -1,7 +1,7 @@ var ScrollableView = View.extend({ events: { - "load img": "deferScrollToTop", + "load img": "deferRefresh", }, deferScrollToTop: function(){ @@ -10,8 +10,15 @@ var ScrollableView = View.extend({ refreshScroller: function(){ this.scroller.refresh() + clearTimeout( this.scrollerRefreshTimeout ) }, - + + scrollerRefreshTimeout: null, + deferRefresh: function(){ + clearTimeout( this.scrollerRefreshTimeout ) + this.scrollerRefreshTimeout = setTimeout(this.refreshScroller.bind(this)) + }, + scrollToTop: function(){ this.scroller.refresh() app.collection.scroller.scrollTo(0, 0) diff --git a/StoneIsland/platforms/ios/www/js/sdk/account.js b/StoneIsland/platforms/ios/www/js/sdk/account.js index fe5f03cd..3eb3f3bd 100644 --- a/StoneIsland/platforms/ios/www/js/sdk/account.js +++ b/StoneIsland/platforms/ios/www/js/sdk/account.js @@ -96,6 +96,38 @@ sdk.account = (function(){ }) } + account.fetch_orders = function(opt){ + return $.ajax({ + method: "GET", + url: sdk.path("Account.API/1.5", "users/" + auth.user_id + "/orders.json"), + headers: { + "x-yoox-appname": auth.appname, + "x-yoox-account-token": auth.access_token, + }, + data: JSON.stringify( opt.data ), + success: function(data){ + opt.success(data) + }, + error: opt.error, + }) + } + + account.fetch_single_order = function(opt){ + return $.ajax({ + method: "GET", + url: sdk.path("Account.API/1.5", "users/" + auth.user_id + "/orders/" + opt.id + ".json"), + headers: { + "x-yoox-appname": auth.appname, + "x-yoox-account-token": auth.access_token, + }, + data: JSON.stringify( opt.data ), + success: function(data){ + opt.success(data) + }, + error: opt.error, + }) + } + return account })() diff --git a/StoneIsland/platforms/ios/www/js/sdk/cart.js b/StoneIsland/platforms/ios/www/js/sdk/cart.js index a5e85089..3ff2e1d2 100644 --- a/StoneIsland/platforms/ios/www/js/sdk/cart.js +++ b/StoneIsland/platforms/ios/www/js/sdk/cart.js @@ -140,6 +140,22 @@ sdk.cart = (function(){ }) } + cart.get_card_types = function(opt){ + return $.ajax({ + method: "GET", + url: sdk.path("Cart.API/1.6", "cardTypes.json"), + headers: { + "x-yoox-appname": auth.appname, + "x-yoox-cart-token": cart.token, + }, + data: "", + success: function(data){ + opt.success(data) + }, + error: opt.error, + }) + } + // use with full CC data if not storing it in wallet cart.set_credit_card = function(opt){ return $.ajax({ diff --git a/StoneIsland/platforms/ios/www/plugins/cordova-plugin-customurlscheme/www/ios/LaunchMyApp.js b/StoneIsland/platforms/ios/www/plugins/cordova-plugin-customurlscheme/www/ios/LaunchMyApp.js new file mode 100644 index 00000000..3568c73f --- /dev/null +++ b/StoneIsland/platforms/ios/www/plugins/cordova-plugin-customurlscheme/www/ios/LaunchMyApp.js @@ -0,0 +1,11 @@ +cordova.define("cordova-plugin-customurlscheme.LaunchMyApp", function(require, exports, module) { "use strict"; + +/* + Q: Why an empty file? + A: iOS doesn't need plumbing to get the plugin to work, so.. + - Including no file would mean the import in index.html would differ per platform. + - Also, using one version and adding a userAgent check for Android feels wrong. + - And if you're not using PhoneGap Build, you could paste your handleOpenUrl JS function here. +*/ + +}); diff --git a/StoneIsland/platforms/ios/www/plugins/cordova-plugin-x-socialsharing/www/SocialSharing.js b/StoneIsland/platforms/ios/www/plugins/cordova-plugin-x-socialsharing/www/SocialSharing.js new file mode 100644 index 00000000..aa82acf6 --- /dev/null +++ b/StoneIsland/platforms/ios/www/plugins/cordova-plugin-x-socialsharing/www/SocialSharing.js @@ -0,0 +1,117 @@ +cordova.define("cordova-plugin-x-socialsharing.SocialSharing", function(require, exports, module) { var cordova = require('cordova'); + +function SocialSharing() { +} + +// Override this method (after deviceready) to set the location where you want the iPad popup arrow to appear. +// If not overridden with different values, the popup is not used. Example: +// +// window.plugins.socialsharing.iPadPopupCoordinates = function() { +// return "100,100,200,300"; +// }; +SocialSharing.prototype.iPadPopupCoordinates = function () { + // left,top,width,height + return "-1,-1,-1,-1"; +}; + +SocialSharing.prototype.setIPadPopupCoordinates = function (coords) { + // left,top,width,height + cordova.exec(function() {}, this._getErrorCallback(function() {}, "setIPadPopupCoordinates"), "SocialSharing", "setIPadPopupCoordinates", [coords]); +}; + +SocialSharing.prototype.available = function (callback) { + cordova.exec(function (avail) { + callback(avail ? true : false); + }, null, "SocialSharing", "available", []); +}; + +SocialSharing.prototype.share = function (message, subject, fileOrFileArray, url, successCallback, errorCallback) { + cordova.exec(successCallback, this._getErrorCallback(errorCallback, "share"), "SocialSharing", "share", [message, subject, this._asArray(fileOrFileArray), url]); +}; + +SocialSharing.prototype.shareViaTwitter = function (message, file /* multiple not allowed by twitter */, url, successCallback, errorCallback) { + var fileArray = this._asArray(file); + var ecb = this._getErrorCallback(errorCallback, "shareViaTwitter"); + if (fileArray.length > 1) { + ecb("shareViaTwitter supports max one file"); + } else { + cordova.exec(successCallback, ecb, "SocialSharing", "shareViaTwitter", [message, null, fileArray, url]); + } +}; + +SocialSharing.prototype.shareViaFacebook = function (message, fileOrFileArray, url, successCallback, errorCallback) { + cordova.exec(successCallback, this._getErrorCallback(errorCallback, "shareViaFacebook"), "SocialSharing", "shareViaFacebook", [message, null, this._asArray(fileOrFileArray), url]); +}; + +SocialSharing.prototype.shareViaFacebookWithPasteMessageHint = function (message, fileOrFileArray, url, pasteMessageHint, successCallback, errorCallback) { + pasteMessageHint = pasteMessageHint || "If you like you can paste a message from your clipboard"; + cordova.exec(successCallback, this._getErrorCallback(errorCallback, "shareViaFacebookWithPasteMessageHint"), "SocialSharing", "shareViaFacebookWithPasteMessageHint", [message, null, this._asArray(fileOrFileArray), url, pasteMessageHint]); +}; + +SocialSharing.prototype.shareViaWhatsApp = function (message, fileOrFileArray, url, successCallback, errorCallback) { + cordova.exec(successCallback, this._getErrorCallback(errorCallback, "shareViaWhatsApp"), "SocialSharing", "shareViaWhatsApp", [message, null, this._asArray(fileOrFileArray), url]); +}; + +SocialSharing.prototype.shareViaSMS = function (options, phonenumbers, successCallback, errorCallback) { + var opts = options; + if (typeof options == "string") { + opts = {"message":options}; // for backward compatibility as the options param used to be the message + } + cordova.exec(successCallback, this._getErrorCallback(errorCallback, "shareViaSMS"), "SocialSharing", "shareViaSMS", [opts, phonenumbers]); +}; + +SocialSharing.prototype.shareViaEmail = function (message, subject, toArray, ccArray, bccArray, fileOrFileArray, successCallback, errorCallback) { + cordova.exec(successCallback, this._getErrorCallback(errorCallback, "shareViaEmail"), "SocialSharing", "shareViaEmail", [message, subject, this._asArray(toArray), this._asArray(ccArray), this._asArray(bccArray), this._asArray(fileOrFileArray)]); +}; + +SocialSharing.prototype.canShareVia = function (via, message, subject, fileOrFileArray, url, successCallback, errorCallback) { + cordova.exec(successCallback, this._getErrorCallback(errorCallback, "canShareVia"), "SocialSharing", "canShareVia", [message, subject, this._asArray(fileOrFileArray), url, via]); +}; + +SocialSharing.prototype.canShareViaEmail = function (successCallback, errorCallback) { + cordova.exec(successCallback, this._getErrorCallback(errorCallback, "canShareViaEmail"), "SocialSharing", "canShareViaEmail", []); +}; + +SocialSharing.prototype.shareViaInstagram = function (message, fileOrFileArray, successCallback, errorCallback) { + cordova.exec(successCallback, this._getErrorCallback(errorCallback, "shareViaInstagram"), "SocialSharing", "shareViaInstagram", [message, null, this._asArray(fileOrFileArray), null]); +}; + +SocialSharing.prototype.shareVia = function (via, message, subject, fileOrFileArray, url, successCallback, errorCallback) { + cordova.exec(successCallback, this._getErrorCallback(errorCallback, "shareVia"), "SocialSharing", "shareVia", [message, subject, this._asArray(fileOrFileArray), url, via]); +}; + +SocialSharing.prototype.saveToPhotoAlbum = function (fileOrFileArray, successCallback, errorCallback) { + cordova.exec(successCallback, this._getErrorCallback(errorCallback, "saveToPhotoAlbum"), "SocialSharing", "saveToPhotoAlbum", [this._asArray(fileOrFileArray)]); +}; + +SocialSharing.prototype._asArray = function (param) { + if (param == null) { + param = []; + } else if (typeof param === 'string') { + param = new Array(param); + } + return param; +}; + +SocialSharing.prototype._getErrorCallback = function (ecb, functionName) { + if (typeof ecb === 'function') { + return ecb; + } else { + return function (result) { + console.log("The injected error callback of '" + functionName + "' received: " + JSON.stringify(result)); + } + } +}; + +SocialSharing.install = function () { + if (!window.plugins) { + window.plugins = {}; + } + + window.plugins.socialsharing = new SocialSharing(); + return window.plugins.socialsharing; +}; + +cordova.addConstructor(SocialSharing.install); + +}); |
