From c2b6fb5e14bb834a4537cede5c3c53230c1ac413 Mon Sep 17 00:00:00 2001 From: sendhilp Date: Thu, 14 Mar 2013 16:48:56 +0000 Subject: [PATCH 01/20] Cleaned up AboutViewController --- WordPress/Classes/AboutViewController.m | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/WordPress/Classes/AboutViewController.m b/WordPress/Classes/AboutViewController.m index a3049b954170..88a3eb09c280 100644 --- a/WordPress/Classes/AboutViewController.m +++ b/WordPress/Classes/AboutViewController.m @@ -10,16 +10,14 @@ #import "ReachabilityUtils.h" #import "WPWebViewController.h" -@interface AboutViewController (Private) -- (void)dismiss; -- (void)openURLWithString:(NSString *)path; -@end - @implementation AboutViewController @synthesize buttonsView; @synthesize logoView; +#define LANDSCAPE_BUTTONS_Y -20.0f +#define PORTRAIT_BUTTONS_Y 90.0f + // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. - (void)viewDidLoad { [FileLogger log:@"%@ %@", self, NSStringFromSelector(_cmd)]; @@ -28,7 +26,7 @@ - (void)viewDidLoad { self.navigationItem.title = NSLocalizedString(@"About", @"About this app (information page title)"); self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"welcome_bg_pattern.png"]]; - if( [self.navigationController.viewControllers count] == 1 ) + if([self.navigationController.viewControllers count] == 1) self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Close", @"") style:UIBarButtonItemStyleBordered target:self action:@selector(dismiss)]; } @@ -37,18 +35,17 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface return [super shouldAutorotateToInterfaceOrientation:interfaceOrientation]; } - - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { - if( IS_IPHONE ) { - if ( YES == UIInterfaceOrientationIsLandscape(toInterfaceOrientation) ) { + if(IS_IPHONE) { + if (YES == UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) { self.logoView.hidden = YES; CGRect frame = buttonsView.frame; - frame.origin.y = -20.0f; + frame.origin.y = LANDSCAPE_BUTTONS_Y; self.buttonsView.frame = frame; } else { self.logoView.hidden = NO; CGRect frame = buttonsView.frame; - frame.origin.y = 90.0f; + frame.origin.y = PORTRAIT_BUTTONS_Y; self.buttonsView.frame = frame; } } From 176698d7ac45ae9b4fafeea45abfe9e1d404cd75 Mon Sep 17 00:00:00 2001 From: sendhilp Date: Thu, 14 Mar 2013 16:48:56 +0000 Subject: [PATCH 02/20] More cleanup for AboutViewController. * Cleaned up header * Changed constants from #define to CGFloat const * Removed unnecessary delegate --- WordPress/Classes/AboutViewController.h | 10 +--------- WordPress/Classes/AboutViewController.m | 15 +++++++++++---- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/WordPress/Classes/AboutViewController.h b/WordPress/Classes/AboutViewController.h index 2ba00dab87da..1282cea3c051 100644 --- a/WordPress/Classes/AboutViewController.h +++ b/WordPress/Classes/AboutViewController.h @@ -9,13 +9,5 @@ #import #import "WordPressAppDelegate.h" -@interface AboutViewController : UIViewController - -@property (nonatomic, strong) IBOutlet UIView *logoView; -@property (nonatomic, strong) IBOutlet UIView *buttonsView; - -- (IBAction)viewTermsOfService:(id)sender; -- (IBAction)viewPrivacyPolicy:(id)sender; -- (IBAction)viewWebsite:(id)sender; - +@interface AboutViewController : UIViewController @end diff --git a/WordPress/Classes/AboutViewController.m b/WordPress/Classes/AboutViewController.m index 88a3eb09c280..e92237d36a43 100644 --- a/WordPress/Classes/AboutViewController.m +++ b/WordPress/Classes/AboutViewController.m @@ -10,13 +10,20 @@ #import "ReachabilityUtils.h" #import "WPWebViewController.h" +@interface AboutViewController() + +@property (nonatomic, strong) IBOutlet UIView *logoView; +@property (nonatomic, strong) IBOutlet UIView *buttonsView; + +@end + @implementation AboutViewController @synthesize buttonsView; @synthesize logoView; -#define LANDSCAPE_BUTTONS_Y -20.0f -#define PORTRAIT_BUTTONS_Y 90.0f +CGFloat const AboutViewLandscapeButtonsY = -20.0f; +CGFloat const AboutViewPortraitButtonsY = 90.0f; // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. - (void)viewDidLoad { @@ -40,12 +47,12 @@ - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrie if (YES == UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) { self.logoView.hidden = YES; CGRect frame = buttonsView.frame; - frame.origin.y = LANDSCAPE_BUTTONS_Y; + frame.origin.y = AboutViewLandscapeButtonsY; self.buttonsView.frame = frame; } else { self.logoView.hidden = NO; CGRect frame = buttonsView.frame; - frame.origin.y = PORTRAIT_BUTTONS_Y; + frame.origin.y = AboutViewPortraitButtonsY; self.buttonsView.frame = frame; } } From a7820742f7b55da5b927cd970acef90f7ec1bb19 Mon Sep 17 00:00:00 2001 From: koke Date: Thu, 14 Mar 2013 16:49:27 +0000 Subject: [PATCH 03/20] Minor style changes for AboutViewController --- WordPress/Classes/AboutViewController.m | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/WordPress/Classes/AboutViewController.m b/WordPress/Classes/AboutViewController.m index e92237d36a43..ca2678b2fa79 100644 --- a/WordPress/Classes/AboutViewController.m +++ b/WordPress/Classes/AboutViewController.m @@ -43,18 +43,16 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface } - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { - if(IS_IPHONE) { - if (YES == UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) { + if (IS_IPHONE) { + CGRect frame = buttonsView.frame; + if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) { self.logoView.hidden = YES; - CGRect frame = buttonsView.frame; frame.origin.y = AboutViewLandscapeButtonsY; - self.buttonsView.frame = frame; } else { self.logoView.hidden = NO; - CGRect frame = buttonsView.frame; frame.origin.y = AboutViewPortraitButtonsY; - self.buttonsView.frame = frame; } + self.buttonsView.frame = frame; } } From dd9ac7024215caea092aa7842e8eff96c5a33019 Mon Sep 17 00:00:00 2001 From: sendhilp Date: Thu, 14 Mar 2013 17:02:41 +0000 Subject: [PATCH 04/20] Cleaned up AddSiteViewController --- WordPress/Classes/AddSiteViewController.h | 4 +- WordPress/Classes/AddSiteViewController.m | 129 +++++++++++++--------- 2 files changed, 78 insertions(+), 55 deletions(-) diff --git a/WordPress/Classes/AddSiteViewController.h b/WordPress/Classes/AddSiteViewController.h index b681fdd42827..58671b1b12a1 100644 --- a/WordPress/Classes/AddSiteViewController.h +++ b/WordPress/Classes/AddSiteViewController.h @@ -8,7 +8,5 @@ #import #import "EditSiteViewController.h" -@interface AddSiteViewController : EditSiteViewController { -} - +@interface AddSiteViewController : EditSiteViewController @end diff --git a/WordPress/Classes/AddSiteViewController.m b/WordPress/Classes/AddSiteViewController.m index ae842f4df91f..b2195b5ed065 100644 --- a/WordPress/Classes/AddSiteViewController.m +++ b/WordPress/Classes/AddSiteViewController.m @@ -16,11 +16,14 @@ - (void)validationDidFail:(id)wrong; @implementation AddSiteViewController +CGFloat const AddSiteViewLogoWidth = 320.0; +CGFloat const AddSiteViewLogoHeight = 70.0f; + - (void)viewDidLoad { [super viewDidLoad]; UIImageView *logoImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"logo_wporg"]]; - logoImage.frame = CGRectMake(0.0f, 0.0f, 320.0f, 70.0f); + logoImage.frame = CGRectMake(0.0f, 0.0f, AddSiteViewLogoWidth, AddSiteViewLogoHeight); logoImage.autoresizingMask = UIViewAutoresizingFlexibleWidth; logoImage.contentMode = UIViewContentModeCenter; tableView.tableHeaderView = logoImage; @@ -35,64 +38,22 @@ - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInte return nil; } -- (void)validationSuccess:(NSString *)xmlrpc { - WordPressAppDelegate *appDelegate = [WordPressAppDelegate sharedWordPressApplicationDelegate]; - NSLog(@"hasSubsites: %@", subsites); +- (void)validationSuccess:(NSString *)xmlRpc { + WPFLog(@"hasSubsites: %@", subsites); if ([subsites count] > 0) { // If the user has entered the URL of a site they own on a MultiSite install, // assume they want to add that specific site. NSDictionary *subsite = nil; - if ([subsites count] > 1) - subsite = [[subsites filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"xmlrpc = %@", xmlrpc]] lastObject]; + if ([subsites count] > 1) { + subsite = [[subsites filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"xmlrpc = %@", xmlRpc]] lastObject]; + } if ([subsites count] > 1 && [[subsite objectForKey:@"blogid"] isEqualToString:@"1"]) { - AddUsersBlogsViewController *addUsersBlogsView = [[AddUsersBlogsViewController alloc] initWithNibName:@"AddUsersBlogsViewController" bundle:nil]; - addUsersBlogsView.isWPcom = NO; - addUsersBlogsView.usersBlogs = subsites; - addUsersBlogsView.url = xmlrpc; - addUsersBlogsView.username = self.username; - addUsersBlogsView.password = self.password; - addUsersBlogsView.geolocationEnabled = self.geolocationEnabled; - [self.navigationController pushViewController:addUsersBlogsView animated:YES]; + [self displayAddUsersBlogsForXmlRpc:xmlRpc]; } else { - NSMutableDictionary *newBlog; - if(subsite) - newBlog = [NSMutableDictionary dictionaryWithDictionary:subsite]; - else - newBlog = [NSMutableDictionary dictionaryWithDictionary:[subsites objectAtIndex:0]]; - [newBlog setObject:self.username forKey:@"username"]; - [newBlog setObject:self.password forKey:@"password"]; - [newBlog setObject:xmlrpc forKey:@"xmlrpc"]; - - self.blog = [Blog createFromDictionary:newBlog withContext:appDelegate.managedObjectContext]; - self.blog.geolocationEnabled = self.geolocationEnabled; - [self.blog dataSave]; - [SVProgressHUD showWithStatus:NSLocalizedString(@"Reading blog options", @"") maskType:SVProgressHUDMaskTypeBlack]; - [self.blog syncBlogWithSuccess:^{ - [[WordPressComApi sharedApi] syncPushNotificationInfo]; - if ([self.blog hasJetpack]) { - NSString *wpcomUsername = [[WordPressComApi sharedApi] username]; - NSString *wpcomPassword = [[WordPressComApi sharedApi] password]; - if (wpcomPassword && wpcomPassword) { - // Try with a known WordPress.com username first - [SVProgressHUD showWithStatus:NSLocalizedString(@"Connecting to Jetpack", @"") maskType:SVProgressHUDMaskTypeBlack]; - [self.blog validateJetpackUsername:wpcomUsername - password:wpcomPassword - success:^{ - [self dismiss]; - } failure:^(NSError *error) { - [self showJetpackAuthentication]; - }]; - } else { - [self showJetpackAuthentication]; - } - } else { - [self dismiss]; - } - } failure:^(NSError *error) { - [SVProgressHUD dismiss]; - }]; + [self createBlogForSubsite:subsite andXmlRpc:xmlRpc]; + [self synchronizeNewlyAddedBlog]; } } else { NSError *error = [NSError errorWithDomain:@"WordPress" code:0 userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"Sorry, you credentials were good but you don't seem to have access to any blogs", @"")}]; @@ -102,13 +63,77 @@ - (void)validationSuccess:(NSString *)xmlrpc { saveButton.enabled = YES; } +- (void)displayAddUsersBlogsForXmlRpc:(NSString *)xmlRpc +{ + AddUsersBlogsViewController *addUsersBlogsView = [[AddUsersBlogsViewController alloc] init]; + addUsersBlogsView.isWPcom = NO; + addUsersBlogsView.usersBlogs = subsites; + addUsersBlogsView.url = xmlRpc; + addUsersBlogsView.username = self.username; + addUsersBlogsView.password = self.password; + addUsersBlogsView.geolocationEnabled = self.geolocationEnabled; + [self.navigationController pushViewController:addUsersBlogsView animated:YES]; +} + +- (void)createBlogForSubsite:(NSDictionary *)subsite andXmlRpc:(NSString *)xmlrpc +{ + NSMutableDictionary *newBlog; + if(subsite != nil) + newBlog = [NSMutableDictionary dictionaryWithDictionary:subsite]; + else + newBlog = [NSMutableDictionary dictionaryWithDictionary:[subsites objectAtIndex:0]]; + [newBlog setObject:self.username forKey:@"username"]; + [newBlog setObject:self.password forKey:@"password"]; + [newBlog setObject:xmlrpc forKey:@"xmlrpc"]; + + WordPressAppDelegate *appDelegate = [WordPressAppDelegate sharedWordPressApplicationDelegate]; + self.blog = [Blog createFromDictionary:newBlog withContext:appDelegate.managedObjectContext]; + self.blog.geolocationEnabled = self.geolocationEnabled; + [self.blog dataSave]; +} + +- (void)synchronizeNewlyAddedBlog +{ + void (^successBlock)() = ^{ + [[WordPressComApi sharedApi] syncPushNotificationInfo]; + if ([self.blog hasJetpack]) { + [self connectToJetpack]; + } else { + [self dismiss]; + } + }; + void (^failureBlock)(NSError*) = ^(NSError * error) { + [SVProgressHUD dismiss]; + }; + [SVProgressHUD showWithStatus:NSLocalizedString(@"Reading blog options", @"") maskType:SVProgressHUDMaskTypeBlack]; + [self.blog syncBlogWithSuccess:successBlock failure:failureBlock]; +} + +- (void)connectToJetpack +{ + NSString *wpcomUsername = [[WordPressComApi sharedApi] username]; + NSString *wpcomPassword = [[WordPressComApi sharedApi] password]; + if (wpcomPassword && wpcomPassword) { + // Try with a known WordPress.com username first + [SVProgressHUD showWithStatus:NSLocalizedString(@"Connecting to Jetpack", @"") maskType:SVProgressHUDMaskTypeBlack]; + [self.blog validateJetpackUsername:wpcomUsername + password:wpcomPassword + success:^{ [self dismiss]; } + failure:^(NSError *error) { [self showJetpackAuthentication]; } + ]; + } else { + [self showJetpackAuthentication]; + } +} + - (void)dismiss { [SVProgressHUD dismiss]; if (IS_IPAD) { [self dismissModalViewControllerAnimated:YES]; } - else + else { [self.navigationController popToRootViewControllerAnimated:YES]; + } [[NSNotificationCenter defaultCenter] postNotificationName:@"BlogsRefreshNotification" object:nil]; } From ede03441e7ddae00566965d1017fa842d5b49442 Mon Sep 17 00:00:00 2001 From: sendhilp Date: Thu, 14 Mar 2013 17:02:41 +0000 Subject: [PATCH 05/20] Updating AddSiteViewController as per kokejb's suggestions. --- WordPress/Classes/AddSiteViewController.m | 29 ++++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/WordPress/Classes/AddSiteViewController.m b/WordPress/Classes/AddSiteViewController.m index b2195b5ed065..7d2a9ce2e9db 100644 --- a/WordPress/Classes/AddSiteViewController.m +++ b/WordPress/Classes/AddSiteViewController.m @@ -16,14 +16,13 @@ - (void)validationDidFail:(id)wrong; @implementation AddSiteViewController -CGFloat const AddSiteViewLogoWidth = 320.0; -CGFloat const AddSiteViewLogoHeight = 70.0f; +CGSize const AddSiteLogoSize = { 320.0, 70.0 }; - (void)viewDidLoad { [super viewDidLoad]; UIImageView *logoImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"logo_wporg"]]; - logoImage.frame = CGRectMake(0.0f, 0.0f, AddSiteViewLogoWidth, AddSiteViewLogoHeight); + logoImage.frame = CGRectMake(0.0f, 0.0f, AddSiteLogoSize.width, AddSiteLogoSize.height); logoImage.autoresizingMask = UIViewAutoresizingFlexibleWidth; logoImage.contentMode = UIViewContentModeCenter; tableView.tableHeaderView = logoImage; @@ -48,11 +47,15 @@ - (void)validationSuccess:(NSString *)xmlRpc { if ([subsites count] > 1) { subsite = [[subsites filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"xmlrpc = %@", xmlRpc]] lastObject]; } + + if (subsite == nil) { + subsite = [subsites objectAtIndex:0]; + } if ([subsites count] > 1 && [[subsite objectForKey:@"blogid"] isEqualToString:@"1"]) { [self displayAddUsersBlogsForXmlRpc:xmlRpc]; } else { - [self createBlogForSubsite:subsite andXmlRpc:xmlRpc]; + [self createBlogWithXmlRpc:xmlRpc andBlogDetails:subsite]; [self synchronizeNewlyAddedBlog]; } } else { @@ -75,16 +78,14 @@ - (void)displayAddUsersBlogsForXmlRpc:(NSString *)xmlRpc [self.navigationController pushViewController:addUsersBlogsView animated:YES]; } -- (void)createBlogForSubsite:(NSDictionary *)subsite andXmlRpc:(NSString *)xmlrpc +- (void)createBlogWithXmlRpc:(NSString *)xmlRpc andBlogDetails:(NSDictionary *)blogDetails { - NSMutableDictionary *newBlog; - if(subsite != nil) - newBlog = [NSMutableDictionary dictionaryWithDictionary:subsite]; - else - newBlog = [NSMutableDictionary dictionaryWithDictionary:[subsites objectAtIndex:0]]; + NSAssert(blogDetails != nil, nil); + + NSMutableDictionary *newBlog = [NSMutableDictionary dictionaryWithDictionary:blogDetails]; [newBlog setObject:self.username forKey:@"username"]; [newBlog setObject:self.password forKey:@"password"]; - [newBlog setObject:xmlrpc forKey:@"xmlrpc"]; + [newBlog setObject:xmlRpc forKey:@"xmlrpc"]; WordPressAppDelegate *appDelegate = [WordPressAppDelegate sharedWordPressApplicationDelegate]; self.blog = [Blog createFromDictionary:newBlog withContext:appDelegate.managedObjectContext]; @@ -111,9 +112,9 @@ - (void)synchronizeNewlyAddedBlog - (void)connectToJetpack { - NSString *wpcomUsername = [[WordPressComApi sharedApi] username]; - NSString *wpcomPassword = [[WordPressComApi sharedApi] password]; - if (wpcomPassword && wpcomPassword) { + NSString *wpcomUsername = [WordPressComApi sharedApi].username; + NSString *wpcomPassword = [WordPressComApi sharedApi].password; + if ((wpcomUsername != nil) && (wpcomPassword != nil)) { // Try with a known WordPress.com username first [SVProgressHUD showWithStatus:NSLocalizedString(@"Connecting to Jetpack", @"") maskType:SVProgressHUDMaskTypeBlack]; [self.blog validateJetpackUsername:wpcomUsername From 4f40f39e8e4c7a7a7088e8853a92124f2d69d7b0 Mon Sep 17 00:00:00 2001 From: Jorge Bernal Date: Tue, 19 Mar 2013 17:49:56 +0100 Subject: [PATCH 06/20] Don't always show friend finder on debug builds It was helpful while developing it, but now it's mostly annoying --- WordPress/Classes/WPReaderViewController.m | 4 ---- 1 file changed, 4 deletions(-) diff --git a/WordPress/Classes/WPReaderViewController.m b/WordPress/Classes/WPReaderViewController.m index 46a196b30adc..676a48fb47d7 100644 --- a/WordPress/Classes/WPReaderViewController.m +++ b/WordPress/Classes/WPReaderViewController.m @@ -523,10 +523,6 @@ - (void)webViewDidFinishLoad:(UIWebView *)aWebView { - (BOOL) shouldDisplayfriendFinderNudgeView { - #ifdef DEBUG - return self.friendFinderNudgeView == nil; - #endif - NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; return ![userDefaults boolForKey:WPReaderViewControllerDisplayedFriendFinder] && self.friendFinderNudgeView == nil; } From 2f7f9e1023a1344a4add835bba85ad53764d8060 Mon Sep 17 00:00:00 2001 From: Jorge Bernal Date: Tue, 19 Mar 2013 18:41:24 +0100 Subject: [PATCH 07/20] Updated README.md Added more formatting and links to trac and style guide --- README.md | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e20e442123b5..5a4b21e02fe5 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,34 @@ WordPress for iOS -Resources ---------------------------------------------------------------- -Developer blog: +## Resources + +### Developer blog + http://dev.ios.wordpress.org/ -Source code: -http://ios.trac.wordpress.org/ -http://ios.svn.wordpress.org/ +### Style guide + +https://github.com/wordpress-mobile/WordPress-iOS/wiki/WordPress-for-iOS-Style-Guide + +### To report an issue + +http://ios.trac.wordpress.org/newticket + +You'll need a WordPress.org account. If you don't have one you can +register here: + +http://wordpress.org/support/register.php + +### Source Code + +SVN: http://ios.svn.wordpress.org/ + +SVN browser: http://ios.trac.wordpress.org/browser + +Github mirror: https://github.com/wordpress-mobile/WordPress-iOS/ +## Building -Building ---------------------------------------------------------------- Starting with changeset 3633 version 3.2, WordPress for iOS uses Cocoapods (http://cocoapods.org/) to manage third party libraries. Trying to build the project by itself (WordPress.xcproj) after launching will result in an error, as the resources managed by cocoapods are not included. Instead, launch the workspace by either double clicking on WordPress.xcworkspace file, or launch Xcode and choose File > Open and browse to WordPress.xcworkspace. From b8254607089ef4c7c60e5f7d4b076a59d91c725d Mon Sep 17 00:00:00 2001 From: Jorge Bernal Date: Mon, 25 Mar 2013 13:06:03 +0100 Subject: [PATCH 08/20] Use right page_id attribute to find pages We were using "postid", but wp.getPages uses "page_id" That means pageID was always nil on `+ [Page findOrCreateWithBlog:andPageID:]`, and pages were recreated on every sync refs #1578 --- WordPress/Classes/Blog.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Classes/Blog.m b/WordPress/Classes/Blog.m index 6d982762591b..9daef8001d5a 100644 --- a/WordPress/Classes/Blog.m +++ b/WordPress/Classes/Blog.m @@ -910,7 +910,7 @@ - (void)mergePages:(NSArray *)newPages { NSMutableArray *pagesToKeep = [NSMutableArray array]; for (NSDictionary *pageInfo in newPages) { - NSNumber *pageID = [[pageInfo objectForKey:@"postid"] numericValue]; + NSNumber *pageID = [[pageInfo objectForKey:@"page_id"] numericValue]; Page *newPage = [Page findOrCreateWithBlog:self andPageID:pageID]; if (newPage.remoteStatus == AbstractPostRemoteStatusSync) { [newPage updateFromDictionary:pageInfo]; From 45884610c93025f522dcea7867ad26cb7dcfee7c Mon Sep 17 00:00:00 2001 From: Jorge Bernal Date: Mon, 25 Mar 2013 13:08:17 +0100 Subject: [PATCH 09/20] Disable remote autosaving We're disabling this until it's more stable --- WordPress/Classes/EditPostViewController.m | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/WordPress/Classes/EditPostViewController.m b/WordPress/Classes/EditPostViewController.m index dfc6a734fff5..6564a7288a24 100644 --- a/WordPress/Classes/EditPostViewController.m +++ b/WordPress/Classes/EditPostViewController.m @@ -63,6 +63,8 @@ @implementation EditPostViewController { AbstractPost *_backupPost; } +#define USE_AUTOSAVES 0 + #pragma mark - #pragma mark LifeCycle Methods @@ -78,8 +80,10 @@ - (id)initWithPost:(AbstractPost *)aPost { self.editMode = EditPostViewControllerModeNewPost; } else { self.editMode = EditPostViewControllerModeEditPost; +#if USE_AUTOSAVES _backupPost = [NSEntityDescription insertNewObjectForEntityForName:[[aPost entity] name] inManagedObjectContext:[aPost managedObjectContext]]; [_backupPost cloneFrom:aPost]; +#endif } } @@ -398,7 +402,9 @@ - (void)restoreBackupPost:(BOOL)upload { } - (void)dismissEditView { +#if USE_AUTOSAVES [self deleteBackupPost]; +#endif [self dismissModalViewControllerAnimated:YES]; [[NSNotificationCenter defaultCenter] removeObserver:self]; @@ -565,9 +571,11 @@ - (IBAction)showAddNewCategoryView:(id)sender } - (void)discard { +#if USE_AUTOSAVES if (self.editMode == EditPostViewControllerModeEditPost) { [self restoreBackupPost:NO]; } +#endif [self.apost.original deleteRevision]; //remove the original post in case of local draft unsaved @@ -635,7 +643,11 @@ - (void)autosaveContent { } - (BOOL)canAutosaveRemotely { +#if USE_AUTOSAVES return ((![self.apost.original hasRemote] || [self.apost.original.status isEqualToString:@"draft"]) && self.apost.blog.reachable); +#else + return NO; +#endif } - (BOOL)autosaveRemote { @@ -782,7 +794,9 @@ - (IBAction)cancelView:(id)sender { [titleTextField resignFirstResponder]; [tagsTextField resignFirstResponder]; [self.postSettingsViewController endEditingAction:nil]; +#if USE_AUTOSAVES [self restoreBackupPost:YES]; +#endif if (!self.hasChanges) { [self discard]; return; From e889f982fa3bbb2b80e568c0bfd6aece215e6f64 Mon Sep 17 00:00:00 2001 From: Jorge Bernal Date: Mon, 25 Mar 2013 13:26:05 +0100 Subject: [PATCH 10/20] Fixed orientation bug on iOS5. fixes #1582 --- WordPress/Classes/UINavigationController+Rotation.m | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/WordPress/Classes/UINavigationController+Rotation.m b/WordPress/Classes/UINavigationController+Rotation.m index dcf02b3510d0..74eba0d902b2 100644 --- a/WordPress/Classes/UINavigationController+Rotation.m +++ b/WordPress/Classes/UINavigationController+Rotation.m @@ -25,11 +25,18 @@ - (NSUInteger)mySupportedInterfaceOrientations { return UIInterfaceOrientationMaskAll; } +- (BOOL)myShouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { + return ([self mySupportedInterfaceOrientations] & toInterfaceOrientation) ? YES : NO; +} + (void)load { Method origMethod = class_getInstanceMethod(self, @selector(supportedInterfaceOrientations)); Method newMethod = class_getInstanceMethod(self, @selector(mySupportedInterfaceOrientations)); method_exchangeImplementations(origMethod, newMethod); + + origMethod = class_getInstanceMethod(self, @selector(shouldAutorotateToInterfaceOrientation:)); + newMethod = class_getInstanceMethod(self, @selector(myShouldAutorotateToInterfaceOrientation:)); + method_exchangeImplementations(origMethod, newMethod); } From cffd95823b723d4ec1551eadbca1265d1244216b Mon Sep 17 00:00:00 2001 From: Jorge Bernal Date: Mon, 25 Mar 2013 14:21:42 +0100 Subject: [PATCH 11/20] Updated translations --- .../Resources/de.lproj/Localizable.strings | Bin 69918 -> 67634 bytes .../Resources/en.lproj/Localizable.strings | Bin 79468 -> 75534 bytes .../Resources/es.lproj/Localizable.strings | Bin 67736 -> 65550 bytes .../Resources/fr.lproj/Localizable.strings | Bin 69362 -> 67140 bytes .../Resources/he.lproj/Localizable.strings | Bin 63362 -> 61670 bytes .../Resources/hr.lproj/Localizable.strings | Bin 68612 -> 66404 bytes .../Resources/hu.lproj/Localizable.strings | Bin 69158 -> 66836 bytes .../Resources/id.lproj/Localizable.strings | Bin 68020 -> 65850 bytes .../Resources/it.lproj/Localizable.strings | Bin 69742 -> 67396 bytes .../Resources/ja.lproj/Localizable.strings | Bin 60076 -> 58726 bytes .../Resources/nb.lproj/Localizable.strings | Bin 67994 -> 65826 bytes .../Resources/nl.lproj/Localizable.strings | Bin 68860 -> 66916 bytes .../Resources/pl.lproj/Localizable.strings | Bin 68360 -> 66206 bytes .../Resources/pt.lproj/Localizable.strings | Bin 68528 -> 66346 bytes .../Resources/sv.lproj/Localizable.strings | Bin 68136 -> 65958 bytes .../Resources/tr.lproj/Localizable.strings | Bin 67670 -> 65538 bytes .../zh-Hans.lproj/Localizable.strings | Bin 61070 -> 57600 bytes .../zh-Hant.lproj/Localizable.strings | Bin 58828 -> 57372 bytes 18 files changed, 0 insertions(+), 0 deletions(-) diff --git a/WordPress/Resources/de.lproj/Localizable.strings b/WordPress/Resources/de.lproj/Localizable.strings index 18bfd29d9ca6a6ec26738e813132a649da3bba0e..fd9133aa6e82b7a81516e59855eb29e2a05e4718 100644 GIT binary patch delta 1726 zcmdT^Sx8h-7(RD4<)(MWahuVWJ7OsnrnJy%NaGEdaT$ zWNicyCa@N^g_UXFNZMME4$=$FCJNS0_P_Mwd&g&5@YW^c_@IKsJcqOd2L=oAZC(K7 zs)-*d+Al$w?BHLDFBrJD^tKFTb_U|Jav)d9d}!uPGY`zK%j6rEzcygF#)hf)9GD-K zF;t^!=i6Hv`B2S(1%3A?;+n^X*DDlhG5lU9RL|-ZX_mAW<#jf^DRv;}RWem-Rwv~j z61Cup*@t+&y|=zh;=>I#8O?6{?j2;%P33h^BVuHh+8C8}X^m3JDok1dr?MYj5jrL3 zQ%2_>!P;3wn`akuvGru_p%%7lUZRyM+eY^&#nVtQEv`)(YZ3(&%@j#YdmHJZ^jGN~ zA}kR@Wac5MU`iLA1qWKOp=Cm5S(0t^Uxg-j?*CsCyaVeHZ!+=C{`W>y-pIqLS8|%0 zS`wi(S#ZONrItpkn?^!wqctPQg1DE+cc#clH!>hdhkg80TSIzwfT%o5^jf+F&=c}i z2)WAYsjpF*P>{}(Syif~-U1JfG+ArOUWbNii;u4g-ATjcsDe+sGH|L}ky`Q2;lrWr z3NMNcnt9*O0t3Ia+hD8l)9xo1EXgFnv9Okd;98dsy^f0gtp_?=S`hEaIoE$wHfvm_ z_rwX?PC3m(Uc_zfZaUmJW8_Y;lRO(+X^LLd$*-TR9G5R%gRm|kkM=%<@$94z;q&R- zaQ;I+f7@Sf)B;W2}?gB%5GM`}DV$s*-qdQidT=NU$#G@ebFgyydW zSzcOl&+gy?@HT^xw`>D2}~J_Bgg^@BMvqklgt@l-PV>-*R`X)>liu^ zABa%`!k3uf12Ra6Su`?^@ee_SCCZ{hfftcK6VwOyf-WS)kUjYO&Rv1Q;)5~42eaJu z-0ytn`}_NT=N@}I{lKC0qYjOZXrIw-m&+X!QK5^t2#L+2Lxj~TNF#?lbmFj$t{Gl> z=ly!xtxc8<2V=+K^zWal@v`Pf)&39u{Q7&iz2+0<0%r)VmBsQux720 z*oY?%tq>#~INu^hv14GbMah;c8zB|kR^@F}1Vk&1G^~@`+zT!8SIWQ4fXc9jc9i-aS%FL=A_3VZ>?G*- zo2_zM#SJT!);X!Z(q&Ph%CDb0HF?=u=(fW+J7j!xsyam#iV~1DAq=*oqiftxUCb6M zAvbWU2|KM~HZ7^~6@-<46UtrCWOSk@NQ@CtOnpdg==rLD%U}NA`eTglt94~^m}9j? z8TwZEEb}PVlfag2UsG(MQ#DREgD0*6<=__~=viVZ>t@ay!vrT0qYr%nd7##5pTZMV ziAIbZO2{hztu#v|wFNvB*<#DDhOJF1aVU%xtPN%27-FX$~a&L&Hv15@bs7KhxO z?4JbuD71<=Rd>&zs{M9~yyBqMmvb{hCM;mInXXUXK+dgMvgXxXD}8XuOIOY~$)0p5 z<$c$^bhO*9>7oYS68P&>%`(Iy+8bX-e{6Ngm$zA+^3gp`yKH!OafWmp8TF8HelAs= z$t~a*yO0)xz$BA#z@pQ=nr4ED8?GZC238xzx*sR+h>Moqv{9rocd8DrLF~loy;AoA zuA2#@HgOB2!n9*ri6cHvjseENx&v3r{Bl+{N5M44drVA0`sh?1-RjcSCi9C zErwh|!NwSOr!R+`;r@d9HL1+BWZaQO!NPN81t#Hy zmBSiX!4->BeASsGa(y_Dt{v7hdE{aUh41<}t@*`Ijo&(G+n}9Je(#he-@R_7_6s&? zy^xjeNzK6B@1C_d-9i4Ve!2c)u65M}9}WnU2P=Wn>Y^I!R+R!5oVD+cQ?t4vdES{5 z@WF9e!=g+)C;$Ke diff --git a/WordPress/Resources/en.lproj/Localizable.strings b/WordPress/Resources/en.lproj/Localizable.strings index 09a875790802ae4859df355be95eee4466ae877f..4db406b4ca7120cedae1b63aa19a9b96326e0600 100644 GIT binary patch delta 1429 zcmd5*UrbYH6#qWFmhw?>J z1-n#UjgP{GMlyrz_+;<8r75F(H4mUatYy{F-Xipb=;vZ49>e8fGlO_Y!@khBG8x{c zq9x)l?qVIRhn8!S(Ln_|J4nU7WcSf-4iGidN9~zCscq>LkD@AQM@3S2b)v%@(@vC` zB=)dk)=YjQb!sQ8la1i!*>X%=5r}!5L~tARF-h%1ah)r>k*Xe666I78#IJp;sw$Qc z?j!7TcS39()#UNsjTY3}oUmC1W)F+h_n(JV(*5?AcF>|o)wBXr<(*_7Yq@91&n<(( z8JA1i`rpkM9#rsRZvnmsTP% z=0oCro76rW=TDp?BNcY&pZgL2OmPq)M9tIF=(OA@ru!VL8tAmGbQ_mPyfu)I?;BsgPT7|DqtL6v^-ufodKBENg-^Iz}UP z=4CZY7STwfNoh1bmB-u19J1)k<2JL<)j?;9{sWwf;1}_loVj*3Px|LhrQ_-yP3GLu z6?yNsj}=TTM(OgXa%}MkN98Sl*8Y^nACZ6`k9rL?om6z@bS4yV`0*OL@+@GTy2F4F^Z7mH+?% delta 3570 zcmd^CZERCz6n^jMwytYS*YB?TxZN0|fP87fm;)xrkIl*|j)}Utb+lu3tSxP!8zET0 z#DtKkJG%QroMQYZfx$Hl)Zie*9~cq-7-N&Qk7kYHk(d++;k z-gC}-&Uv2qZO19a<;#kmHw;i~)I*tZiIA7V<(WJz!de*5nplv9@w*ZGKG@b}hxLYO zrXUO8SeW_P2AuIrEiWuGIx~~Tgk$Mkop{3NP^gpeLwS} z9xt||_{?Di*jtQG0UMRJOd<_gt+}98=ZJ2zJ4HNYJE0)Qt?*f?vMPoSk&Ek4)wB3> z;dd=M8%8sJ+>#%AWYUKwc{Y>HWhyked_oBxw>{rzuuVR@zsv*WyaLYUY2mk^85H>i z(zo$lqv+1Rm?mDGKEUPj=uZ%B%3+J5FMhPQ2_K$CU_*leb~;ssca@TY6crp=?nU^n zSOp=cveT&(2WPaU2+K5_(ay6PX%F%qeHhr$fC@`BoJBKEK+aF?td$DrTj0VtM=&Uj zm=$t~va=q)0k{?~gyFf`%;YgHS`6ilCF1vU*C?UkaaUn03!!)IxL`F~h4CJ>%T}sWOq%jJuwm%N;n(S!m~){J?5W|wJJ47VD=5iCypM%ip^d+-TiKZL~{ zlKKROh_H?4Z1BU6=2TqF{BXY7y*#mCLKqd2+cCZP1ot*!G|} z;S3Rs?J$~Z#$E#1#jFy?qqxe0GcBwbZr9oJ{gQt&&f8JXMk%fl+@S;;c%t48-F2=9 zWzT*WdvN}29W*rPq2Ra`T=hCAJ)TF5B8?5#YvIXyE8MIpcu_d9uY_o+eF(3zrddRKT7`4dC9c0(Z9BK01mj$EsTz z1+Kva<(1RK!yEKzTm^g?bK?8=SfO~ZZD)q$R?ZH7N)>wwUfEtObZ{Kj^!Bh=wxc8y z-hWdqroDbN6*_!sxcRGjQs&LgoFP#c<<$#k6n4%Ddphkf?`JavhRv|KR|T^{o9GKQ z8g7lKeftwGvjW#WxRQV5Uza=@^+Ir~34Tgf!@f=}1iGv+Sgqqq!2z~J54t;Qp{G+V z^1>X$!H)(q;iW@7qRa^1pbm-D3g-^Z8_CiQIQpqhtU1!A7R$f5Y&A?k>acXHWieHH zSRz+qg9J8{KqC?V^HN>&NKk%Ec(YXTh#NR|C4VYWK#~^W+BDA48bYN66`uqsiGHNO z2JuaR<5>=mrN(l39)U-sAVZC?y^+#}62vJ4{V`C{Y(Pq_SJF(xhWrTEVm2FrS3Wan z6D{a=Ez05po-0L*=oF!YnIsaVGeJls&xi!t(JK$Wm%{u(!~Z;Z3-2*_;AuC2?z~%^ zeYPtdUg)c$jtdr8)1Q6M>knM;iG70$ z6!5{!JYk-V)4@Qs)j{P}z|ywl}?Z~Arc;mn--Qxk*u zkQ(|feJt+1baBe8aR5Sp2$G2dT1JO_)j&MKfs+>aBWMJDjUKKJJ$4^!&A^|m5#vMp zl#xq>R=j?Fl>*{LS_p&jxx3#7Cnk%rJ7V=H;>OMZX$(BC)q(DYPVD~k;uOdkQZ7%r z-eFk~j3W~3JdN!Z3b42x8vNh0rB^9b+PEC*1%z8>P7m?pDq*jc(+j6fTsHN3vDc{m E2adjdN&o-= diff --git a/WordPress/Resources/es.lproj/Localizable.strings b/WordPress/Resources/es.lproj/Localizable.strings index a3d69c9febeef0c142a83ee0dbee35293f999cb9..684eaa57308fa7f1f362ed077177994591c1d3cc 100644 GIT binary patch delta 1658 zcmdT^T}YE*6n?*L>ROg-b8~B3&YD zJ5>F*bx>qx;)+g(;4Tk3baDPwUnp?3u~0DNu{LIBrwC0#fU z7bo?(1*{%kNh#!cwiZ4!#HC2qk)NsvFw=@KyPP~(I{%MUtkDPY~G z;dk?{YWRcgFH?BYo`O|ecW73D&QdL`k4%`J)8KrmUHZOpxPf<;Hl*Ovt93#ccS>x+ zeng$2qb**P}F~P_g=ps9Ov3vl?or@MtDwY z(#q)mF=G5f+>Fb?8hsftOJhydi(}qIYaIlm-n@)m;x2@-d^f*e|0Wf0bzby`Q~CRo zYC#_)Nh}S2Iqia2BOKcyeNon<#Ah4zMm!;x9rzh5N5Gd;n^8`9Sw370x^bZ?mCrVM z(=d8!wQaA=?WD`M((jB^oS*H5uRX-8TH`5v=4`rx51lW~F#AZti+Wm|BXPo7u-&wA7tw-_-!t4VWF%<06VfQkGXJn2#A`l*)0bS2lhfTdfI zAGJ9?cyDRB|K^}3OB8yGtR9yn{T7V%y3y6A=Ii>#jeO{Fx{`N2jVZbDMNEw=BU(Hh zPUV}2ixlPtN+9ZKsjkF6f`PCZGw;%sG}q!&g|2z4rHcIvJ`?w5s<~%$ttw9xp(w~i zQo=vUa{GrWx|iv2O642g=B w?hW!>@=24~#hK%uC#(t{ncS|_H!rUgn|Re_d`oIU$CQfqO?wS|c<#0SJGCpHTL1t6 delta 2811 zcmeHJUu=_A9KG$jtu$RJ{b21_XS?Ab1f9$fKn%#Nz(6;KAeq@vy0whT)|Ixi3?D4S zC?X-?F@*T%VaY;_7$n{YCnB;a2uLCU48|u*e1Vi0UU)>$@B5qsTzoJl^5DZ=?|1L- z{_eTwch0@rn|B=C?>KtUhewTJgpI)Lw2G^(YCt8F^kS+`h1FuVI@QYWZng~PvMQ=O zjKj7$VKXet1!SZs+r7`xo01J-Q;K5sgN!EA2${^J2$NDAh`u5a? zHXZZ-QWA+XPnPR8v2~m4;>;kUY1Pj*4ku!cP7sTlc~LB{_QBp!3Hx(CG!$OPv7kr$ zg7ZuD?b#$X4xwvSlKf8->xn zJ9cibtX^+|u;AX!Rs=ULRTTU{=k zb*md_dZGi##yWj{?uVtw&vO~$WC}2$w+H)c4Ww$Fc*bx~zH>gQVyL}jVBfNKy>I^9 ziYWp?*puSPiQ6!`yb3QADldD8Du=J8W3vf`M36}`P;o5(k3_p zM$@wf4qf$3GlL2GuH)g?H>0|&t=VPk!JH3ry4dM(*jD1^#@g}%GteCPKGLV_y3Uuq zy~~N%<`kT}+(;*`>(g6e<@#vmOzEUJX%QOISaWFxt`}TWR+=MXff%Wx3sK-qXQ3TS zavr^H&~3+&6#+a|^kQMgjgcRHxUjtp_B0)k@5IuaTfg?os>wS4*7`}FpRTOS@7o$X&n1%wGF!zOi4 z5FTp^TiTD^*QVovbFRkBA2q&5YdjwPuNoL1Vb8M2fV!r-u%h`5gpWJ5Z^T_f|NP}b zz>c_ou}Cd#8dhYJu$U!B<4%y&&olJ^fBP8GLs5$4cr+Y76?!$w{@q!!j1Yf~AR^9%w$h z>p|Wq%ecIPF?890=c4ES!*#L$KfzRMSXb@+!_tI^^w7nj5;(5}u=I#iJFYC9hRcPp Q&HR@P+2T9;sp2`~cLoBqa{vGU diff --git a/WordPress/Resources/fr.lproj/Localizable.strings b/WordPress/Resources/fr.lproj/Localizable.strings index 8fb3a5bf6afbe831f40146902115a8314e50d6fc..baf680b01c7885c65ae4f2e5d17dbf14ef28e445 100644 GIT binary patch delta 1693 zcmdT^TSyd97(TnM>p0muHm-JAZPqj^EQumasHB^%7MZKDsc5^dW~u9@V>hIH>M54! zgOcb1^%A{koi30S1`-5C5*idnH|ZfFD54@F`p?wjxLxSAhv7f}_00eM-+$hpv<)7z z^}U*cE0qq^rrL2+m7%B->;*OGRx^>QCgH0`I-(xrYg1=ixG!z3#hJ@=rm&2Dp1?BsQ`()=oY@-2F4>2gu*Xwy`X-ETb=rt)kcv`^S7J_N}}peJn1gi8Zi# z)=Za$sGP>4*OZW5XJINzURQL{@&}JTnEi%!>J6Jzi~z4G3u6aV!(lO&m1W8 z$jCb*qi0}>q3`kd&^Ob@_hofkP@5y+ZMMRPv%9R^I_H$k^A^2`=R->iCi82>V^-WP zRZ!MH6_JlJu9s@YxniylLmnGnP+Dk5#l1`%EmyF^RV|TeU*g$LCH9u z2>R3w1S_%MXt{-e&{zPQ($wS_J5KjD@DITykH8yr~}EEwAP)Tc0IhdWR#iFzSL|S1pC&BCd7X?cCbsvU10PK=L#{ zEpT+Nq6;fn62_($XGS@-_UDM5fqE3d#>0_FV!S~=dIhGXjQ@_8l8KbUit}%M`9F2K zGD@L|EynmogXr#2cv4Tvq;#?W;b=o7y~c|W#?G_#y!PzvbpHB!VH~~=&OzAzwWHEW*zF56sg2g;tIu{Upt)`A+@_&tn|4Vi8 zuTjw#aUu27{?~e@NTfunXPIl6d1kU3jQjQ|&x(1^yD-!*VfoWkKJWPZEEc~KNbc=xCRV&`KO_<9_ zkj~6ay3N`_lwJvo5Wgav^m0h_2#;u|74KVV9TgsUF6BM#p*@>sjSkT#epcsx5mEmg zBoC2H+lNRaMDk@@e$=gNk`>k(o&3mtEw0K>wxZBPyH27_&LxN@*sYRO!t<9xursU^h4ye9#4HQG~F zoMUI80TqSGa(dGVQ({nblFvS*9LU%8ApP|g{9fY1m2wldZ*`%xv|ipVDUXMFn<;;} zpd2Q*>oA4AS0&O(p;OwJD79PG(8K!O0lEFjvXpe6sxW8eBO^}XM#r-bj4x&O`w9B$gG6L_Xuq_?i#Waq|J zk@7N7_EE-%5p=i6`sQEabXDl^+EJ8fOsZBzV}PftT_w^jiycthu1;URG>lnc?TB8jJP~we4ti4;GQzdb(3Xr z79TlWHGy!m!@h&j8dlSQ>&6vaJr#>c@}k0~lR^#<0oy16l`6U}TTtvu9^hHI(h{f0 zl#SW!Brl97?nWzF(TE%+yRo9>5`=yb$Hbt>BN?wgBpW;}nMYjCZsHmOA-&G$xBgBe|ysvv)RbLapy zFmT0cT~qJ>qTYW|ufE+R-BY7+a8G7E#eL*v_fprmFIx4T)GNNcUm_4_<6P5Xa77eA zqBwTZikivne_5A8szZ&DZQNgZp5mq gq)$96-MuDkxs`$8CR0rE(+jwDQ%PjouM3%f0ISI2aR2}S diff --git a/WordPress/Resources/he.lproj/Localizable.strings b/WordPress/Resources/he.lproj/Localizable.strings index 5ebe057dfcf1c5d42b6e40af39447b3fa80dae5e..18fed8d8355484ed1341c5673440562c9cf44e88 100644 GIT binary patch delta 2046 zcmcgtUrbw77(cg{(?Kas*RBDJTko2n8Oab9G9A$ffk86qR-{{S1=a%nw~pJ|R;G#B zR)dSmTu46S=7_rK;=?wba27RjBS6gL!MS3Xf|AM>qMHw*#wQ;ZzjNWbwkp{YW18D@ z&pE&E|L^wuv7IGb2w7c38w1d&J|@sfQc zM0#*d5FZpZl@|C(gv9X93*K!Om_MuA*oBw~2@pG;K8BB-)FWOd_n?C+I-sT64V4xx zTdaFqGx;SCpGX{qY?f% zTLQNiba0_jQr`Qowy_J1Q7Sf&2%I;R+PFt?^qnViA9|J@$>Z>LbKtJANk<4w_7XVL zY%HqBl*{4ld9>hQ1TzswTfB5(L`dX0L_dRT5dG*=PO|-w5YIC# zAu5XhT(>I4i>;Qp0^gS`2ap7u6mhbiv?IC|Z3PsmkcPL78%+`Y(clk)53^xch6tJdZ6n zjg2>lO*l<|!gfqS($v95+Ybvu2)1_GEDj7grX+}SXo=CiQ042cb6}OQ9hGz~u}ZB^ zJR@lzUl^r|f9l zDZu7&4}AEvf$91lFu*UaHJHH&i9#}I5ud~vwdk@epPWy2gXiTuR@pzO73b*<7_RM5 z4$21(2(a!*zR(TVXKjV8e>DZ)7lUh{b7K#BzQon+s8np$J+utCVeC}{`{+ouu9#1u zs2T;Xt;$@ADxmgb`RupXZ)@PuQByG=z*9JSr;!EU;`p5RFX)`dl^Sm3p2y~7e*0Vd3l~&p<+h2)`g?u-lX0+y_?AsheZ4o zU8CR7ANi+fgA17&LyAa5Ax=hCa&F+%Y4?t7Y&N+b!6NnkyL=AO6g1b_l&e$yGE`xJ zu@&`YA-S&gcXVYEI3p5;%BjmWns;MY#I3z|)uz0IRzO1Cl$%9Um(A?wh1X1f0s|%< Apa1{> delta 3012 zcmd5;TTE0}6g|UmP+&l0l$TI0K5A<$DXpDSm7qGpMD;T9`JohTKn>HP2|RAO&?#Skvx zzd=7EtZK6zPoAagf%=)(1)yn(wOc|l&1oirVHX$Y_E#k-f}MG7V@iF6=hh2Fc8GV&8s z(*^(apUcaU@;3JR1AAYg&lZ%a?McZ}IgJl3^w5YHWuC-^91h^;o$54hx2U5((^A5F zq#rqMN`uaSTcg_3T0`iyk#QNh2<4X;Bp0B6OP|zR;gG*$+ko_H0GB8jSEx$H{uMr? zM$}@51{$A}YVF49H*F|XIqBa?YRVWo(il)gE+Ch+k}QUu0;xk2xnP~rBYnv1#TBgr zxL$xeF|SfRc>SntSQ)zI!XH=0EeuMm9yiPoegrd^YX}d}g6YL-f9BZ`nvjzmZa(Uj zx9PXSV%nP-O0`+Zsw6u{HZDT-Yf+J9$X1QKYj9r*K-}Lttd(M)GO--rD)g>~7%%2x z-Ho?Ob!W!o8S}^FhgsQb-x6-Aq#g4{(StAZ zDQ0n~x}V=+q3s0|D6=_N%_v-NvCN^nMe*dHVv8~*5)f^71uH;g3`Yps!p~&3ZY5c z)>Fk-`E+=PO|9GRv_=Ls&wBvZtA_0SD2jHCNv5sGVyHbUAPj(nBKNub7(G~CkunC!+$S*1L)QHV_5%DamfEF)Aq3>DB z>GboS6nb=UscPEo3$d5!-Vd@VYOac(&a!Z6BVjsMfgL8aerrs}$_JY8e1s}d2?4Pb za13f*W~YZoY>lP(J~)#bQS1kOIcu>C3yqsxjx2BqJTs+c79?4WGcrYrFpM>Lm#vhA z$|b5tH(0{8+S~`qkDoe4MGV5rb!t8!Je^JyB_^`=835Z}9b7kE6d@QNNN0xAUFnrvNWN+!Hll?- z-K?t!?ZWb9I4_SIKgODwpa=ZyKoq;DN&g%2mUd7>T$7nd*8_fE0u?$D(TVp=5ATyo z|KQ?r7DOb+F?FuWx7mP{c_2u0fWZ@J z!4Ah$5izvk$Nj45rzR@}P9*3bJ%JOUc9W0&quGOBHr{hf)Pa*zLgtzJdFJ3p{S5Ig z=($3lgsaNY{ls3T#~~|@Rar;hQIva}S_P5*y2OS3-%8COf8T2|F^_N3jC mMZt}!v@tS*-Z~Y#Id3TCTrZ+KT?w=$D~UYUY-(+nGxlE%M`2h1 diff --git a/WordPress/Resources/hr.lproj/Localizable.strings b/WordPress/Resources/hr.lproj/Localizable.strings index 5e240c1d6043c26a2832e69d45651ae2fcb1e932..4914bec10fb7b62c2413db1f494e35b78dfe0426 100644 GIT binary patch delta 1576 zcmd5+T}YE*6n?*LPMz*o=jN9Asnc1MXbBedV|byCi9gd2|2MapsB^ffBpM0gMPMvX z>4+{0y6`47-nz(c{0RvWA?hNc1fz=zA&RJwh|W6|zlm0t@iE@-{JhW3bDnd)p`hg5 zuw;5#14VfX$c~pnb({wJ^6DU{nWg%869*f?SZYeh5 zA%GX5nn@eU3O!qY0aHe;cF#PRi*1CgBn2Hl&>sPc6+KL>Dn^TCTmi(a7?}ZC#ntpz zN`MSp1wLZ8$q2X9dha|d@q7^iwedb>7nea3|?FK(0i)2 zhOSyNrBJba5OOP2%J53h!eDvJc1#`?gYxUO&|p)^3$S4xd|b%QkNHNd#7!G)xg5=} z%9p{ARdZvW)1-vm#%B6LJ>f|=_JwB{(72#W=ds}ouLVV6BKb%PsYBa_vbEsJA*DI{DgsGZ3%B}lF-M2Xotxa+8vcOyAQlFfBHbl%e`OR%9rpKj7cC!DEKac<%k za4tp54WBz|bC{neRoEFn_O>10(@FmBOkoDBRW_Eb@`BHZ2j0gc;S;>n^b}H z_RmOhG*f=$Ry1UfMZpte0vuVFMcVK}4{rCIF%e9YH5ikcod~%(9O2})a=Q9|mHakb|9plpt4F7T@V5F z{o2wn58e?fd;(k4vH$(OvKeOKZp`iPRt|FM`XgRgCc{eG!4giAkckHd*J`QiB~Hrd hs#UD)*frWX?s1IOZaRN`DKK*_w{x{YDlAHhl delta 3062 zcmeHJTWnNi5dP10TS{%0?QYBNLTk@%p+J#pL5SRfS`sdD*t#*G*JuX*Phlr7ubk7M0T`c8qKm7nh|q6~O?lT{sm<1vVu}?K{Mr;vtRCT0Ctqsg6P}y+oDv3o`lV<7 zHrCPkZ9>T+>`GVnA|ff`O4_NOb$;p?z8R(J^C9UdUZTkzo=aICll6vyh(=`xHchH^ zyZtq6|FLgbnqZ3w(xz>uMN^$LEi{>$7CMWAO5Q1e45)xSM%P#RG=nbYH_*uvhqRaM z&Xx-T`?XS_MS3!ECpbov?*KuPx`S?7biqqi<*vdcVpceDiijv3Pj9B)r|q<5nnQk7 ze!@m`4;L-d#YW{=<&{rOT!Bm_UJ_A;1X)Cx=;U90xIRc>p=Q#VdT&JH9b40vX$i& z9LS>|x*X+czGyzol|>56IxlM4sJUIY}Pae{>?V<8!B36Y>fGd3|Wfe}T*jIjC^m@^qE5!1!bqFcNrN?C@}=WGLf zL4zPyX|4fUC(b8We%K0L^%?}h6weHQp6XN@_W96rP{;gB@|da;_3WO%Gvf08-L3;%JFW%apVvgkygcMs}{;&10F zqE1#dbgmu9zk^9(&2dW$WJ7DTv2N9D9?!a0HZ0s^)@aG?gi$ z0e+#@E&sN&0vvP=I{>{pxNB>#hv>lh99eSlS}y5lPABn**zJ?kF4)H_K~Kc?;7NTZ>QK^v3hmP9|i`BIFp=CU943O0Ut?*_DJ)D z)uhB$#so;x!Fo3@C%r7DVB@bA0&fz}utsJXa%0lawNf8EX66faxz+XjUyg=u_@5Li zPS;~mQEhAJ(9NPJ1k3NXhV_3XP5#1hc#xpaZf?z@iheKk_UFrrep|6tL)C}Nc)OKQ VYQRPIcV4I9U9~Ia%)uo^e*u>#+$sP7 diff --git a/WordPress/Resources/hu.lproj/Localizable.strings b/WordPress/Resources/hu.lproj/Localizable.strings index f9b1a953b3aa3d76e163e4065fb16cd61748aa84..ddd7e7f694bc8fd731517c944badceb20d018bb8 100644 GIT binary patch delta 1706 zcmdT^ZAep57(Ul+W;b;gYpG4$U1&;Fww9E`EL|b_fy*Vx7O3Usq;0NkeuO64kD!RK z-VlR`sPI?z!4Z*G{pnA?`VcevfRz431f@t2g!P_Nvg^q5Z(J_tzV|%ubI&wGb1 zt1q5W-|0`$`bjfcPh_$S@AaevhIfRZGi8*1S}hCowQidLwzcuvcG5_^q=hu$8YV87 z>DFu9q?H8Wb5%ObN5svCaldsDmld&ol8bnm{4-y}^TAZ=r17cuRp8M}Rr~{(Tuxj_ z5Z zfjSr~muOAJws_e7Bui+4`u&;0ZuoJaIT}NX)&W~L!Vcl zv_)Z_N_bwW`=3q^BP9;n+mN8fcAaiA=&De7kjrIO`eh>@7`#Ucs<71PdoJFKC6Rey znBPN+0>q#oa@z&ZTxz<}{-?Hf&c2uMV!Q2~01YFyEd`Ep3w;`n_vjpyNFQ+Vn>3 z=)(Lgj52dp0M2`LIW;JKNd!MP^Wco^gfF0mqJD{Xp1ZbE!|jXzigYOI5?9!f0`1J> zIk_(Xcg(DW6wGpqg~#kO*^qTfqIrWot8{GI0}7dTHvb^(bHchCBE5C}R4Pq-pjOe3 zkAf=N^LQiyEE5tPAFqtd^k6Epaa887*pFujgYTVDg+>QcBpnXV<~j zNs(@NF{{dLLo2bF&)s&gw;PFh}Wzome*C()oWvGtRPD&V|3C2?YiJ y%C`u~xQtOQrRx+*xc|<+%7~-VltoqOTh_QRl`%*@GX2wPTK?XnqrKmT*8Bv>T&&Lk delta 2958 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 QPvTv_Mcn-Jr+3ny11ImSp#T5? delta 3234 zcmd^BU2IfE6rOFDw$x=?c4@b`z~1eTfF%t@0w@rIfKnn*NRdiKxNI-&+IG9_-crzz zT4VY|2zU}g`(TQI3DGo_i5g4^B|#Grun?kP)Tj@T7&Q%=n2>7x&P*@6K=Hwsn)q;c zXU@!=-|u`g=MT7l?REDL`e=*)9qRM>%3DQD7$PAou}idxs2bIaV#t=_D;CQkwXqr# zHg%r$Q_anMIzF&P-to_Kb?AdOwj{8@67@I|#b~!MMKeY`ugBQNSCOW)3af_Lf!|iq zfKemXos&_uzZLT~XkvK+nvx=py-B6XfLyulNi$^9uFZ9_v>@S<=L5r;0Sm`$9NdX7 zqEuQ?Ws&LkhgQJVF;^i?h*rANQ%CV>Zu&6jr8kZg&aQy->Fz(T&Zl&9kQRbzrtsH6 z>6_-slGlp&yUMhqwhF<5HynrspV<=~iY<~fxva#``HvvrIQ|px7IWHsF+_c`mWGPm zG*ar7jitRA)L&Q_OgGOtPZetg9lBNEHDNu9j97v%a=HRXD8l^dx0nIQeVz#Fc|oUJ-lH^nQE zaE&-rtkSz1qH@o|u1R?jh&js~FET@ylI0T(u}aBIIy$hG=058__SeeH*<<}H>;xt9>lR_2h=mR+A%h9fN_|Fj1wCH+6-id-7v&Vu?BJ*r%bFgVQyf? z=;H`=kx*DQ=R)ds*^7V1JZp_&zop?pmFpwp?89RE?DQsjygHxydgsx58ya~muU9W| z@n8~TFQJ@9AY@MU)7zi;3UvAIO~g|a?%pP+Z0yQ)HPEu7feD7F!jaC}t;d#ZbGxc& zX(UXwf6Suet7>Vu-c5(E=gZgYAI+iOm|Nz?PGwVbyGO3uJuqRSVh^@Vc~vD8KjNWl zXA8@9g4rLC=3=(B`45XNyW6R1!mFS`|22 zV3KL8X?`$!v_)z0)0Q0Bw>?jK53J0k+#aty*uCQs`tC%IY(CKwpwgi^RK2<=WQZ1+ z<`!WrX*8rkmzJL_pgVn@Y#V5@L<@!Y&Cb@W7Nh0A1zfGvGJh&^#@G)Jg_b#>O)3O2 zzEaxkQ3M$xy|bCL5OXz+(Elz%!$W}SICvnhgwu{g{DHao_&sezvur34Oy zWt_HDyH-H*f`T-M9R(#f!X+p42(2#;b}$ih3#Bx%1*QT=XB=zXN}O~?6bJ%qx|wtm zr-?H0qv#Z`iRoD3(MQTl-IAP;HU!Mg8pnt=-)*!tDqk_hXiT=KD@-uo=wNi%Tr-yI zF4fNI+oK5``XWx@qbr}6bubyXAs{xQYseKDJEhDZd%-1)hh=GGSp(;}IuASd52aWH z^G@FW@3naHU)O@(|DcYHkF#Wa@NyN+xoZm;&y_DeIU@ACXr+Qs{|jItZFFb4S^dhp)o7H8%$^wWfl zj6!A+IegL1puwv-^3>1_chKpC)H|XET2*(*b6>V)tkr!z=IaG{GsIe$X&QBduSIsq zX{vi4dEg#exV|!!ezkHf=HP^LQG=nV^NZK0J^z=R&Y9v&Z`0uS+tjz+iA z_HW#@|Ev6Q@ht4uy#C+FQ+VN^d@9%j(;|Px%{f Cj_)D> diff --git a/WordPress/Resources/ja.lproj/Localizable.strings b/WordPress/Resources/ja.lproj/Localizable.strings index 34f5ed03120111a5ad62784eb8aab004d4f58e58..b48762d58c7b61836951bc9871f359d3337bee43 100644 GIT binary patch delta 1724 zcmd5+T}V@L6#s8?b52}$yINP)^eTu%Dw(7qmF7TnYPtMCo%!uHOXtw31-c>-K?rf@ zB}76*kiuyB@8dx!6od#t0}F(u(S!65La#k_{@0e9&cL_0jJxyoJLmk)Id|@pV&{Xx zSI9v_rV3U|)Zo#n;60~DxgMIN{{ob9gVd%IWZ)RlLm~f*PbF?5l77-mI!Om$;_l33vwZBE4fWFq$fC?1MSSxfobhnLfAOCI?+hK3tJIz&ZvQeSuO153o;Yv zW(_eR31D1TOP7r;GP;p?OHQ|vr=#Z6tCduqwG&M}d2@2`6>#3?0$khFz*K?A{yw-= z2d4|P)K~B|0xDl5$U0y<-zdw2hh_tqmqaKmN(<3r4)7Oq;7=6bk(rAzA%{+USR=?a zR^TsAlhOGSzZ$-o^yzoe-iNI@kc58p5=ltSDECSviRk5mk3~F8`qil!sNX}j z7HA&f4Po>WWp>gljV`;kKa#iM8tyOYb(CyiX|m=py-2E%IX808KvPKmLC?b;EcS#m z#Lr1BO=~I`wP}sHL56Z1OD{eHQa5cR7cvK|RJ7}rbhpzdqt)GuG4ahfx4^jsE?C3> z7pyhL8E;_IM|*s!ZUxu<2pIHmG-3a8L5;YA#3;g5i?5vlAt8X=rFLoGgx8u%b)VrxDBL=5p{Xeq&H!TT4Y2g{0;E-%RC hG;R5ZobL*MIEifQ!`S{Fk7ea16;>QPy|U@l{RZY?u6O_d delta 2620 zcmc&$TWr&16#v?l(T!Wz4%W#o|4j)Xa~u-m1F{PS0cBhq8{M)2>$$+AApZdj%%;V@kb3ctFhkpjQiAe^FwW(}mEf#zWvg$XJrt#J98;R4); z(@+L;D!O1dMm})Kpf%kfkEL%)%5am$Flq46a48LL(&fg5CAQ=R(aD~B9;_=_hcDW# zm|i|Dr;yYq8t8{F;WM}kKR{1(K@_`|*UH=W-%RrDoOK4=|9Ps7gA9|6Ci>k#LlYr1 zEVUsVFsH;|FdBj3-frBbdGUUZSzga=He&h7X;apaC|_c?2qiplG1K(Trk*H%I;$3s z=TDR?@;^+;ZWRGizL}I(igHnw5crlYemuR*iQ5YDWpcqQ22h43J~>q^E^6Zlt-BEOMqowC5xXF40IUkFuwUnc_{_57R9to%m?2(W;HU>}iPR zoa+{~Cco&!Pv6b-%dB9nO(f&i(}M?#Gw|2f%bu|xui}NiO1!hgI*B8DfH^VXlj7-k zIjfdWWb=~e3^cJ!WqJfv7#!Ms3TcKYWzm$&MBwA_C)~xoA3NncOGnHGFaFfij#`;X z8Y{j^GQ5FD9Jv!J;XUv{DC&TfxOZ)hyjc|p2}#EXIf7gu+MMD(E$tAHJb1RuQe?Oe|v`94)DNAsDnyagxx!9WT5Th zB>7k8Vl$5Hm@ET3hEifNv)sQoX2YAZ0JTzko+er;Va!dYfS$yMsD)=sZ8oL=6U|2w zVKr~X?7`VM@ro5kucl(vU>43_m}=PtJ7Fcm{2Q9*jls2E z2XtY3?s`SRfiKMCiykEcBO0VEG0pVEwvZXdoQ=gh!Gj!NT6rd3c^|N=*KGS9PSA7W zhmZF8;^^UAnSrn`K<1Kh+mHoEj#}h*M@9_t*0D=TnemK{J*5m!HS9v?xtgQj8jZ`I z@CuO+%##p>tcm3`_bLAv2$mjWN4@IbOnRnv2)p01QD@b16MHfPSwIr;4o}R(lQKKP z9E=wbcXgfC+=UV!(Mn2-lL{=35cmB5#pC3scbUNa50~+5Uk#29r#~Yw^CEh;dIm5) sHHvw*C-}6VweL!^{s~Q*n>w_OtzueO zVpgO?PK=2oJg3D`+zW@QEs+ruqJR&VL$H4HX=&`(S{F)*y!bCM<6Bd5Z}5@_^I>zN zlaS9v#Zf*p$;XC87Ugiu11wXWLvpm?9WM?`kD_`yCqNWocBuOndV32<^9W5_#$fJ*4LX6-S5Lf)N<|v zyW+UjrAsUNvlnNsG-+eVb~S2y5Q&9x_Ns-;ecM*`Xf_YyqV@&34YzS7t2 zf%1DpHNEtA<-@&n0!_IMvXq^y#y}x}i*NYRIYnX@4BmBQPQ;O%@k^ulfmhBQZ>W;9 za~(A=rMSFg0r~KE(Y#G?%TzUrJw?|$2MPRv5x9~Z##1MCIe+rlLtclj>W_fCcYM_` zhLOIGZ2b`5eqZL}D>PdRy27p?W6MXTv`;Phf>~BJ>8dKmU7-eFo=V7{J{br~>+>d$ z^j}=`$nP&L7&7q9n^mDvx+v1FtcN1MlJgiE3*nEeel3ODr65mc2e>a;o?!s3Qzup^VJ@LYNua*Di4#Fw? zV?LKBZaEMWe!0p=a%`)qwe(E*Ee9UXS`+TV(0i GK>eR_f~rRV delta 2909 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 KQ9N+}UHLz;N9Ljc delta 3233 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 diff --git a/WordPress/Resources/pt.lproj/Localizable.strings b/WordPress/Resources/pt.lproj/Localizable.strings index cf131ca1eae088aa8790a055520706e634c154cc..81e4418e67da301c586211b766cb99a426654d13 100644 GIT binary patch delta 1660 zcmdT^T}YEr7(V;cIsc~Lrs6a{wW)zvW>f~5W)ZrXMi4pmY zi}Hz7F4{?&NGjpUe*98NA$-~6hDY2M$mA~5K24T{UWiMVXfuch^IfElI7kbz;pica zP-xVJ*-0Dez+4@~WF&9rNj)Okf;fv1?IeH60IKkMIv)RC23bjJZGgOlG~$6SBx)e1 zAjQJzn=yiOybLRVCz~VNZ`abLq;Um|&Llv{yQuK>N{isijE==1%Tx`syqsQ2?Uz7= zK7p=o9g@<5%pny_?~0(-+y@H!A@5`)T|BZR1;0TJ1NRfa*P((%124>Di)*OaFr$Eq zXIr4ETn#&fLTJ8#(&+6Njitk;d%o!7wG;O;&PH6BFuKNsqGQHJc<6QLBC`Ya z;%J2DM(zJ`Zy0YeQ@hnKle9psEhUV(nU%>_@$jmyI=2%GW)bFn2abW}xP9yZEh_)ry{@JuOa!Px{U-Fdzw8eC>gGV_T`IFI>7eEo8CRhwChPDBI@ zIvQyAU|*PG&2HYFv``aP&#dR|(ZTBHDzFYKGf;RWV+IMn`Y$Xq2FtUH!|I5dhKww$ z;@OLJiE1zjZ`cK6BNpl(YmTSs4|mJp>XS^kbvFy9@2F`1<9#yfdpe+`%d=Lgt{Dm3 z$Q)1sl@iuYJjr{HgVDDU;G2`n(4y>*1ZICyas@t}f8C{lI7Jmb_EIg+=tN7f_a&$& zx_bqRF3Ny+(oz-_!98My_hJ)Uf4_e-G~+zHku&hG%fYfb{>Udn!Wcb~w$3E>k+=>g zEPS-k*KZP~@OAzi_zX%qH-Al<*BWeakpN;Jv1&IUg{RQHVAF#9dp`C3nB{%~M24lV delta 2967 zcmeHJe@NVA7=Q1)(^EEg-Vc8}zjvD(m0dbUqA+sJTuxKBmaLgSPR}3bZ@s&@nU%Lc zV#tt<2eLoPgg|0hti9kuY&jO?z($c6!Tv}Swtq5>B7#AEp6}P=PH-?9)cy#0{l4$> zzR!>M^E{vDy-RNzE{_^6JFPTh9VfHZQra!Lgd+Mxljs!z;ZK zK<>jn98m6`_B1}@fpH(?n*P#;em8aRtdT=@mrmYJx*e6&1cw|@GX@96Au6!4UTn=c zg!z`ckoM8hIRb%*dUt@ zUBN@a5$FRYgw_akMO0G8FIhX-OvDZ)9ITU* zMQi%3`-QhDc@&JPrkr8}T{xUh=8`s222FD9`9fpeabVd4FAeb50nh!IyWxxL#Rr)i zku-`{teVxh6tPzvf!q%*H+I^wR}esa`UV>jvxdG0K4`8PZoRgZKr zwT9X%%rrEXYAr&{oaQc!JK}e&d`OCy_hoWrp^hiW4A%oIGbamhg)C7>pZ}b)ebbfc z+ZWyP#L@aVT?=JaI%wiO4^^Ht$dk3dMd?bYqQPNz!$ycg8gQM$P4AAm)ab8qGWGq|B(jxSsB%vny)$p7 z)x*gSMIb1(#yR_1{vv7&+3TImq_yd2T_^qZ>SLsQVR}d#4jL$_qVcOHd3O5gs21*B zTeXQ$srhj$4M#4;KD7b#sey*D4Rgr_`OC;#0N+k%wLq8YgR4>RT;>}ZVv$zZIy00n z&h~oXfeV|_^gssQLaLRv22eWcVOa#lkjTIe&#tNwY6M~E0w{c@PLJBN6@be!#GI_M zw@a--kLrS319~%+Hl(C*LOBp_Mm})LC0>Dh3_5T#E1&yc0CGOTL36I|2OV?w3|P#0 zeTJ5%tp9`jKp^M+Ly&3xOE=A4dtCnbSx*!V&&1KS>G*ukFqc6;^2r&~da8mf@{@fU z<)L+V?G%?Cleq(o3w~;+b2Hl>(#rZ*ZdrEyg6T=EiHDiP_1}k@WES(bL#1lN|m!+JL8AE8_4gd^}Xx zGWcCUPxEu8=eBs~!3IUVfQoKcLuI5Gu`m}J)R&9N%7g}$slPloGx9BBoU^eXdfC7- zy6&}8*Ssl(ITvac{Gw?z#*ZypT5vpaG4<}Oruy%rseB>+KZ$LdRcn@y22xu`6N%Bt k;voOnq16SO99cZCmoq=q+i7`4(WyTH`8|{4tHZXx0bkVHng9R* diff --git a/WordPress/Resources/sv.lproj/Localizable.strings b/WordPress/Resources/sv.lproj/Localizable.strings index 115c9d9cbdea6bca5162e34f29a3eb24a9984725..35d1ec55f578b30711e12bda04c4bcafbfeb4ace 100644 GIT binary patch delta 1738 zcmdT^TS!z<6g@L@&FQA2jg8|tPFyv!r)Y$V6dGpQkZ3xEbOkldaWu!#8MXHtA?P7( z3yJ6<5m8ari5?$?K|f(g(c>e845GiHpCUq{b*>FvBcnd!GIQ=Zd+mMp+Iz2iu}`|N zUm84RrJigH9k3?Qo$PALi6e|C0?Dp#Xtpf%zPmAgprTW-6eB*$-@YKCD#+pFRglRq$qbRjoeNk zWtB|hs}=2C%B!NG66uC}&NK==nr-lrtHfo4nd%cICeZ6Fo|Dba}*U=+3$_)e@%C`gxfGPyts@SOQ zrzz-+xXFtSijD?ZGONbE5|O=F6;VJcJ~ChQm6Xc~SsM{YbhjI}5LN|yKYT^ML?)Fu zorr{qfTe*R)VkJX=w@LJy#6}|6iVE{V{67twC`R#$&qqoDM)lc0=w@yD5JhAzZ9i~ zBv1k&kB8UOFNwo zI$u;p-}=ny4PY`cUz1t>z#h>9`pIZw@2BlP2R(TeWx`B{zi;IKoappGYyakB zrOzwZQ^qryFMTRW>7AG!Auz4My1YG@Bb|j-+*Zpboxn#w1i2_)>(u_gLyMS2zs3xI zA+tcN8@s_5xkg?-T4E|}{VS~qmQx~yUPyT<@&4Ct8^8G} GH0wJiaI6gg delta 2943 zcmc&$eN5F=7(VxM!3z@N{SfGa98iWC5ZG$1kBMRs2I)v0fjTbS%ST*3mfOK7UQ>RK{zY=4vBT*PJkQWve;sdC&27FG{U8H^+YP`<;*H zectDN&U^UaW!r~u+4jEYphulM=~aiLx<_;iDf)z8tP}mBL%;b%KE|HHlP{`;4|Clj zgt=Bcox-c%&Av{oKQ9JEP)I79)=1K6Q)iv?Ej0S8E29J32CzJUZ9ahc^j0tJIhadz zzd17enDGLTq1)o-uVyu>8?N~lwIbuwgbF`GM1!|z1V7gDXrJi86Qf$8N26;E(PEJH z)3B?Nk~|K&)-WrvMBs;>I9EZgm20UzJ57DaYVr5F!kmlrdgqL2>PX61Hhe#U2Etn9}=M&NNjO1P-D?QX@&`PWzkL(Px zq?+0^$a(UBhsw9r^QfA5uGE5;bhoK86J*klgKU8)2hFS*#o9@Inmp!cQ=M1MUM^EC zZM1z`Sbe{GEWuJuhnw;e;1fE~QQ}?>nG!#x%Z)_}` zp?Y6?C0WgT+diFUzi(F`4cjv4`rK@~Jf2R0%FJ8|r+c+MxsV8foZ`$w$9B4%Tt+rh zC+0)?y^F3Mdw^=jvuVNca{6O;nund(hlk5O$z&o#n-4rl7pn%T{PQHWd;djiTML#< zb=;#);UFE{ZM2j6Zpq5zcx-aRDZ$7K+BcjETeV#~3hB_*&zy8crbd_+doqT^5%@So zF?%t`-emQCIs&(<5O9sdrN|ZqvRvc{Dc5Uu#@j4aKWf9S@5LJ<#$3#^-J*3d0AuZy zJEcj&q|5sA88b(~km4>9gx)1$H30C?zLA0m_p5%4a}ZMpiK4kg!iVO-OB z2J5?k!Hjqf3pyFYbX18R$Oo|})&=I`H3UjhECCG(dJMn?zmBCr{Kg3Vc_=5sD&DSm z5Kvth4TuXs31TmYj@c%r?*PaJfW`G-luoU10N+NoZoD;XdR*6Ntn+$DA8O-o&;jny z5N(@*S$&^QpbeCK*mfRtyFqAbB@7K-;}aKX(X~eH<2MftCeYaa%m^2jtG^!LTolvE zB?2(dLAb*7V6%!{7S#E$lCewe`CCeuV6D*e0`^bVkiU&yMhAAQ%+^Du=^BAeIR-c@ zTGQ&+Y;8v`*^4Km#b2(>o==?7m~n$tw#!YwG`Og4*E~A1!A_S)WLEqcGRItkC5%Ep zZYZF!swAw4ua-uFDyTJCti?3?#gMvrqR6Uxze=^`M9myip(<7o+Em!6MovCvt)1eg z){tzX5=c@Dcs2{C$Cn4cMNdaFQep>7q^Au>&(@aZvg?@?dx6VRgn70ytB7+)RbS>r z*ger!!q=5K==={-eA!lFmltM?3dil@uJE=0U&0yxK$wP)tf9T%+Gyfb`aO{{FJij( zJrL1oXvIIR|E=nIGw+}pl}}Bas!vcqpIPd*RFGwBuD<)OoX*#m@hI-WP^E(=7T8tI Hc!TRNJ$}PS diff --git a/WordPress/Resources/tr.lproj/Localizable.strings b/WordPress/Resources/tr.lproj/Localizable.strings index fb29c8ae16778bcaa3e68372aefc6a1568bef80d..fda9db6ef6190118c8784e9d05938a17e8f7cd3a 100644 GIT binary patch delta 1629 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 Rr8>{E=Ik;!>Cq5-NPBCAM)e*cq&p; zDCZ1WqMvl+RE%6x=MVHc6~#hlu2oCd%r$3Doo%hPvevA*);i~YMbLC>)|P*?x68fv z-0wN}obx&7+(Xl8!&_e)+JYPMqw#jUcJO?T1-C7+Xc()Briib?kZ+xa$uACSi_Xa)@+?IM2tZa<5S9s#ZRkcN~uy!E8dsWIz+=eKxpCY&UqKsU(wd& zUiD4)1$?z-Xq!+d&O};N@q1K`!RaG`AreqQqf83$ktiR=Y>VZP(F zr5?M7Ck%b)IXrL7Lta8EjYQ;SYBW2<_X#~Ju6M@_)1->J`s|f{cTUB%ZfC@Ra~w!2 zLTsW{9P()4aWzVS?q5NA6ezQloB@oDjj&~x;Dt0BqDKu!p`3Ljn6`72SJHNlO6EAA z@AmUPd^R~`DIrqM3XAM#POG@&O_cyvkKT;h(Uz!wuox(YuM$7KFf1Xn&!42tgT85w z_a91MV~EJ2E2`;Nrz~e<#Eo%*Fa(~xjF@qn_-?{hV`LelLO&m286s(UICyTT@$5Xc z0lkw-#F~lkheh9SF9(LS_~t|-+>_(5BclrTYO`p{$ThCYr^xokdl_5m$%SL>cYeRXi8;5foG`p}_^wC??N_^N-!(WM* zS;tgtot=uUjhgW0*Q)AE*j6x7{&nI?fhIoJep4fJrQ7L#(qaXJLJ2z;wS^|(o!e@_ z_L(kRE|`P%`7U^ithA5Cmc}{QTvR2h7NnWbR$&z>6%KW19x*fKGG<9w4efbXic`Ky zv8VC_6^%7Ec>QCM{Dua%--gTn-@=)Rp$y_&##3ne$YT3-9oGA1mb|ihS?iWl>oCPM zpFb8Cs?MlL?{?v{-FEc)jLyEI`0Kh~D!P2TN>(r9AdbbmPtKJL?bQVl`EOYbXkTx`)wTxMj#C1+ z@j4ZIHx_c(-#JSadpBM%%1zfM3vO;+E8(`Z$J~?YMOfM1s?Nr?9;a}<6CI8-uQ_1% zSWtZ4j+K*L9`;qKtTUWJdJf!^r8t-og+De~2Zbn$d`b;|Ts#t!cbNYbNgiooUWZwv zb&e0KEMqJPk^9SiU+S_7eu`Z^wS%%yb4u#8d*2%`(dWvfWfT2MCGm1PlbKkxFJV>b zU!<^fE_{9R0;CHUihDy#FBQ78;wX2nE6qxi5>H&bIx02P3l6(+DHRefMFCo|3R*)mE$+6p6ZrYnNR#Q@Y9zgp5wP`Dbe{79Vs{6 z@L+dxeO#d|m$+wO!}h5E9skIVfA*0ak8AtNMDfmBVJPl&J;(TSkSr%;89V(2a}%E2 zN;OdM===Uiow5HwLgYB=UOLQh?K&dNyW+xRYNzeKc_%SV$U9&{ z@17nM?z7T-ShkOO9XdVdRkN_~ofbCg{)FVXlO33}ij%gQwC2e4;lM^GzI8-nY->7Q zWzu~HK6#gi~HXA{JTlf-*?@m@mnLjN9kEy z*&U6pqb<-*&cXJhju{W_^~mpBR%TG!{ecWig>rg(XwRBn<2; z7{xR?@9R=1o6*q~PaS4|k>buoFCX+kVM({=vD0bh$)f+vSDq-n;6EN-dayQk{3C83 zYvTYjq3XDdN&I|#IE@(j@&`{OB6uQJ_UY|CNoenhb9r|sWuanqV?mn)P<$y%$hoXEAI^N>LPk5 zBBV&^BKljs(H}M@cvTh@5fKpuU35_r;YC-`c|RI`Gp#OTjPE<|dCocSbIxagQmrA)Ph zJX*C>;=`M_CF4W61-Tb;*8jU(l%ghE79QOOF$_G)O& zi$eF40K#A4_oUAC)23yQt0R%cY`@@uhGR0H z8QPF+6I&S8(DAE#8K%Xq=dR-$t$gxAnT}6g8rSjW%h!#(_|_fCe1L+4*y3M-n{P7l zaXed3B1G4DCzR)=j2iYg6wR5xXjHDP2X!KgnGvbzY<@ Y`F-~c2u|4XWg?XaCq^v%!3#^q5Adp(K>z>% delta 2685 zcmeHJT}+#06nEA7_~a6~Z8 zGP@C(N5fpE8IvGhsFl~asnyhrZ7~o)GfgyR7fZbH!WhGa*_G#fAB3N9<%RCTG++9D z@B8*V=RD^*=k#JaV_`lcd2=TO)uZ54>&#&$umKij#~7_V%*>3e79TTXlVh)qCmPQ1 z33W)(WR%WDycuRe>825X6J#;wW`10G@HZY@i}+YJSeYC7Y511o1J@}#v)|if8aO1x zV>iyeEx;d&4*pj`wt`yX_A=vY*g*9#f8Xk_v=0_irF(ts=r$suO-Ypn+oh4p1E|17*TV@4WATMu7`;K1m{s zfgZyEg7Do1EnKfxs}6-LeUK{Z;=>2+ISL;Li2(Pue43$XfO3aHwc;&nhtXUoZ)|%Z zi|^>RX2P;BkN@mlQRN889mN`kiqG!{+qK->`NZDWh34*~@fg^aoIKq>qX0{t4!UO5 z<<`V9+r@6PF*eF7@Pt-Z&<3>`(kn3$ zMIDloL%1T#L((4lt&@&}Qdjaw5ELjjJb1=YT1q8A*Qsqpu-+`piB8}HU)|j05^+C@ z`*cI5mcX{}WK>E+SX7jzx(&&0MHeY$+x+f-l9A*m|1rrpGTJ2(i|?hB;GfcUQGQ7T zCor3oFS)@PF^4qn22mVx|CDc0H;qWb5jRa6>(P8)pW~L}TX(+w)pqrHgD)Oy8oB5L zrLYiU{HVM;@wn;OH00rlYV8&kvkDYtyjkDSMShO!ka zL}fU+IwAB?g8%*@_Kk_TY<@fWW=8p%0@p`a>zXQw0G|F#uRKDb5RcoqLlE~DxSubT!+{d z;l>ryUFXwS$^{Eo)&GfKCav7*?hcl=_Xhdl3s-+p^24dL29~dxU}Uj0Q=T9=&+uQw HlBVEqp8u4Q From ec07a51b55bed89e539a817142780af5dada501a Mon Sep 17 00:00:00 2001 From: Jorge Bernal Date: Wed, 27 Mar 2013 11:02:55 +0100 Subject: [PATCH 12/20] Don't succeed media uploads on empty response In some cases (display_errors Off?) media uploads that run out of memory would return an empty response. Treat that as a failed upload so it can be retried/discarded --- WordPress/Classes/Media.m | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/WordPress/Classes/Media.m b/WordPress/Classes/Media.m index 237e0232a707..2e0158a77575 100644 --- a/WordPress/Classes/Media.m +++ b/WordPress/Classes/Media.m @@ -143,11 +143,27 @@ - (void)xmlrpcUploadWithSuccess:(void (^)())success failure:(void (^)(NSError *e NSMutableURLRequest *request = [self.blog.api requestWithMethod:@"metaWeblog.newMediaObject" parameters:parameters]; dispatch_async(dispatch_get_main_queue(), ^(void) { + void (^failureBlock)(AFHTTPRequestOperation *, NSError *) = ^(AFHTTPRequestOperation *operation, NSError *error) { + if ([self.mediaType isEqualToString:@"featured"]) { + [[NSNotificationCenter defaultCenter] postNotificationName:FeaturedImageUploadFailed + object:self]; + } + + self.remoteStatus = MediaRemoteStatusFailed; + _uploadOperation = nil; + if (failure) failure(error); + }; AFHTTPRequestOperation *operation = [self.blog.api HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) { if ([self isDeleted] || self.managedObjectContext == nil) return; NSDictionary *response = (NSDictionary *)responseObject; + + if (![response isKindOfClass:[NSDictionary class]]) { + NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"The server returned an empty response. This usually means you need to increase the memory limit in your blog", @"")}]; + failureBlock(operation, error); + return; + } if([response objectForKey:@"videopress_shortcode"] != nil) self.shortcode = [response objectForKey:@"videopress_shortcode"]; @@ -178,15 +194,6 @@ - (void)xmlrpcUploadWithSuccess:(void (^)())success failure:(void (^)(NSError *e } failure:^(AFHTTPRequestOperation *operation, NSError *error) { if ([self isDeleted] || self.managedObjectContext == nil) return; - - if ([self.mediaType isEqualToString:@"featured"]) { - [[NSNotificationCenter defaultCenter] postNotificationName:FeaturedImageUploadFailed - object:self]; - } - - self.remoteStatus = MediaRemoteStatusFailed; - _uploadOperation = nil; - if (failure) failure(error); }]; [operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) { dispatch_async(dispatch_get_main_queue(), ^(void) { From 431e8c7460debf8cef22ce1497edad872213ecb2 Mon Sep 17 00:00:00 2001 From: Dan Roundhill Date: Fri, 29 Mar 2013 16:06:26 -0700 Subject: [PATCH 13/20] Spelling correction. Ref: http://make.wordpress.org/polyglots/2013/03/29/i-found-a-misspelled-string-while-updating-wordpress --- WordPress/Classes/NotificationsCommentDetailViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Classes/NotificationsCommentDetailViewController.m b/WordPress/Classes/NotificationsCommentDetailViewController.m index 640b20f7ad86..ae076a013316 100644 --- a/WordPress/Classes/NotificationsCommentDetailViewController.m +++ b/WordPress/Classes/NotificationsCommentDetailViewController.m @@ -160,7 +160,7 @@ - (void)displayNote { self.disclosureIndicator.hidden = NO; NSString *postTitle = [[self.post valueForKeyPath:@"title"] stringByDecodingXMLCharacters]; if (!postTitle || [postTitle isEqualToString:@""]) - postTitle = NSLocalizedString(@"Unitled Post", @"Used when a post has no title"); + postTitle = NSLocalizedString(@"Untitled Post", @"Used when a post has no title"); self.postBanner.titleLabel.text = postTitle; id authorAvatarURL = [self.post valueForKeyPath:@"author.avatar_URL"]; if ([authorAvatarURL isKindOfClass:[NSString class]]) { From 4a50e3af869334d1059fea579e6ce45ec104c19f Mon Sep 17 00:00:00 2001 From: Jorge Bernal Date: Tue, 2 Apr 2013 19:41:38 +0200 Subject: [PATCH 14/20] Check for dismissBlock before calling --- WordPress/Classes/WPFriendFinderViewController.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/WPFriendFinderViewController.m b/WordPress/Classes/WPFriendFinderViewController.m index 7c2c59ceccbe..60b6d58e9181 100644 --- a/WordPress/Classes/WPFriendFinderViewController.m +++ b/WordPress/Classes/WPFriendFinderViewController.m @@ -305,14 +305,18 @@ - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)butto [defaults setBool:YES forKey:kAccessedAddressBookPreference]; [defaults synchronize]; } - self.dismissBlock(buttonIndex); + if (self.dismissBlock) { + self.dismissBlock(buttonIndex); + } } // Called when we cancel a view (eg. the user clicks the Home button). This is not called when the user clicks the cancel button. // If not defined in the delegate, we simulate a click in the cancel button - (void)alertViewCancel:(UIAlertView *)alertView { - self.dismissBlock(-1); + if (self.dismissBlock) { + self.dismissBlock(-1); + } } From 87cb3004564fdbcfd4c216fb6bfa3963bbe01baa Mon Sep 17 00:00:00 2001 From: Jorge Bernal Date: Wed, 3 Apr 2013 23:26:29 +0200 Subject: [PATCH 15/20] Prompt for password when two step asks for app password If we get a XML-RPC error 425, that means the password was correct, but two step authentication is enabled, and we need to switch to an app specific password --- WordPress/Classes/WPTableViewController.m | 43 ++++++++++++++--------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/WordPress/Classes/WPTableViewController.m b/WordPress/Classes/WPTableViewController.m index 32e373df38e4..96f2874d02f1 100644 --- a/WordPress/Classes/WPTableViewController.m +++ b/WordPress/Classes/WPTableViewController.m @@ -619,21 +619,27 @@ - (void)syncItemsWithUserInteraction:(BOOL)userInteraction { _isSyncing = NO; [self configureNoResultsView]; if (self.blog) { - if (error.code == 405) { - // Prompt to enable XML-RPC using the default message provided from the WordPress site. - UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Couldn't sync", @"") - message:[error localizedDescription] - delegate:self - cancelButtonTitle:NSLocalizedString(@"Need Help?", @"") - otherButtonTitles:NSLocalizedString(@"Enable Now", @""), nil]; - - alertView.tag = 30; - [alertView show]; - - } else if (error.code == 403 && editSiteViewController == nil) { - [self promptForPassword]; - } else if (userInteraction) { - [WPError showAlertWithError:error title:NSLocalizedString(@"Couldn't sync", @"")]; + if ([error.domain isEqualToString:@"XMLRPC"]) { + if (error.code == 405) { + // Prompt to enable XML-RPC using the default message provided from the WordPress site. + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Couldn't sync", @"") + message:[error localizedDescription] + delegate:self + cancelButtonTitle:NSLocalizedString(@"Need Help?", @"") + otherButtonTitles:NSLocalizedString(@"Enable Now", @""), nil]; + + alertView.tag = 30; + [alertView show]; + + } else if (error.code == 403 && editSiteViewController == nil) { + [self promptForPasswordWithMessage:nil]; + } else if (error.code == 425 && editSiteViewController == nil) { + [self promptForPasswordWithMessage:[error localizedDescription]]; + } else if (userInteraction) { + [WPError showAlertWithError:error title:NSLocalizedString(@"Couldn't sync", @"")]; + } + } else { + [WPError showAlertWithError:error]; } } else { // For non-blog tables (notifications), just show the error for now @@ -642,9 +648,12 @@ - (void)syncItemsWithUserInteraction:(BOOL)userInteraction { }]; } -- (void)promptForPassword { +- (void)promptForPasswordWithMessage:(NSString *)message { + if (message == nil) { + message = NSLocalizedString(@"The username or password stored in the app may be out of date. Please re-enter your password in the settings and try again.", @""); + } UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Couldn't Connect", @"") - message:NSLocalizedString(@"The username or password stored in the app may be out of date. Please re-enter your password in the settings and try again.", @"") + message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:NSLocalizedString(@"OK", @""), nil]; From 73ba5e7b976d0efa22647151adee1b607427dddd Mon Sep 17 00:00:00 2001 From: Jorge Bernal Date: Wed, 3 Apr 2013 23:53:37 +0200 Subject: [PATCH 16/20] Added missing method --- WordPress/Classes/WPTableViewController.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/WPTableViewController.m b/WordPress/Classes/WPTableViewController.m index 96f2874d02f1..4d8e446fb729 100644 --- a/WordPress/Classes/WPTableViewController.m +++ b/WordPress/Classes/WPTableViewController.m @@ -632,7 +632,7 @@ - (void)syncItemsWithUserInteraction:(BOOL)userInteraction { [alertView show]; } else if (error.code == 403 && editSiteViewController == nil) { - [self promptForPasswordWithMessage:nil]; + [self promptForPassword]; } else if (error.code == 425 && editSiteViewController == nil) { [self promptForPasswordWithMessage:[error localizedDescription]]; } else if (userInteraction) { @@ -648,6 +648,10 @@ - (void)syncItemsWithUserInteraction:(BOOL)userInteraction { }]; } +- (void)promptForPassword { + [self promptForPasswordWithMessage:nil]; +} + - (void)promptForPasswordWithMessage:(NSString *)message { if (message == nil) { message = NSLocalizedString(@"The username or password stored in the app may be out of date. Please re-enter your password in the settings and try again.", @""); From 9cf6186607b7b64c34a5b1d319ab01e77c01f23e Mon Sep 17 00:00:00 2001 From: Jorge Bernal Date: Thu, 4 Apr 2013 11:49:37 +0200 Subject: [PATCH 17/20] Fixed orientation parsing on iOS5 --- WordPress/Classes/UINavigationController+Rotation.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/UINavigationController+Rotation.m b/WordPress/Classes/UINavigationController+Rotation.m index 74eba0d902b2..bbbc8b1d939c 100644 --- a/WordPress/Classes/UINavigationController+Rotation.m +++ b/WordPress/Classes/UINavigationController+Rotation.m @@ -26,7 +26,9 @@ - (NSUInteger)mySupportedInterfaceOrientations { } - (BOOL)myShouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { - return ([self mySupportedInterfaceOrientations] & toInterfaceOrientation) ? YES : NO; + NSUInteger mask = [self mySupportedInterfaceOrientations]; + NSUInteger orientation = 1 << toInterfaceOrientation; + return (mask & orientation) ? YES : NO; } + (void)load { From 637873f328804f2cde60f9206034a6718ad763c3 Mon Sep 17 00:00:00 2001 From: aerych Date: Tue, 9 Apr 2013 11:38:19 -0500 Subject: [PATCH 18/20] Fixes #1600. Also fixes an issue where the user's password would disappear after scrolling the view in landscape orientation. --- .../Classes/JetpackSettingsViewController.m | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/WordPress/Classes/JetpackSettingsViewController.m b/WordPress/Classes/JetpackSettingsViewController.m index fd3fb9e905bd..fcb4e1d7db23 100644 --- a/WordPress/Classes/JetpackSettingsViewController.m +++ b/WordPress/Classes/JetpackSettingsViewController.m @@ -15,6 +15,9 @@ @interface JetpackSettingsViewController () +@property (nonatomic, strong) NSString *username; +@property (nonatomic, strong) NSString *password; + @end @implementation JetpackSettingsViewController { @@ -27,6 +30,9 @@ @implementation JetpackSettingsViewController { BOOL _authenticating; } +@synthesize username = _username; +@synthesize password = _password; + #define kCheckCredentials NSLocalizedString(@"Verify and Save Credentials", @""); #define kCheckingCredentials NSLocalizedString(@"Verifing Credentials", @""); @@ -36,6 +42,8 @@ - (id)initWithBlog:(Blog *)blog { self = [super initWithStyle:UITableViewStyleGrouped]; if (self) { _blog = blog; + self.username = _blog.jetpackUsername; + self.password = _blog.jetpackPassword; } return self; } @@ -85,15 +93,14 @@ - (IBAction)skip:(id)sender { - (IBAction)save:(id)sender { [self dismissKeyboard]; [SVProgressHUD show]; - NSString *username = _usernameCell.textField.text; - NSString *password = _passwordCell.textField.text; + [self setAuthenticating:YES]; - [_blog validateJetpackUsername:username - password:password + [_blog validateJetpackUsername:_username + password:_password success:^{ [SVProgressHUD dismiss]; if (![[WordPressComApi sharedApi] username]) { - [[WordPressComApi sharedApi] signInWithUsername:username password:password success:nil failure:nil]; + [[WordPressComApi sharedApi] signInWithUsername:_username password:_password success:nil failure:nil]; } [self setAuthenticating:NO]; if (self.completionBlock) { @@ -162,7 +169,7 @@ - (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexP textCell.textField.keyboardType = UIKeyboardTypeEmailAddress; textCell.shouldDismissOnReturn = NO; textCell.delegate = self; - textCell.textField.text = _blog.jetpackUsername; + textCell.textField.text = _username; _usernameCell = textCell; } else { textCell.textLabel.text = NSLocalizedString(@"Password:", @""); @@ -170,7 +177,7 @@ - (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexP textCell.textField.secureTextEntry = YES; textCell.shouldDismissOnReturn = YES; textCell.delegate = self; - textCell.textField.text = _blog.jetpackPassword; + textCell.textField.text = _password; _passwordCell = textCell; } cell = textCell; @@ -235,6 +242,11 @@ - (void)cellWantsToSelectNextField:(UITableViewTextFieldCell *)cell { } - (void)cellTextDidChange:(UITableViewTextFieldCell *)cell { + if([cell isEqual:_usernameCell]) { + self.username = _usernameCell.textField.text; + } else { + self.password = _passwordCell.textField.text; + } [self updateSaveButton]; } @@ -254,6 +266,8 @@ - (void)setAuthenticating:(BOOL)authenticating { } - (void)updateSaveButton { + if (![self isViewLoaded]) return; + if ([self useNavigationController]) { self.navigationItem.rightBarButtonItem.enabled = [self saveEnabled]; } else { @@ -313,7 +327,7 @@ - (void)tryLoginWithCurrentWPComCredentials { if ([_blog hasJetpack] && !([[_blog jetpackUsername] length] && [[_blog jetpackPassword] length])) { NSString *wpcomUsername = [[WordPressComApi sharedApi] username]; NSString *wpcomPassword = [[WordPressComApi sharedApi] password]; - if (wpcomPassword && wpcomPassword) { + if (wpcomUsername && wpcomPassword) { [self tryLoginWithUsername:wpcomUsername andPassword:wpcomPassword]; } } @@ -324,6 +338,10 @@ - (void)tryLoginWithUsername:(NSString *)username andPassword:(NSString *)passwo NSAssert(password != nil, @"Can't login with a nil password"); _usernameCell.textField.text = username; _passwordCell.textField.text = password; + + self.username = username; + self.password = password; + [self save:nil]; } From 303acf7ade62599a39d97256a556c7d390ab72bd Mon Sep 17 00:00:00 2001 From: aerych Date: Wed, 10 Apr 2013 15:25:03 -0500 Subject: [PATCH 19/20] Adds a check for an uploading featured image when there are no other changes. --- WordPress/Classes/EditPostViewController.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/EditPostViewController.m b/WordPress/Classes/EditPostViewController.m index 6564a7288a24..148e3cad93ab 100644 --- a/WordPress/Classes/EditPostViewController.m +++ b/WordPress/Classes/EditPostViewController.m @@ -797,7 +797,9 @@ - (IBAction)cancelView:(id)sender { #if USE_AUTOSAVES [self restoreBackupPost:YES]; #endif - if (!self.hasChanges) { + // If this is a draft with no changes other than a featured image and + // the featured image is still uploading then hasChanges will be false. + if (!self.hasChanges && ![self isMediaInUploading]) { [self discard]; return; } From 060cf3c5a401ac0e58bb7ebe99fcf609744ce97d Mon Sep 17 00:00:00 2001 From: Jeffrey Vanneste Date: Sun, 14 Apr 2013 20:14:47 -0400 Subject: [PATCH 20/20] Add a media settings view for images (#1527) Ref: http://ios.trac.wordpress.org/ticket/1527 Added a media settings view that allows a user to manage the caption, link, alignment, position and size of an image that has been uploaded from the iOS device. Changes made to the media settings on other devices (web, android, etc) are handled. Example, you can upload an image from your phone, edit the size and caption on the web site and then open the post on the phone and make changes to the settings again. If there are any additional attributes added to the image or anchor elements they will not be lost. Note: Images uploaded from other devices are still not displayed in the attachments for a post. * Updating media no longer blindly replaces text, handles when the user makes changes to the HTML manually or from another device, and keeps attributes in place that the media settings can not handle * Changed all the media notifications to be sent in the same way. The notification object is always the sender and Media and MediaSettings are sent inside the userInfo dctionary. * MediaSettings ** Class method createMediaSettingsForUrl can be used to pull out the HTML for a media object matching the URL. This HTML will include the caption, a and img elements. ** 5 properties are exposed that can be set from the new MediaSettingsViewController (captionText, alignment, customWidth, customHeight, linkHref). Making changes to any of these will only replace/update the text in the media HTML and leave all other attributes alone. --- WordPress/Classes/EditPostViewController.m | 118 +- WordPress/Classes/Media.h | 2 + WordPress/Classes/Media.m | 41 +- WordPress/Classes/MediaObjectViewController.m | 5 +- WordPress/Classes/MediaSettings.h | 29 + WordPress/Classes/MediaSettings.m | 315 +++++ .../Classes/MediaSettingsViewController.h | 43 + .../Classes/MediaSettingsViewController.m | 643 ++++++++++ WordPress/Classes/PostMediaViewController.h | 2 + WordPress/Classes/PostMediaViewController.m | 29 +- WordPress/Resources/Images/button_red.png | Bin 0 -> 2363 bytes WordPress/Resources/Images/button_red@2x.png | Bin 0 -> 3516 bytes .../Resources/MediaSettingsViewController.xib | 1087 +++++++++++++++++ WordPress/WordPress.xcodeproj/project.pbxproj | 32 + WordPress/WordPressTest/MediaSettingsTests.h | 14 + WordPress/WordPressTest/MediaSettingsTests.m | 251 ++++ 16 files changed, 2536 insertions(+), 75 deletions(-) mode change 100644 => 100755 WordPress/Classes/EditPostViewController.m mode change 100644 => 100755 WordPress/Classes/Media.h mode change 100644 => 100755 WordPress/Classes/Media.m create mode 100644 WordPress/Classes/MediaSettings.h create mode 100644 WordPress/Classes/MediaSettings.m create mode 100755 WordPress/Classes/MediaSettingsViewController.h create mode 100755 WordPress/Classes/MediaSettingsViewController.m mode change 100644 => 100755 WordPress/Classes/PostMediaViewController.h mode change 100644 => 100755 WordPress/Classes/PostMediaViewController.m create mode 100755 WordPress/Resources/Images/button_red.png create mode 100755 WordPress/Resources/Images/button_red@2x.png create mode 100755 WordPress/Resources/MediaSettingsViewController.xib create mode 100644 WordPress/WordPressTest/MediaSettingsTests.h create mode 100644 WordPress/WordPressTest/MediaSettingsTests.m diff --git a/WordPress/Classes/EditPostViewController.m b/WordPress/Classes/EditPostViewController.m old mode 100644 new mode 100755 index 148e3cad93ab..0ba3adf0bc81 --- a/WordPress/Classes/EditPostViewController.m +++ b/WordPress/Classes/EditPostViewController.m @@ -136,7 +136,8 @@ - (void)viewDidLoad { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(newCategoryCreatedNotificationReceived:) name:WPNewCategoryCreatedAndUpdatedInBlogNotificationName object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(insertMediaAbove:) name:@"ShouldInsertMediaAbove" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(insertMediaBelow:) name:@"ShouldInsertMediaBelow" object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(removeMedia:) name:@"ShouldRemoveMedia" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(removeMedia:) name:@"ShouldRemoveMedia" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateMedia:) name:@"UpdateMedia" object:nil]; currentView = editView; writeButton.enabled = NO; @@ -1244,46 +1245,71 @@ - (void)deviceDidRotate:(NSNotification *)notification { } #pragma mark - Media management +- (void)removeMediaFromContent:(NSMutableString *)content mediaHtml:(NSString *)mediaHtml{ + // find the image html and replace it with an empty string + NSRange imageLocation = [content rangeOfString:[NSString stringWithFormat:@"%@%@", @"

", mediaHtml]]; + if (imageLocation.location == NSNotFound) { + // look at the end of the content + imageLocation = [content rangeOfString:[NSString stringWithFormat:@"%@%@", mediaHtml, @"

"]]; + if (imageLocation.location == NSNotFound) { + // look anywhere in the content + imageLocation = [content rangeOfString:mediaHtml]; + } + } + if (imageLocation.location != NSNotFound) { + [content replaceCharactersInRange:imageLocation withString:@""]; + } +} - (void)insertMediaAbove:(NSNotification *)notification { - Media *media = (Media *)[notification object]; - NSString *prefix = @"

"; + NSDictionary *userInfo = notification.userInfo; + Media *media = (Media *)[userInfo objectForKey:@"media"]; + MediaSettings *mediaSettings = (MediaSettings *)[userInfo objectForKey:@"mediaSettings"]; + NSString *postfix = @"

"; if(self.apost.content == nil || [self.apost.content isEqualToString:@""]) { self.apost.content = @""; - prefix = @""; + postfix = @""; } - NSMutableString *content = [[NSMutableString alloc] initWithString:media.html]; - NSRange imgHTML = [textView.text rangeOfString: content]; - - NSRange imgHTMLPre = [textView.text rangeOfString:[NSString stringWithFormat:@"%@%@", @"

", content]]; - NSRange imgHTMLPost = [textView.text rangeOfString:[NSString stringWithFormat:@"%@%@", content, @"

"]]; + NSString *currentMediaHtml = [MediaSettings createMediaSettingsForUrl:media.remoteURL content:self.apost.content].parsedHtml; + if (currentMediaHtml == nil) { + currentMediaHtml = @""; + } + NSMutableString *content = [[NSMutableString alloc] initWithString:self.apost.content]; + [self removeMediaFromContent:content mediaHtml:currentMediaHtml]; + + self.apost.content = [NSString stringWithFormat:@"%@%@%@", [media htmlWithMediaSettings:mediaSettings], postfix, content]; + [self refreshUIForCurrentPost]; +} + +- (void)updateMedia:(NSNotification *)notification { + NSDictionary *userInfo = notification.userInfo; + Media *media = (Media *)[userInfo objectForKey:@"media"]; + MediaSettings *mediaSettings = (MediaSettings *)[userInfo objectForKey:@"mediaSettings"]; - if (imgHTMLPre.location == NSNotFound && imgHTMLPost.location == NSNotFound && imgHTML.location == NSNotFound) { - [content appendString:[NSString stringWithFormat:@"%@%@", prefix, self.apost.content]]; - self.apost.content = content; + NSMutableString *content = [[NSMutableString alloc] initWithString:self.apost.content]; + + NSString *currentMediaHtml = [MediaSettings createMediaSettingsForUrl:media.remoteURL content:content].parsedHtml; + if (currentMediaHtml == nil) { + currentMediaHtml = @""; + } + NSRange mediaHtmlRange = [content rangeOfString:currentMediaHtml]; + + if (mediaHtmlRange.location == NSNotFound) { + [content appendString:[NSString stringWithFormat:@"

%@", [media htmlWithMediaSettings:mediaSettings]]]; } - else { - NSMutableString *processedText = [[NSMutableString alloc] initWithString:textView.text]; - if (imgHTMLPre.location != NSNotFound) - [processedText replaceCharactersInRange:imgHTMLPre withString:@""]; - else if (imgHTMLPost.location != NSNotFound) - [processedText replaceCharactersInRange:imgHTMLPost withString:@""]; - else - [processedText replaceCharactersInRange:imgHTML withString:@""]; - - [content appendString:[NSString stringWithFormat:@"

%@", processedText]]; - self.apost.content = content; + else { + [content replaceCharactersInRange:mediaHtmlRange withString:[media htmlWithMediaSettings:mediaSettings]]; } - _hasChangesToAutosave = YES; + self.apost.content = content; [self refreshUIForCurrentPost]; - [self.apost autosave]; - [self incrementCharactersChangedForAutosaveBy:content.length]; } - (void)insertMediaBelow:(NSNotification *)notification { - Media *media = (Media *)[notification object]; + NSDictionary *userInfo = notification.userInfo; + Media *media = (Media *)[userInfo objectForKey:@"media"]; + MediaSettings *mediaSettings = (MediaSettings *)[userInfo objectForKey:@"mediaSettings"]; NSString *prefix = @"

"; if(self.apost.content == nil || [self.apost.content isEqualToString:@""]) { @@ -1291,41 +1317,25 @@ - (void)insertMediaBelow:(NSNotification *)notification { prefix = @""; } + NSString *currentMediaHtml = [MediaSettings createMediaSettingsForUrl:media.remoteURL content:self.apost.content].parsedHtml; + if (currentMediaHtml == nil) { + currentMediaHtml = @""; + } NSMutableString *content = [[NSMutableString alloc] initWithString:self.apost.content]; - NSRange imgHTML = [content rangeOfString: media.html]; - NSRange imgHTMLPre = [content rangeOfString:[NSString stringWithFormat:@"%@%@", @"

", media.html]]; - NSRange imgHTMLPost = [content rangeOfString:[NSString stringWithFormat:@"%@%@", media.html, @"

"]]; - - if (imgHTMLPre.location == NSNotFound && imgHTMLPost.location == NSNotFound && imgHTML.location == NSNotFound) { - [content appendString:[NSString stringWithFormat:@"%@%@", prefix, media.html]]; - self.apost.content = content; - } - else { - if (imgHTMLPre.location != NSNotFound) - [content replaceCharactersInRange:imgHTMLPre withString:@""]; - else if (imgHTMLPost.location != NSNotFound) - [content replaceCharactersInRange:imgHTMLPost withString:@""]; - else - [content replaceCharactersInRange:imgHTML withString:@""]; - [content appendString:[NSString stringWithFormat:@"

%@", media.html]]; - self.apost.content = content; - } - _hasChangesToAutosave = YES; + [self removeMediaFromContent:content mediaHtml:currentMediaHtml]; + + self.apost.content = [NSString stringWithFormat:@"%@%@%@", content, prefix, [media htmlWithMediaSettings:mediaSettings]]; [self refreshUIForCurrentPost]; - [self.apost autosave]; - [self incrementCharactersChangedForAutosaveBy:content.length]; } - (void)removeMedia:(NSNotification *)notification { //remove the html string for the media object Media *media = (Media *)[notification object]; - textView.text = [textView.text stringByReplacingOccurrencesOfString:[NSString stringWithFormat:@"

%@", media.html] withString:@""]; - textView.text = [textView.text stringByReplacingOccurrencesOfString:[NSString stringWithFormat:@"%@

", media.html] withString:@""]; - textView.text = [textView.text stringByReplacingOccurrencesOfString:media.html withString:@""]; - _hasChangesToAutosave = YES; - [self autosaveContent]; + NSString *currentMediaHtml = [MediaSettings createMediaSettingsForUrl:media.remoteURL content:self.apost.content].parsedHtml; + NSMutableString *content = [[NSMutableString alloc] initWithString:self.apost.content]; + [self removeMediaFromContent:content mediaHtml:currentMediaHtml]; + self.apost.content = content; [self refreshUIForCurrentPost]; - [self incrementCharactersChangedForAutosaveBy:media.html.length]; } diff --git a/WordPress/Classes/Media.h b/WordPress/Classes/Media.h old mode 100644 new mode 100755 index 9206c2053734..11a7048627f5 --- a/WordPress/Classes/Media.h +++ b/WordPress/Classes/Media.h @@ -9,6 +9,7 @@ #import #import "Blog.h" #import "AbstractPost.h" +#import "MediaSettings.h" typedef NS_ENUM(NSUInteger, MediaRemoteStatus) { MediaRemoteStatusPushing, // Uploading post @@ -51,6 +52,7 @@ typedef NS_ENUM(NSUInteger, MediaRemoteStatus) { - (void)remove; - (void)save; - (void)setImage:(UIImage *)image withSize:(MediaResize)size; +- (NSString *)htmlWithMediaSettings:(MediaSettings *)mediaSettings; @end diff --git a/WordPress/Classes/Media.m b/WordPress/Classes/Media.m old mode 100644 new mode 100755 index 2e0158a77575..f6e4f700d84d --- a/WordPress/Classes/Media.m +++ b/WordPress/Classes/Media.m @@ -214,6 +214,13 @@ - (void)xmlrpcUploadWithSuccess:(void (^)())success failure:(void (^)(NSError *e } - (NSString *)html { + return [self htmlWithMediaSettings:nil]; +} + +- (NSString *)htmlWithMediaSettings:(MediaSettings *)mediaSettings { + if (mediaSettings == nil) { + mediaSettings = [[MediaSettings alloc] init]; + } NSString *result = @""; if(self.mediaType != nil) { @@ -221,20 +228,30 @@ - (NSString *)html { if(self.shortcode != nil) result = self.shortcode; else if(self.remoteURL != nil) { - NSString *linkType = nil; - if( [[self.blog getOptionValue:@"image_default_link_type"] isKindOfClass:[NSString class]] ) - linkType = (NSString *)[self.blog getOptionValue:@"image_default_link_type"]; - else - linkType = @""; + // try to generate the HTML from the media settings first + result = [mediaSettings html]; - if ([linkType isEqualToString:@"none"]) { - result = [NSString stringWithFormat: - @"\"%@\"", - self.remoteURL, self.filename]; - } else { + // if the HTML generated was empty then create the default HTML for the image + if (result == nil || [result isEqualToString:@""]) { + // set the link blocks + NSString *linkPrefix = nil; + NSString *linkPostfix = nil; + if([[self.blog getOptionValue:@"image_default_link_type"] isKindOfClass:[NSString class]]) { + NSString *mediaLinkType = (NSString *)[self.blog getOptionValue:@"image_default_link_type"]; + if ([mediaLinkType isEqualToString:@"file"]) { + linkPrefix = [NSString stringWithFormat: + @"", + self.remoteURL]; + linkPostfix = @""; + } + } else { + linkPrefix = @""; + linkPostfix = @""; + } + result = [NSString stringWithFormat: - @"\"%@\"", - self.remoteURL, self.remoteURL, self.filename]; + @"%@%@", + linkPrefix, self.remoteURL, linkPostfix]; } } } diff --git a/WordPress/Classes/MediaObjectViewController.m b/WordPress/Classes/MediaObjectViewController.m index c1a15f39058e..33903ccca659 100644 --- a/WordPress/Classes/MediaObjectViewController.m +++ b/WordPress/Classes/MediaObjectViewController.m @@ -143,16 +143,17 @@ - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger } } else if(isInserting == YES) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:media, @"media", [[MediaSettings alloc] init], @"mediaSettings", nil]; switch (buttonIndex) { case 0: - [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldInsertMediaAbove" object:media]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldInsertMediaAbove" object:self userInfo:userInfo]; if(IS_IPAD == YES) [self dismissModalViewControllerAnimated:YES]; else [self.navigationController popViewControllerAnimated:YES]; break; case 1: - [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldInsertMediaBelow" object:media]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldInsertMediaBelow" object:self userInfo:userInfo]; if(IS_IPAD == YES) [self dismissModalViewControllerAnimated:YES]; else diff --git a/WordPress/Classes/MediaSettings.h b/WordPress/Classes/MediaSettings.h new file mode 100644 index 000000000000..bde1f1921eb5 --- /dev/null +++ b/WordPress/Classes/MediaSettings.h @@ -0,0 +1,29 @@ +// +// MediaSettings.h +// WordPress +// +// Created by Jeffrey Vanneste on 2013-01-12. +// Copyright (c) 2013 WordPress. All rights reserved. +// + +#import + +@interface MediaSettings : NSObject + +// creates a MediaSettings object for the first occurrence of the URL in the content ++ (MediaSettings *)createMediaSettingsForUrl:(NSString *)url content:(NSString *)content; +- (NSString *) html; + +@property (nonatomic, strong, readonly) NSString* parsedHtml; +@property (nonatomic, strong, readonly) NSString* parsedCaptionAttributes; +@property (nonatomic, strong, readonly) NSString* parsedImageHtml; +@property (nonatomic, strong, readonly) NSString* parsedAnchorHtml; + +@property (nonatomic, strong) NSString* linkHref; +@property (nonatomic, strong) NSString* captionText; +@property (nonatomic, strong) NSString* alignment; +@property (nonatomic, strong) NSNumber* customWidth; +@property (nonatomic, strong) NSNumber* customHeight; + +@end + diff --git a/WordPress/Classes/MediaSettings.m b/WordPress/Classes/MediaSettings.m new file mode 100644 index 000000000000..533001a896fe --- /dev/null +++ b/WordPress/Classes/MediaSettings.m @@ -0,0 +1,315 @@ +// +// MediaSettings.m +// WordPress +// +// Created by Jeffrey Vanneste on 2013-01-12. +// Copyright (c) 2013 WordPress. All rights reserved. +// + +#import "MediaSettings.h" + +@interface MediaSettings () +@property (nonatomic, strong) NSString* parsedHtml; +@property (nonatomic, strong) NSString* parsedCaptionAttributes; +@property (nonatomic, strong) NSString* parsedImageHtml; +@property (nonatomic, strong) NSString* parsedAnchorHtml; +@end + + +@implementation MediaSettings {} + +@synthesize parsedHtml; +@synthesize parsedImageHtml; +@synthesize parsedCaptionAttributes; +@synthesize parsedAnchorHtml; +@synthesize linkHref; +@synthesize captionText; +@synthesize customWidth; +@synthesize customHeight; +@synthesize alignment; + +- (void)dealloc { + parsedHtml = nil; + parsedImageHtml = nil; + parsedCaptionAttributes = nil; + parsedAnchorHtml = nil; + linkHref = nil; + captionText = nil; + customWidth = nil; + customHeight = nil; + alignment = nil; +} + + +- (NSString *) html { + NSMutableString *html = [NSMutableString string]; + + // MediaSettings can only generate html if existing parsed html exists + if (parsedHtml == nil || [parsedHtml isEqualToString:@""] || parsedImageHtml == nil || [parsedImageHtml isEqualToString:@""]) { + return @""; + } + + // create the caption blocks + NSString *captionPrefix = nil; + NSString *captionPostfix = nil; + if (captionText != nil && ![captionText isEqualToString:@""]) { + NSString *captionAttributes = @""; + if (parsedCaptionAttributes == nil || [parsedCaptionAttributes isEqualToString:@""]) { + captionAttributes = @""; + } else { + captionAttributes = [NSString stringWithString:parsedCaptionAttributes]; + } + if (alignment != nil) { + captionAttributes = [self replaceOrSetValueInContent:captionAttributes regex:@"align=['\"]([^'\"]*)['\"]?" replacement:[NSString stringWithFormat:@"align=\"%@\"", alignment]]; + } + if (customWidth != nil) { + captionAttributes = [self replaceOrSetValueInContent:captionAttributes regex:@"width=['\"]([0-9]*)['\"]?" replacement:[NSString stringWithFormat:@"width=\"%d\"", [customWidth intValue]]]; + } + captionPrefix = [NSString stringWithFormat:@"[caption%@]", captionAttributes]; + captionPostfix = [NSString stringWithFormat:@"%@[/caption]", captionText]; + } else { + captionPrefix = @""; + captionPostfix = @""; + } + + // create the link blocks + NSString *linkPrefix = @""; + NSString *linkPostfix = @""; + if (linkHref != nil) { + if (![linkHref isEqualToString:@""]) { + if (parsedAnchorHtml == nil || [parsedAnchorHtml isEqualToString:@""]) { + linkPrefix = [NSString stringWithFormat:@"", linkHref]; + } else { + // temporary remove the trailing > + linkPrefix = [parsedAnchorHtml substringWithRange:NSMakeRange(0, parsedAnchorHtml.length-1)]; + linkPrefix = [NSString stringWithFormat:@"%@>", [self replaceOrSetValueInContent:linkPrefix regex:@"href=['\"]([^'\"]*)['\"]?" replacement:[NSString stringWithFormat:@"href=\"%@\"", linkHref]]]; + } + linkPostfix = @""; + } + } + + // update the image html + NSString *imageHtml = [NSString stringWithString:parsedImageHtml]; + // temporary remove the trailing /> + imageHtml = [imageHtml substringWithRange:NSMakeRange(0, imageHtml.length-2)]; + if (customWidth != nil) { + imageHtml = [self replaceOrSetValueInContent:imageHtml regex:@"width=['\"]([0-9]*)['\"]?" replacement:[NSString stringWithFormat:@"width=\"%d\"", [customWidth intValue]]]; + } + if (customHeight != nil) { + imageHtml = [self replaceOrSetValueInContent:imageHtml regex:@"height=['\"]([0-9]*)['\"]?" replacement:[NSString stringWithFormat:@"height=\"%d\"", [customHeight intValue]]]; + } + if (alignment != nil) { + // add the alignment to the img class field unless it was added to the caption shortcode + NSString *imageClass = [MediaSettings parseContent:imageHtml regex:@"class=['\"]([^'\"]*)['\"]?" retrievalGroup:1]; + NSMutableArray *imageClasses = [NSMutableArray arrayWithArray:[imageClass componentsSeparatedByString:@" "]]; + [imageClasses removeObject:@""]; + [imageClasses removeObject:@"alignnone"]; + [imageClasses removeObject:@"alignleft"]; + [imageClasses removeObject:@"alignright"]; + [imageClasses removeObject:@"aligncenter"]; + if (captionText == nil || [captionText isEqualToString:@""]) { + [imageClasses addObject:alignment]; + } + if ([imageClasses count] > 0) { + imageClass = [imageClasses componentsJoinedByString:@" "]; + imageHtml = [self replaceOrSetValueInContent:imageHtml regex:@"class=['\"]([^'\"]*)['\"]?" replacement:[NSString stringWithFormat:@"class=\"%@\"", imageClass]]; + } + } + imageHtml = [NSString stringWithFormat:@"%@/>", imageHtml]; + + [html appendFormat:@"%@%@%@%@%@", captionPrefix, linkPrefix, imageHtml, linkPostfix, captionPostfix]; + + return html; +} + +- (NSString *)description { + NSMutableString *result = [[NSMutableString alloc] init]; + [result appendFormat:@"parsedHtml: %@\n", parsedHtml]; + [result appendFormat:@"parsedAnchorHtml: %@\n", parsedAnchorHtml]; + [result appendFormat:@"parsedImageHtml: %@\n", parsedImageHtml]; + [result appendFormat:@"parsedCaptionAttributes: %@\n", parsedCaptionAttributes]; + [result appendFormat:@"linkHref: %@\n", linkHref]; + [result appendFormat:@"captionText: %@\n", captionText]; + [result appendFormat:@"customWidth: %@\n", customWidth]; + [result appendFormat:@"customHeight: %@\n", customHeight]; + [result appendFormat:@"alignment: %@\n", alignment]; + + [result appendFormat:@"html: %@\n", [self html]]; + return result; +} + +- (NSString *)replaceOrSetValueInContent:(NSString *)content regex:(NSString *)regex replacement:(NSString *)replacement { + NSError* error = nil; + NSRegularExpression* regexExpression = [NSRegularExpression + regularExpressionWithPattern:regex + options:NSRegularExpressionCaseInsensitive + error:&error]; + NSArray* matches = [regexExpression matchesInString:content options:NSRegularExpressionCaseInsensitive range:NSMakeRange(0, [content length])]; + for (NSTextCheckingResult* match in matches) { + if ([match numberOfRanges] > 0) { + NSMutableString *newContent = [NSMutableString stringWithString:content]; + [newContent replaceCharactersInRange:[match rangeAtIndex:0] withString:replacement]; + return newContent; + } + } + + // if no match is found return the same content + return [NSString stringWithFormat:@"%@ %@", content, replacement]; +} + +#pragma mark - +#pragma mark - Class methods ++ (NSString *)parseContent:(NSString *)content regex:(NSString *)regex retrievalGroup:(int)retrievalGroup { + NSError* error = nil; + NSRegularExpression* regexExpression = [NSRegularExpression + regularExpressionWithPattern:regex + options:NSRegularExpressionCaseInsensitive + error:&error]; + NSArray* matches = [regexExpression matchesInString:content options:NSRegularExpressionCaseInsensitive range:NSMakeRange(0, [content length])]; + for (NSTextCheckingResult* match in matches) { + if ([match numberOfRanges] > retrievalGroup) { + return [content substringWithRange:[match rangeAtIndex:retrievalGroup]]; + } + } + + // if nothing is found + return @""; +} + ++ (MediaSettings *)createMediaSettingsForUrlHelper:(NSString *)url content:(NSString *)content includeCaption:(BOOL)includeCaption mediaSettings:(MediaSettings *)mediaSettings { + if (mediaSettings == nil) { + mediaSettings = [[MediaSettings alloc] init]; + } + + // This will match every [caption...] ... [/caption] and create 3 groups: + // Group0: the whole match + // Group1: html containing link and img or just img if there is no link + // Group2: the img html + // Group3: the caption if includeCaption is set + NSError* error = nil; + NSRegularExpression* fullMediaRegex; + if (includeCaption) { + fullMediaRegex = [NSRegularExpression + regularExpressionWithPattern:@"((?:]+>)?(]+>)(?:<\\/a>)?)([\\s\\S]*)" + options:NSRegularExpressionCaseInsensitive + error:&error]; + } else { + fullMediaRegex = [NSRegularExpression + regularExpressionWithPattern:@"((?:]+>)?(]+>)(?:<\\/a>)?)" + options:NSRegularExpressionCaseInsensitive + error:&error]; + } + + // find the first match of url in a media match + NSArray* matches = [fullMediaRegex matchesInString:content options:NSRegularExpressionCaseInsensitive range:NSMakeRange(0, [content length])]; + for (NSTextCheckingResult* match in matches) { + NSString* matchText = [content substringWithRange:[match range]]; + if ([matchText rangeOfString:url options:NSCaseInsensitiveSearch].location != NSNotFound) { + if ([match numberOfRanges] >= 3) { + // text containing the link and img + NSString *imageHtml = [content substringWithRange:[match rangeAtIndex:2]]; + mediaSettings.parsedImageHtml = imageHtml; + NSString *imageSource = [self parseContent:imageHtml regex:@"src=['\"]([^'\"]*)['\"]?" retrievalGroup:1]; + if ([imageSource caseInsensitiveCompare:url] != NSOrderedSame) { + // the image source tag does not match the url passed in so look at the next match + continue; + } + NSString *parsedWidth = [self parseContent:imageHtml regex:@"width=['\"]([0-9]*)['\"]?" retrievalGroup:1]; + if (parsedWidth != nil && ![parsedWidth isEqualToString:@""]) { + mediaSettings.customWidth = [NSNumber numberWithInt:[parsedWidth intValue]]; + } + NSString *parsedHeight = [self parseContent:imageHtml regex:@"height=['\"]([0-9]*)['\"]?" retrievalGroup:1]; + if (parsedHeight != nil && ![parsedHeight isEqualToString:@""]) { + mediaSettings.customHeight = [NSNumber numberWithInt:[parsedHeight intValue]]; + } + if (mediaSettings.alignment == nil) { + NSString *imageClasses = [self parseContent:imageHtml regex:@"class=['\"]([^'\"]*)['\"]?" retrievalGroup:1]; + if ([imageClasses rangeOfString:@"alignleft" options:NSCaseInsensitiveSearch].location != NSNotFound) { + mediaSettings.alignment = @"alignleft"; + } else if ([imageClasses rangeOfString:@"aligncenter" options:NSCaseInsensitiveSearch].location != NSNotFound) { + mediaSettings.alignment = @"aligncenter"; + } else if ([imageClasses rangeOfString:@"alignright" options:NSCaseInsensitiveSearch].location != NSNotFound) { + mediaSettings.alignment = @"alignright"; + } else { + mediaSettings.alignment = @"alignnone"; + } + } + } + if ([match numberOfRanges] >= 2) { + // text containing the link and img + NSString *linkAndImageHtml = [content substringWithRange:[match rangeAtIndex:1]]; + if (!includeCaption) { + mediaSettings.parsedHtml = linkAndImageHtml; + } + + mediaSettings.linkHref = [self parseContent:linkAndImageHtml regex:@"href=['\"]([^'\"]*)['\"]?" retrievalGroup:1]; + if (mediaSettings.linkHref != nil && ![mediaSettings.linkHref isEqualToString:@""]) { + NSRange imageHtmlRange = [linkAndImageHtml rangeOfString:mediaSettings.parsedImageHtml]; + + mediaSettings.parsedAnchorHtml = [linkAndImageHtml substringWithRange:NSMakeRange(0, imageHtmlRange.location)];; + } + } + if (includeCaption && [match numberOfRanges] >= 4) { + mediaSettings.captionText = [content substringWithRange:[match rangeAtIndex:3]]; + } + + break; + } + } + + return mediaSettings; +} + ++ (MediaSettings *)createMediaSettingsForUrl:(NSString *)url content:(NSString *)content { + MediaSettings *mediaSettings = [[MediaSettings alloc] init]; + + // This will match every [caption...] ... [/caption] and create 3 groups: + // Group0: the whole match + // Group1: the caption attributes + // Group2: the a and img elements and the caption string + NSError* error = nil; + NSRegularExpression* fullMediaRegex = [NSRegularExpression + regularExpressionWithPattern:@"(?:

)?\\[(?:wp_)?caption([^\\]]+)\\]([\\s\\S]+?)\\[\\/(?:wp_)?caption\\](?:<\\/p>)?" + options:NSRegularExpressionCaseInsensitive + error:&error]; + + // find the first match of url in a media match + BOOL mediaFound = NO; + NSArray* matches = [fullMediaRegex matchesInString:content options:NSRegularExpressionCaseInsensitive range:NSMakeRange(0, [content length])]; + for (NSTextCheckingResult* match in matches) { + NSString* matchText = [content substringWithRange:[match range]]; + if ([matchText rangeOfString:url options:NSCaseInsensitiveSearch].location != NSNotFound) { + mediaSettings.parsedHtml = matchText; + if ([match numberOfRanges] >= 1) { + + // get all the attributes for the caption + NSString *captionAttributes = [content substringWithRange:[match rangeAtIndex:1]]; + + mediaSettings.parsedCaptionAttributes = captionAttributes; + NSString *parsedWidth = [self parseContent:captionAttributes regex:@"width=['\"]([0-9]*)['\"]?" retrievalGroup:1]; + if (parsedWidth != nil && ![parsedWidth isEqualToString:@""]) { + mediaSettings.customWidth = [NSNumber numberWithInt:[parsedWidth intValue]]; + } + mediaSettings.alignment = [[self parseContent:captionAttributes regex:@"align=['\"]([^'\"]*)['\"]?" retrievalGroup:1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + } + if ([match numberOfRanges] >= 2) { + NSString *imageHtmlWithCaption = [content substringWithRange:[match rangeAtIndex:2]]; + [self createMediaSettingsForUrlHelper:url content:imageHtmlWithCaption includeCaption:YES mediaSettings:mediaSettings]; + } + + mediaFound = YES; + break; + } + } + + if (!mediaFound) { + // if the image didn't have a caption we need to do another search + [self createMediaSettingsForUrlHelper:url content:content includeCaption:NO mediaSettings:mediaSettings]; + } + + return mediaSettings; +} + +@end + + diff --git a/WordPress/Classes/MediaSettingsViewController.h b/WordPress/Classes/MediaSettingsViewController.h new file mode 100755 index 000000000000..fc28a8ec9e5b --- /dev/null +++ b/WordPress/Classes/MediaSettingsViewController.h @@ -0,0 +1,43 @@ +// +// MediaSettingsViewController.h +// WordPress +// +// Created by Jeffrey Vanneste on 2013-01-05. +// Copyright (c) 2013 WordPress. All rights reserved. +// + +#import +#import +#import "WordPressAppDelegate.h" +#import "Media.h" +#import "UITableViewActivityCell.h" +#import "WPPopoverBackgroundView.h" +#import "MediaSettings.h" + +@interface MediaSettingsViewController : UIViewController { + Media *media; + NSArray *linkToOptionsList, *positioningOptionsList, *alignmentOptionsList; + BOOL isShowingKeyboard; + + UIPickerView *pickerView; + UIToolbar *toolbar; + UIActionSheet *currentActionSheet; + UIActionSheet *actionSheet; + UIView *footerView; + UIButton *deleteButton; + IBOutlet UIBarButtonItem *cancelButton; + UIPopoverController *popover; + + IBOutlet UITableView *tableView; + IBOutlet UITableViewCell *linkToTableViewCell, *captionTableViewCell, *widthTableViewCell, *alignmentTableViewCell, *positioningTableViewCell, *mediaTableViewCell; + IBOutlet UILabel *linkToLabel, *alignmentLabel, *positioningLabel, *imageSizeLabel, + *linkToTitleLabel, *captionTitleLabel, *widthTitleLabel, *alignmentTitleLabel, *positioningTitleLabel; + IBOutlet UIImageView *thumbnail; + IBOutlet UITextField *captionTextField; + IBOutlet UISlider *widthSlider; +} + +@property (nonatomic, strong) Media *media; +@property (nonatomic, strong) MediaSettings *mediaSettings; + +@end diff --git a/WordPress/Classes/MediaSettingsViewController.m b/WordPress/Classes/MediaSettingsViewController.m new file mode 100755 index 000000000000..8b2317197b1d --- /dev/null +++ b/WordPress/Classes/MediaSettingsViewController.m @@ -0,0 +1,643 @@ +// +// MediaSettingsViewController.m +// WordPress +// +// Created by Jeffrey Vanneste on 2013-01-05. +// Copyright (c) 2013 WordPress. All rights reserved. +// + +#import "MediaSettingsViewController.h" + + +#define TAG_PICKER_LINK_TO 0 +#define TAG_PICKER_ALIGNMENT 1 +#define TAG_PICKER_POSITIONING 2 + +@implementation MediaSettingsViewController + +@synthesize media; +@synthesize mediaSettings; + +- (void)viewDidLoad { + [super viewDidLoad]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; + + // fill the lists with the available options + linkToOptionsList = [NSArray arrayWithObjects: + NSLocalizedString(@"No Linking", @"Media Settings option to have media have no link"), + NSLocalizedString(@"Media File", @"Media Settings option to have media link to the file"), + NSLocalizedString(@"Current", @"Media Settings option to leave the media alone"), nil]; + positioningOptionsList = [NSArray arrayWithObjects: + NSLocalizedString(@"Current", @"Media Settings option to leave the media alone"), + NSLocalizedString(@"Above Content", @"Media Settings option to move media above the content"), + NSLocalizedString(@"Below Content", @"Media Settings option to move media below the content"), nil]; + alignmentOptionsList = [NSArray arrayWithObjects: + NSLocalizedString(@"None", @"Media Settings option to have no alignment"), + NSLocalizedString(@"Left", @"Media Settings option to align the media to left"), + NSLocalizedString(@"Center", @"Media Settings option to align the media to center"), + NSLocalizedString(@"Right", @"Media Settings option to align the media to right"), nil]; + + if (mediaSettings.captionText != nil) { + captionTextField.text = mediaSettings.captionText; + } else { + captionTextField.text = @""; + } + if (mediaSettings.linkHref!= nil) { + if ([mediaSettings.linkHref caseInsensitiveCompare:media.remoteURL] == NSOrderedSame) { + linkToLabel.text = [linkToOptionsList objectAtIndex:1]; + } else if ([mediaSettings.linkHref length] > 0) { + linkToLabel.text = [linkToOptionsList objectAtIndex:2]; + } else { + linkToLabel.text = [linkToOptionsList objectAtIndex:0]; + } + } else { + linkToLabel.text = [linkToOptionsList objectAtIndex:0]; + } + if (mediaSettings.alignment != nil) { + if ([mediaSettings.alignment isEqualToString:@"alignleft"]) { + alignmentLabel.text = [alignmentOptionsList objectAtIndex:1]; + } else if ([mediaSettings.alignment isEqualToString:@"aligncenter"]) { + alignmentLabel.text = [alignmentOptionsList objectAtIndex:2]; + } else if ([mediaSettings.alignment isEqualToString:@"alignright"]) { + alignmentLabel.text = [alignmentOptionsList objectAtIndex:3]; + } else { + alignmentLabel.text = [alignmentOptionsList objectAtIndex:0]; + } + } else { + alignmentLabel.text = [alignmentOptionsList objectAtIndex:0]; + } + positioningLabel.text = [positioningOptionsList objectAtIndex:0]; + + widthSlider.minimumValue = 0; + widthSlider.maximumValue = [media.width intValue]; + if (mediaSettings.customWidth != nil) { + int customWidth = [mediaSettings.customWidth intValue]; + if (customWidth > widthSlider.maximumValue) { + widthSlider.maximumValue = customWidth; + } + int customHeight = customWidth * [media.height intValue]/[media.width intValue]; + imageSizeLabel.text = [NSString stringWithFormat:@"%d x %d", customWidth, customHeight]; + widthSlider.value = customWidth; + } else { + imageSizeLabel.text = [NSString stringWithFormat:@"%d x %d", [media.width intValue], [media.height intValue]]; + widthSlider.value = [media.width intValue]; + } + + [tableView setBackgroundView:nil]; + [tableView setBackgroundColor:[UIColor clearColor]]; //Fix for black corners on iOS4. http://stackoverflow.com/questions/1557856/black-corners-on-uitableview-group-style + self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"settings_bg"]]; + + linkToTitleLabel.text = NSLocalizedString(@"Link to", @"Media Settings for what an image/view should link to"); + positioningTitleLabel.text = NSLocalizedString(@"Position", @"Media Settings for where an image/view should be positioned"); + alignmentTitleLabel.text = NSLocalizedString(@"Alignment", @"Media Settings for where an image/view should be aligned"); + captionTitleLabel.text = NSLocalizedString(@"Caption", @"Media Settings for the caption of an image/view"); + widthTitleLabel.text = NSLocalizedString(@"Width", @"Media Settings for the width of image/video"); + captionTextField.placeholder = NSLocalizedString(@"Optional", @"Media Settings for the optional caption"); + + // only supporting images right now + if ([media.mediaType isEqualToString:@"image"]) { + thumbnail.image = [UIImage imageWithContentsOfFile:media.localURL]; + if((thumbnail.image == nil) && (media.remoteURL != nil)) { + [thumbnail setImageWithURL:[NSURL URLWithString:media.remoteURL]]; + } + self.navigationItem.title = NSLocalizedString(@"Image", @""); + } + + isShowingKeyboard = NO; + + CGRect pickerFrame; + if (IS_IPAD) + pickerFrame = CGRectMake(0.0f, 0.0f, 320.0f, 216.0f); + else + pickerFrame = CGRectMake(0.0f, 44.0f, 320.0f, 216.0f); + pickerView = [[UIPickerView alloc] initWithFrame:pickerFrame]; + pickerView.delegate = self; + pickerView.dataSource = self; + pickerView.showsSelectionIndicator = YES; + + // on the ipad we want to show a Close button in the toolbar since the back button will not be there + if (IS_IPAD) { + cancelButton.title = NSLocalizedString(@"Close", @"Close an action sheet");; + CGRect rect = tableView.frame; + rect.origin.y = 44.0f; + rect.size.height = rect.size.height - 44.0f; + tableView.frame = rect; + + UIToolbar *topToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, 44.0f)]; + topToolbar.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth; + UIBarButtonItem *flex = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; + topToolbar.items = [NSArray arrayWithObjects:flex, cancelButton, nil]; + [self.view addSubview:topToolbar]; + } +} + +- (void)viewDidUnload { + [super viewDidUnload]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + [linkToTableViewCell becomeFirstResponder]; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; +} + +#pragma mark - +#pragma mark Misc Methods +- (void)deleteObject:(id)sender { + // On ipad show an alert view like how Apple does in the contacts app. On the iPhone show an action sheet. + if (IS_IPAD) { + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:NSLocalizedString(@"Remove %@?", @""), media.mediaTypeName] message:@"" delegate:self cancelButtonTitle:NSLocalizedString(@"Cancel", @"") otherButtonTitles:nil]; + [alert addButtonWithTitle:NSLocalizedString(@"Remove", @"")]; + [alert show]; + } else { + NSString *titleString = [NSString stringWithFormat:NSLocalizedString(@"Remove %@?", @""), media.mediaTypeName]; + UIActionSheet *deleteActionSheet = [[UIActionSheet alloc] initWithTitle:titleString + delegate:self + cancelButtonTitle:NSLocalizedString(@"Cancel", @"") + destructiveButtonTitle:NSLocalizedString(@"Remove", @"") + otherButtonTitles:nil]; + + [deleteActionSheet showInView:self.view]; + } +} + +- (void)reloadData { + [tableView reloadData]; +} + + +#pragma mark - +#pragma mark TableView Methods +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + NSInteger sections = 1; + return sections; +} + +- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + switch (indexPath.section) { + case 0: + switch (indexPath.row) { + case 0: // media + mediaTableViewCell.selectionStyle = UITableViewCellSelectionStyleNone; + return mediaTableViewCell; + break; + case 1: // caption + captionTableViewCell.selectionStyle = UITableViewCellSelectionStyleNone; + return captionTableViewCell; + break; + case 2: // link to + linkToTableViewCell.selectionStyle = UITableViewCellSelectionStyleNone; + return linkToTableViewCell; + break; + case 3: // alignment + alignmentTableViewCell.selectionStyle = UITableViewCellSelectionStyleNone; + return alignmentTableViewCell; + break; + case 4: // positioning + positioningTableViewCell.selectionStyle = UITableViewCellSelectionStyleNone; + return positioningTableViewCell; + break; + case 5: // width + widthTableViewCell.selectionStyle = UITableViewCellSelectionStyleNone; + return widthTableViewCell; + break; + default: + break; + } + break; + } + + return nil; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + if ((indexPath.section == 0) && (indexPath.row == 5)) { + // width row + return 70.0f; + } else if ((indexPath.section == 0) && (indexPath.row == 0)) { + // thumbnail row + return 188.0f; + } + else { + return 44.0f; + } +} + +- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { + return 70; +} + +- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { + + if(footerView == nil) { + footerView = [[UIView alloc] init]; + + // create a glossy red button + UIImage *image = [[UIImage imageNamed:@"button_red.png"] + stretchableImageWithLeftCapWidth:8 topCapHeight:8]; + deleteButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + [deleteButton setBackgroundImage:image forState:UIControlStateNormal]; + + if (IS_IPAD) { + [deleteButton setFrame:CGRectMake(30, 20, 480, 44)]; + } + else { + [deleteButton setFrame:CGRectMake(10, 20, 300, 44)]; + } + + [deleteButton setTitle:[NSString stringWithFormat:NSLocalizedString(@"Remove %@", @""), media.mediaTypeName] forState:UIControlStateNormal]; + [deleteButton.titleLabel setFont:[UIFont boldSystemFontOfSize:20]]; + [deleteButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [deleteButton addTarget:self action:@selector(deleteObject:) + forControlEvents:UIControlEventTouchUpInside]; + [footerView addSubview:deleteButton]; + } + + return footerView; +} + + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + if (section == 0) { + return 6; + } + return 0; +} + +- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + if (isShowingKeyboard) { + [captionTextField resignFirstResponder]; + } + + switch (indexPath.section) { + case 0: + switch (indexPath.row) { + case 2: + { + pickerView.tag = TAG_PICKER_LINK_TO; + [pickerView reloadAllComponents]; + [pickerView selectRow:[linkToOptionsList indexOfObject:linkToLabel.text] inComponent:0 animated:NO]; + [self showPicker:pickerView]; + break; + } + case 3: + { + pickerView.tag = TAG_PICKER_ALIGNMENT; + [pickerView reloadAllComponents]; + [pickerView selectRow:[alignmentOptionsList indexOfObject:alignmentLabel.text] inComponent:0 animated:NO]; + [self showPicker:pickerView]; + break; + } + case 4: + { + pickerView.tag = TAG_PICKER_POSITIONING; + [pickerView reloadAllComponents]; + [pickerView selectRow:[positioningOptionsList indexOfObject:positioningLabel.text] inComponent:0 animated:NO]; + [self showPicker:pickerView]; + break; + } + + default: + break; + } + break; + } + [aTableView deselectRowAtIndexPath:[tableView indexPathForSelectedRow] animated:YES]; +} + +#pragma mark - +#pragma mark UIPickerViewDataSource + +- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { + return 1; +} + +- (NSInteger)pickerView:(UIPickerView *)aPickerView numberOfRowsInComponent:(NSInteger)component { + if (aPickerView.tag == TAG_PICKER_LINK_TO) { + return [linkToOptionsList count]; + } else if (aPickerView.tag == TAG_PICKER_ALIGNMENT) { + return [alignmentOptionsList count]; + } else if (aPickerView.tag == TAG_PICKER_POSITIONING) { + return [positioningOptionsList count]; + } + return 0; +} + +#pragma mark - +#pragma mark UIPickerViewDelegate + +- (NSString *)pickerView:(UIPickerView *)aPickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { + if (aPickerView.tag == TAG_PICKER_LINK_TO) { + return [linkToOptionsList objectAtIndex:row]; + } else if (aPickerView.tag == TAG_PICKER_ALIGNMENT) { + return [alignmentOptionsList objectAtIndex:row]; + } else if (aPickerView.tag == TAG_PICKER_POSITIONING) { + return [positioningOptionsList objectAtIndex:row]; + } + + return @""; +} + +- (void)pickerView:(UIPickerView *)aPickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { + NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:media, @"media", mediaSettings, @"mediaSettings", nil]; + if (aPickerView.tag == TAG_PICKER_POSITIONING) { + positioningLabel.text = [positioningOptionsList objectAtIndex:row]; + if (row == 1) { + [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldInsertMediaAbove" object:self userInfo:userInfo]; + } else if (row == 2) { + [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldInsertMediaBelow" object:self userInfo:userInfo]; + } + } else { + if (aPickerView.tag == TAG_PICKER_LINK_TO) { + linkToLabel.text = [linkToOptionsList objectAtIndex:row]; + if (row == 0) { + mediaSettings.linkHref = @""; + } else if (row == 1){ + mediaSettings.linkHref = media.remoteURL; + } // else leave the linkHref alone + } else if (aPickerView.tag == TAG_PICKER_ALIGNMENT) { + alignmentLabel.text = [alignmentOptionsList objectAtIndex:row]; + if (row == 0) { + mediaSettings.alignment = @"alignnone"; + } else if (row == 1) { + mediaSettings.alignment = @"alignleft"; + } else if (row == 2) { + mediaSettings.alignment = @"aligncenter"; + } else if (row == 3) { + mediaSettings.alignment = @"alignright"; + } + } + [[NSNotificationCenter defaultCenter] + postNotificationName:@"UpdateMedia" + object:self + userInfo:userInfo]; + } + + [tableView reloadData]; +} + +#pragma mark - +#pragma mark Pickers and keyboard animations + +- (void)showPicker:(UIView *)picker { + if (isShowingKeyboard) { + [captionTextField resignFirstResponder]; + } + + if (IS_IPAD) { + UIViewController *fakeController = [[UIViewController alloc] init]; + fakeController.contentSizeForViewInPopover = CGSizeMake(320.0f, 216.0f); + + [fakeController.view addSubview:picker]; + popover = [[UIPopoverController alloc] initWithContentViewController:fakeController]; + if ([popover respondsToSelector:@selector(popoverBackgroundViewClass)]) { + popover.popoverBackgroundViewClass = [WPPopoverBackgroundView class]; + } + + CGRect popoverRect; + if (picker.tag == TAG_PICKER_LINK_TO) + popoverRect = [self.view convertRect:linkToLabel.frame fromView:[linkToLabel superview]]; + else if (picker.tag == TAG_PICKER_ALIGNMENT) + popoverRect = [self.view convertRect:alignmentLabel.frame fromView:[alignmentLabel superview]]; + else if (picker.tag == TAG_PICKER_POSITIONING) + popoverRect = [self.view convertRect:positioningLabel.frame fromView:[positioningLabel superview]]; + + popoverRect.size.width = 100.0f; + [popover presentPopoverFromRect:popoverRect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; + + } else { + + CGFloat width = self.view.frame.size.width; + CGFloat height = 0.0; + + // Refactor this class to not use UIActionSheets for display. See trac #1509. + // Shoehorning a UIPicker inside a UIActionSheet is just madness. + // For now, hardcoding height values for the iPhone so we don't get + // a funky gap at the bottom of the screen on the iPhone 5. + if(self.view.frame.size.height <= 416.0f) { + height = 490.0f; + } else { + height = 500.0f; + } + if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation)){ + height = 460.0f; // Show most of the actionsheet but keep the top of the view visible. + } + + UIView *pickerWrapperView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, width, 260.0f)]; // 216 + 44 (height of the picker and the "tooblar") + pickerWrapperView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; + [pickerWrapperView addSubview:picker]; + + CGRect pickerFrame = picker.frame; + pickerFrame.size.width = width; + picker.frame = pickerFrame; + + actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:nil cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil]; + [actionSheet setActionSheetStyle:UIActionSheetStyleAutomatic]; + [actionSheet setBounds:CGRectMake(0.0f, 0.0f, width, height)]; + + [actionSheet addSubview:pickerWrapperView]; + + UISegmentedControl *closeButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:NSLocalizedString(@"Done", @"Default main action button for closing/finishing a work flow in the app (used in Comments>Edit, Comment edits and replies, post editor body text, etc, to dismiss keyboard).")]]; + closeButton.momentary = YES; + CGFloat x = self.view.frame.size.width - 60.0f; + closeButton.frame = CGRectMake(x, 7.0f, 50.0f, 30.0f); + closeButton.segmentedControlStyle = UISegmentedControlStyleBar; + if ([closeButton respondsToSelector:@selector(setTintColor:)]) { + closeButton.tintColor = [UIColor blackColor]; + } + [closeButton addTarget:self action:@selector(hidePicker) forControlEvents:UIControlEventValueChanged]; + closeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin; + [pickerWrapperView addSubview:closeButton]; + + UISegmentedControl *publishNowButton = nil; + + if ([[UISegmentedControl class] respondsToSelector:@selector(appearance)]) { + // Since we're requiring a black tint we do not want to use the custom text colors. + NSDictionary *titleTextAttributesForStateNormal = [NSDictionary dictionaryWithObjectsAndKeys: + [UIColor whiteColor], + UITextAttributeTextColor, + [UIColor darkGrayColor], + UITextAttributeTextShadowColor, + [NSValue valueWithUIOffset:UIOffsetMake(0, 1)], + UITextAttributeTextShadowOffset, + nil]; + + // The UISegmentControl does not show a pressed state for its button so (for now) use the same + // state for normal and highlighted. + // It would be nice to refactor this to use a toolbar and buttons instead of a segmented control to get the + // correct look and feel. + [closeButton setTitleTextAttributes:titleTextAttributesForStateNormal forState:UIControlStateNormal]; + [closeButton setTitleTextAttributes:titleTextAttributesForStateNormal forState:UIControlStateHighlighted]; + + if (publishNowButton) { + [publishNowButton setTitleTextAttributes:titleTextAttributesForStateNormal forState:UIControlStateNormal]; + [publishNowButton setTitleTextAttributes:titleTextAttributesForStateNormal forState:UIControlStateHighlighted]; + } + } + + [actionSheet showInView:self.view]; + [actionSheet setBounds:CGRectMake(0.0f, 0.0f, width, height)]; // Update the bounds again now that its in the view else it won't draw correctly. + } +} + +- (void)hidePicker { + [actionSheet dismissWithClickedButtonIndex:0 animated:YES]; + actionSheet = nil; +} + +- (void)keyboardWillShow:(NSNotification *)keyboardInfo { + if(IS_IPAD == NO) { + // on iphone it's possible we need to scroll the tableview when the keyboard is shown + if (isShowingKeyboard) { + return; + } + + NSDictionary* userInfo = [keyboardInfo userInfo]; + + // get the size of the keyboard + CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; + + // resize the tableview + CGRect viewFrame = tableView.frame; + viewFrame.size.height -= keyboardSize.height; + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationBeginsFromCurrentState:YES]; + [UIView setAnimationDuration:0.3f]; + [tableView setFrame:viewFrame]; + + // scroll the view if the caption textfield is not visible + if (tableView.contentOffset.y <= 100) { + tableView.contentOffset = CGPointMake(0, 100); + } + [UIView commitAnimations]; + } + isShowingKeyboard = YES; +} + +- (void)keyboardWillHide:(NSNotification *)keyboardInfo { + if(IS_IPAD == NO) { + NSDictionary* userInfo = [keyboardInfo userInfo]; + + // get the size of the keyboard + CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; + + // resize the tableview + CGRect viewFrame = tableView.frame; + viewFrame.size.height += keyboardSize.height; + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationBeginsFromCurrentState:YES]; + [UIView setAnimationDuration:0.3f]; + [tableView setFrame:viewFrame]; + [UIView commitAnimations]; + } + + isShowingKeyboard = NO; +} + +#pragma mark - +#pragma mark Rotation Methods + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + return [super shouldAutorotateToInterfaceOrientation:interfaceOrientation]; +} + +- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { + [self reloadData]; +} + +#pragma mark - +#pragma mark Slider Methods +-(IBAction) sliderChanged:(id) sender{ + UISlider *slider = (UISlider *) sender; + // step by 10s + float newStep = roundf((slider.value) / 10.0f); + slider.value = newStep * 10.0f; + if (slider.value + 10 > slider.maximumValue) { + slider.value = slider.maximumValue; + } + int width = (int)slider.value; + int height = width * [media.height intValue]/[media.width intValue]; + imageSizeLabel.text = [NSString stringWithFormat:@"%d x %d", width, height]; + NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:media, @"media", mediaSettings, @"mediaSettings", nil]; + mediaSettings.customWidth = [NSNumber numberWithInt:width]; + mediaSettings.customHeight = [NSNumber numberWithInt:height]; + [[NSNotificationCenter defaultCenter] + postNotificationName:@"UpdateMedia" + object:self + userInfo:userInfo]; +} + +#pragma mark - +#pragma mark TextField Methods + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + [captionTextField resignFirstResponder]; + return YES; +} + +- (void)textFieldDidBeginEditing:(UITextField *)textField { + captionTextField.placeholder = nil; +} + +- (IBAction)textFieldReturn:(id)sender { + [sender resignFirstResponder]; +} + +- (IBAction)textFieldFinishedEditing:(id)sender { + NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:media, @"media", mediaSettings, @"mediaSettings", nil]; + mediaSettings.captionText = captionTextField.text; + [[NSNotificationCenter defaultCenter] + postNotificationName:@"UpdateMedia" + object:self + userInfo:userInfo]; +} + +- (IBAction)backgroundTouched:(id)sender { + [captionTextField resignFirstResponder]; +} + +#pragma mark - +#pragma mark UIActionSheet delegate + +- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { + switch (buttonIndex) { + case 0: + [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldRemoveMedia" object:media]; + [media remove]; + if(IS_IPAD == YES) + [self dismissModalViewControllerAnimated:YES]; + else + [self.navigationController popViewControllerAnimated:YES]; + break; + default: + break; + } +} + +#pragma mark - +#pragma mark Cancel button actions + +- (IBAction)cancelSelection:(id)sender { + if (IS_IPAD) + [self dismissModalViewControllerAnimated:YES]; +} + +#pragma mark - +#pragma mark UIAlertViewDelegate delegate +- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { + if (buttonIndex == 1) { + [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldRemoveMedia" object:media]; + [media remove]; + [self dismissModalViewControllerAnimated:YES]; + } +} + +@end diff --git a/WordPress/Classes/PostMediaViewController.h b/WordPress/Classes/PostMediaViewController.h old mode 100644 new mode 100755 index a9538a2a8f27..7785f68d39c2 --- a/WordPress/Classes/PostMediaViewController.h +++ b/WordPress/Classes/PostMediaViewController.h @@ -15,6 +15,8 @@ #import "UIImage+Resize.h" #import "WordPressAppDelegate.h" #import "MediaObjectViewController.h" +#import "MediaSettingsViewController.h" +#import "MediaSettings.h" typedef void (^ALAssetsLibraryAssetForURLResultBlock)(ALAsset *asset); typedef void (^ALAssetsLibraryAccessFailureBlock)(NSError *error); diff --git a/WordPress/Classes/PostMediaViewController.m b/WordPress/Classes/PostMediaViewController.m old mode 100644 new mode 100755 index 7ef01d7ed34a..58f5405ed040 --- a/WordPress/Classes/PostMediaViewController.m +++ b/WordPress/Classes/PostMediaViewController.m @@ -231,7 +231,8 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath NSLog(@"Media deleted while uploading (%@)", media); return; } - [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldInsertMediaBelow" object:media]; + NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:media, @"media", [[MediaSettings alloc] init], @"mediaSettings", nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldInsertMediaBelow" object:self userInfo:userInfo]; [media save]; } failure:nil]; } else if (media.remoteStatus == MediaRemoteStatusPushing) { @@ -239,9 +240,20 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath } else if (media.remoteStatus == MediaRemoteStatusProcessing) { // Do nothing. See trac #1508 } else { - MediaObjectViewController *mediaView = [[MediaObjectViewController alloc] initWithNibName:@"MediaObjectView" bundle:nil]; - [mediaView setMedia:media]; - + // for images use the new media settings view + UIViewController *mediaView; + if ([media.mediaType isEqualToString:@"image"]) { + MediaSettingsViewController *tempMediaView = [[MediaSettingsViewController alloc] initWithNibName:@"MediaSettingsViewController" bundle:nil]; + [tempMediaView setMedia:media]; + MediaSettings *mediaSettings = [MediaSettings createMediaSettingsForUrl:media.remoteURL content:postDetailViewController.apost.content]; + [tempMediaView setMediaSettings:mediaSettings]; + mediaView = tempMediaView; + } else { + MediaObjectViewController *tempMediaView = [[MediaObjectViewController alloc] initWithNibName:@"MediaObjectView" bundle:nil]; + [tempMediaView setMedia:media]; + mediaView = tempMediaView; + } + if(IS_IPAD == YES) { mediaView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; mediaView.modalPresentationStyle = UIModalPresentationFormSheet; @@ -1347,7 +1359,8 @@ - (void)useImage:(UIImage *)theImage { return; } if (!isPickingFeaturedImage) { - [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldInsertMediaBelow" object:imageMedia]; + NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:imageMedia, @"media", [[MediaSettings alloc] init], @"mediaSettings", nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldInsertMediaBelow" object:self userInfo:userInfo]; } else { @@ -1442,7 +1455,8 @@ - (void)useVideo:(NSString *)videoURL { NSLog(@"Media deleted while uploading (%@)", videoMedia); return; } - [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldInsertMediaBelow" object:videoMedia]; + NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:videoMedia, @"media", [[MediaSettings alloc] init], @"mediaSettings", nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldInsertMediaBelow" object:self userInfo:userInfo]; [videoMedia save]; } failure:nil]; isAddingMedia = NO; @@ -1484,7 +1498,8 @@ - (void)mediaDidUploadSuccessfully:(NSNotification *)notification { NSLog(@"Media deleted while uploading (%@)", media); return; } - [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldInsertMediaBelow" object:media]; + NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:media, @"media", [[MediaSettings alloc] init], @"mediaSettings", nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"ShouldInsertMediaBelow" object:self userInfo:userInfo]; [media save]; self.isAddingMedia = NO; } diff --git a/WordPress/Resources/Images/button_red.png b/WordPress/Resources/Images/button_red.png new file mode 100755 index 0000000000000000000000000000000000000000..a77d5a27654174b51facbc2a9c774e49dfb365b7 GIT binary patch literal 2363 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 literal 0 HcmV?d00001 diff --git a/WordPress/Resources/Images/button_red@2x.png b/WordPress/Resources/Images/button_red@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..e90738d862df21d0ac05b6486bd17347eeaaf1b3 GIT binary patch literal 3516 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 + + + 784 + 12C3006 + 2840 + 1187.34 + 625.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 1926 + + + IBProxyObject + IBUIBarButtonItem + IBUIImageView + IBUILabel + IBUISlider + IBUITableView + IBUITableViewCell + IBUITextField + IBUIView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + + + + 274 + {320, 372} + + + + 3 + MCAwAA + + NO + YES + NO + IBCocoaTouchFramework + 1 + 1 + 0 + YES + 44 + 15 + 10 + + + {{0, 64}, {320, 372}} + + + + + 3 + MQA + + NO + + + NO + + + IBCocoaTouchFramework + + + + 292 + + + + 256 + + + + 292 + {{8, 11}, {57, 21}} + + + + NO + YES + NO + IBCocoaTouchFramework + Link to + + 1 + MCAwIDAAA + darkTextColor + + + 1 + 10 + + Helvetica-Bold + Helvetica + 2 + 17 + + + Helvetica-Bold + 17 + 16 + + + + + 290 + {{94, 11}, {206, 21}} + + + NO + YES + 7 + NO + IBCocoaTouchFramework + Media File + + + 1 + 10 + + 1 + 17 + + + Helvetica + 17 + 16 + + + + {320, 43} + + + + + NO + YES + 4 + YES + IBCocoaTouchFramework + + + {320, 44} + + + + + 1 + MSAxIDEAA + + IBCocoaTouchFramework + + + + + 292 + + + + 256 + + + + 293 + {{20, 12}, {280, 163}} + + + _NS:9 + 1 + NO + IBCocoaTouchFramework + + + {320, 187} + + + + _NS:11 + + NO + YES + 4 + YES + IBCocoaTouchFramework + + + {320, 188} + + + + _NS:9 + IBCocoaTouchFramework + + + + + 292 + + + + 256 + + + + 292 + {{8, 11}, {84, 21}} + + + + NO + YES + NO + IBCocoaTouchFramework + Alignment + + + 1 + 10 + + + + + + 290 + {{94, 11}, {206, 21}} + + + NO + YES + 7 + NO + IBCocoaTouchFramework + None + + + 1 + 10 + + + + + {320, 43} + + + + + NO + YES + 4 + YES + IBCocoaTouchFramework + + + {320, 44} + + + + + IBCocoaTouchFramework + + + + + 292 + + + + 256 + + + + 292 + {{8, 11}, {93, 21}} + + + + NO + YES + NO + IBCocoaTouchFramework + Positioning + + + 1 + 10 + + + + + + 290 + {{94, 11}, {206, 21}} + + + NO + YES + 7 + NO + IBCocoaTouchFramework + Above Content + + + 1 + 10 + + + + + {320, 43} + + + + + NO + YES + 4 + YES + IBCocoaTouchFramework + + + {320, 44} + + + + + IBCocoaTouchFramework + + + + + 292 + + + + 256 + + + + 292 + {{8, 11}, {64, 21}} + + + + NO + YES + NO + IBCocoaTouchFramework + Caption + + + 1 + 10 + + + + + + 290 + {{94, 7}, {206, 30}} + + + _NS:9 + NO + YES + IBCocoaTouchFramework + 0 + + 3 + + 3 + MAA + + 2 + + + YES + 17 + + IBCocoaTouchFramework + + + 1 + 14 + + + Helvetica + 14 + 16 + + + + {320, 43} + + + + + NO + YES + 4 + YES + IBCocoaTouchFramework + + + {320, 44} + + + + + IBCocoaTouchFramework + + + + + 292 + + + + 256 + + + + 292 + {{8, 11}, {48, 21}} + + + + NO + YES + NO + IBCocoaTouchFramework + Width + + + 1 + 10 + + + + + + 290 + {{94, 11}, {206, 23}} + + + + _NS:9 + NO + IBCocoaTouchFramework + 0 + 0 + 500 + 10 + 1000 + + + + 292 + {{96, 41}, {206, 21}} + + + NO + YES + 7 + NO + IBCocoaTouchFramework + Image Size + + + 1 + 10 + + + + + {320, 78} + + + + + NO + YES + 4 + YES + IBCocoaTouchFramework + + + {320, 79} + + + + + IBCocoaTouchFramework + + + + + Item + IBCocoaTouchFramework + 1 + + + + + + + view + + + + 128 + + + + tableView + + + + 254 + + + + linkToLabel + + + + 276 + + + + linkToTitleLabel + + + + 277 + + + + linkToTableViewCell + + + + 278 + + + + captionTableViewCell + + + + 294 + + + + captionTitleLabel + + + + 295 + + + + captionTextField + + + + 296 + + + + widthTitleLabel + + + + 298 + + + + widthTableViewCell + + + + 299 + + + + widthSlider + + + + 300 + + + + positioningTableViewCell + + + + 301 + + + + positioningTitleLabel + + + + 302 + + + + positioningLabel + + + + 303 + + + + alignmentTableViewCell + + + + 304 + + + + alignmentTitleLabel + + + + 305 + + + + alignmentLabel + + + + 306 + + + + thumbnail + + + + 307 + + + + imageSizeLabel + + + + 310 + + + + mediaTableViewCell + + + + 313 + + + + cancelButton + + + + 316 + + + + backgroundTouched: + + + 1 + + 312 + + + + dataSource + + + + 8 + + + + delegate + + + + 9 + + + + textFieldReturn: + + + 20 + + 311 + + + + textFieldFinishedEditing: + + + 19 + + 314 + + + + sliderChanged: + + + 13 + + 309 + + + + cancelSelection: + + + + 317 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 2 + + + + + + + + 6 + + + + + + 223 + + + + + + + Link to + + + 226 + + + + + 227 + + + + + 263 + + + + + + Thumbnail + + + 266 + + + + + 279 + + + + + + + Alignment + + + 280 + + + + + 281 + + + + + 282 + + + + + + + Positioning + + + 284 + + + + + 283 + + + + + 285 + + + + + + + Caption + + + 287 + + + + + 288 + + + + + 289 + + + + + + + + Width + + + 291 + + + + + 292 + + + + + 308 + + + + + 315 + + + + + + + MediaSettingsViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIControl + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 317 + + + + + MediaSettingsViewController + UIViewController + + cancelSelection: + id + + + cancelSelection: + + cancelSelection: + id + + + + UILabel + UITableViewCell + UILabel + UIBarButtonItem + UITableViewCell + UITextField + UILabel + UILabel + UILabel + UITableViewCell + UILabel + UITableViewCell + UILabel + UITableViewCell + UILabel + UITableView + UIImageView + UISlider + UITableViewCell + UILabel + + + + alignmentLabel + UILabel + + + alignmentTableViewCell + UITableViewCell + + + alignmentTitleLabel + UILabel + + + cancelButton + UIBarButtonItem + + + captionTableViewCell + UITableViewCell + + + captionTextField + UITextField + + + captionTitleLabel + UILabel + + + imageSizeLabel + UILabel + + + linkToLabel + UILabel + + + linkToTableViewCell + UITableViewCell + + + linkToTitleLabel + UILabel + + + mediaTableViewCell + UITableViewCell + + + positioningLabel + UILabel + + + positioningTableViewCell + UITableViewCell + + + positioningTitleLabel + UILabel + + + tableView + UITableView + + + thumbnail + UIImageView + + + widthSlider + UISlider + + + widthTableViewCell + UITableViewCell + + + widthTitleLabel + UILabel + + + + IBProjectSource + ./Classes/MediaSettingsViewController.h + + + + + 0 + IBCocoaTouchFramework + + com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS + + + + com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS + + + YES + 3 + 1926 + + diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 158db8a7bbbd..e9e91c55f191 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -7,6 +7,13 @@ objects = { /* Begin PBXBuildFile section */ + 00C0D2581718AB1C00E2B95D /* button_red.png in Resources */ = {isa = PBXBuildFile; fileRef = 00C0D2561718AB1C00E2B95D /* button_red.png */; }; + 00C0D2591718AB1C00E2B95D /* button_red@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 00C0D2571718AB1C00E2B95D /* button_red@2x.png */; }; + 00C0D25B1718AB4B00E2B95D /* MediaSettingsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 00C0D25A1718AB4B00E2B95D /* MediaSettingsViewController.xib */; }; + 00C0D25E1718AB6300E2B95D /* MediaSettingsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00C0D25D1718AB6300E2B95D /* MediaSettingsTests.m */; }; + 00C0D2611718AB9C00E2B95D /* MediaSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 00C0D2601718AB9C00E2B95D /* MediaSettingsViewController.m */; }; + 00C0D2641718ABCC00E2B95D /* MediaSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 00C0D2631718ABCC00E2B95D /* MediaSettings.m */; }; + 00C0D2651718ABCC00E2B95D /* MediaSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 00C0D2631718ABCC00E2B95D /* MediaSettings.m */; }; 00F2E3F8166EEF9800D0527C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 834CE7371256D0F60046A4A3 /* CoreGraphics.framework */; }; 00F2E3FA166EEFBE00D0527C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E10B3653158F2D4500419A93 /* UIKit.framework */; }; 00F2E3FB166EEFE100D0527C /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E10B3651158F2D3F00419A93 /* QuartzCore.framework */; }; @@ -721,6 +728,15 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 00C0D2561718AB1C00E2B95D /* button_red.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = button_red.png; path = Resources/Images/button_red.png; sourceTree = ""; }; + 00C0D2571718AB1C00E2B95D /* button_red@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "button_red@2x.png"; path = "Resources/Images/button_red@2x.png"; sourceTree = ""; }; + 00C0D25A1718AB4B00E2B95D /* MediaSettingsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = MediaSettingsViewController.xib; path = Resources/MediaSettingsViewController.xib; sourceTree = ""; }; + 00C0D25C1718AB6300E2B95D /* MediaSettingsTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaSettingsTests.h; sourceTree = ""; }; + 00C0D25D1718AB6300E2B95D /* MediaSettingsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MediaSettingsTests.m; sourceTree = ""; }; + 00C0D25F1718AB9C00E2B95D /* MediaSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaSettingsViewController.h; sourceTree = ""; }; + 00C0D2601718AB9C00E2B95D /* MediaSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MediaSettingsViewController.m; sourceTree = ""; }; + 00C0D2621718ABCC00E2B95D /* MediaSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaSettings.h; sourceTree = ""; }; + 00C0D2631718ABCC00E2B95D /* MediaSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MediaSettings.m; sourceTree = ""; }; 031663050FFB151A0045D052 /* PostTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PostTableViewCell.h; sourceTree = ""; }; 031663060FFB151A0045D052 /* PostTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PostTableViewCell.m; sourceTree = ""; }; 031666AC0FFC3E130045D052 /* CommentTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommentTableViewCell.h; sourceTree = ""; }; @@ -2262,6 +2278,7 @@ 83290399120CF517000A965A /* Media */ = { isa = PBXGroup; children = ( + 00C0D25A1718AB4B00E2B95D /* MediaSettingsViewController.xib */, 83CAD4201235F9F4003DFA20 /* MediaObjectView.xib */, 8383178712270E980047B476 /* PostMediaViewController.xib */, ); @@ -2282,6 +2299,10 @@ 83CAD4191235F823003DFA20 /* Media */ = { isa = PBXGroup; children = ( + 00C0D2621718ABCC00E2B95D /* MediaSettings.h */, + 00C0D2631718ABCC00E2B95D /* MediaSettings.m */, + 00C0D25F1718AB9C00E2B95D /* MediaSettingsViewController.h */, + 00C0D2601718AB9C00E2B95D /* MediaSettingsViewController.m */, 8383178512270E980047B476 /* PostMediaViewController.h */, 8383178612270E980047B476 /* PostMediaViewController.m */, 83CAD41A1235F854003DFA20 /* MediaObjectViewController.h */, @@ -2387,6 +2408,8 @@ AC512F790E20D25E00B7DA32 /* Images */ = { isa = PBXGroup; children = ( + 00C0D2561718AB1C00E2B95D /* button_red.png */, + 00C0D2571718AB1C00E2B95D /* button_red@2x.png */, E1D0D82D16D3D2BA00E33F4C /* NNInstapaperActivity@2x~ipad.png */, E1D0D82E16D3D2BA00E33F4C /* NNInstapaperActivity@2x~iphone.png */, E1D0D82F16D3D2BA00E33F4C /* NNInstapaperActivity~ipad.png */, @@ -2920,6 +2943,8 @@ E183EC9F16B2164900C2EB11 /* EditPostViewControllerTest.m */, E150520A16CAC5C400D3DDDC /* BlogJetpackTest.h */, E150520B16CAC5C400D3DDDC /* BlogJetpackTest.m */, + 00C0D25C1718AB6300E2B95D /* MediaSettingsTests.h */, + 00C0D25D1718AB6300E2B95D /* MediaSettingsTests.m */, ); path = WordPressTest; sourceTree = ""; @@ -3617,6 +3642,9 @@ E12A08E416C9706200E3DDF6 /* clouds_header@2x.png in Resources */, E15051CE16CA8E4900D3DDDC /* logo_jetpack.png in Resources */, E15051CF16CA8E4900D3DDDC /* logo_jetpack@2x.png in Resources */, + 00C0D2581718AB1C00E2B95D /* button_red.png in Resources */, + 00C0D2591718AB1C00E2B95D /* button_red@2x.png in Resources */, + 00C0D25B1718AB4B00E2B95D /* MediaSettingsViewController.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3832,6 +3860,8 @@ E1D0D82B16D3D19200E33F4C /* PocketAPIOperation.m in Sources */, E1D0D84716D3D2EA00E33F4C /* PocketActivity.m in Sources */, E15051CB16CA5DDB00D3DDDC /* Blog+Jetpack.m in Sources */, + 00C0D2611718AB9C00E2B95D /* MediaSettingsViewController.m in Sources */, + 00C0D2641718ABCC00E2B95D /* MediaSettings.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3847,6 +3877,8 @@ E150520F16CAC75A00D3DDDC /* CoreDataTestHelper.m in Sources */, E131CB5E16CAD659004B0314 /* AsyncTestHelper.m in Sources */, E15618FD16DB8677006532C4 /* UIKitTestHelper.m in Sources */, + 00C0D25E1718AB6300E2B95D /* MediaSettingsTests.m in Sources */, + 00C0D2651718ABCC00E2B95D /* MediaSettings.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/WordPress/WordPressTest/MediaSettingsTests.h b/WordPress/WordPressTest/MediaSettingsTests.h new file mode 100644 index 000000000000..e1154f507580 --- /dev/null +++ b/WordPress/WordPressTest/MediaSettingsTests.h @@ -0,0 +1,14 @@ +// +// MediaSettingsTests.h +// WordPress +// +// Created by Jeffrey Vanneste on 2013-01-12. +// Copyright (c) 2013 WordPress. All rights reserved. +// + +#import +#import "MediaSettings.h" + +@interface MediaSettingsTests : SenTestCase + +@end diff --git a/WordPress/WordPressTest/MediaSettingsTests.m b/WordPress/WordPressTest/MediaSettingsTests.m new file mode 100644 index 000000000000..e9355fea49ff --- /dev/null +++ b/WordPress/WordPressTest/MediaSettingsTests.m @@ -0,0 +1,251 @@ +// +// MediaSettingsTests.m +// WordPress +// +// Created by Jeffrey Vanneste on 2013-01-12. +// Copyright (c) 2013 WordPress. All rights reserved. +// + +#import "MediaSettingsTests.h" + +@implementation MediaSettingsTests + +- (void)setUp +{ + [super setUp]; + + // Set-up code here. +} + +- (void)tearDown +{ + // Tear-down code here. + + [super tearDown]; +} + +- (void)testParseSettingsWhenUrlNotFound { + // setup + NSString *content = @"This image links to the image we want to match but we shouldn't match it since the URL is not in the img src "; + + // test + MediaSettings *mediaSettings = [MediaSettings createMediaSettingsForUrl:@"http://www.someurlnotfound.com/image.jpg" content:content]; + //NSLog(@"MediaSettings: %@", mediaSettings); + + // asserts + STAssertNotNil(mediaSettings, @"mediaSettings should not be nil"); + STAssertNil(mediaSettings.parsedHtml, @"parsedHtml will be nil since no matching HTML was found"); +} + +- (void)testParseSettingsUrlMatchInContentAndImage { + // setup + NSString *content = @"This image links to the image we want to match but we shouldn't match it since the URL is not in the img src "; + NSString *parsedHtml = @""; + + // test + MediaSettings *mediaSettings = [MediaSettings createMediaSettingsForUrl:@"http://www.someurl.com/image.jpg" content:content]; + //NSLog(@"MediaSettings: %@", mediaSettings); + + // asserts + STAssertEqualObjects(parsedHtml, mediaSettings.parsedHtml, @"parsedHtml"); +} + +- (void)testParseSettingsForMultipleImages { + // setup + NSString *content = @"

Previous content

\n\n and some post content
end
"; + NSString *parsedHtml = @""; + + // test + MediaSettings *mediaSettings = [MediaSettings createMediaSettingsForUrl:@"http://www.someurl2.com/image2.jpg" content:content]; + //NSLog(@"MediaSettings: %@", mediaSettings); + + // asserts + STAssertEqualObjects(parsedHtml, mediaSettings.parsedHtml, @"parsedHtml"); +} + +- (void)testParseSettingsForSingleImageWithoutLinkAndNoAttributes { + // setup + NSString *content = @"

Previous content

\n\n and some post content
end
"; + NSString *parsedHtml = @""; + + // test + MediaSettings *mediaSettings = [MediaSettings createMediaSettingsForUrl:@"http://www.someurl.com/image.jpg" content:content]; + //NSLog(@"MediaSettings: %@", mediaSettings); + + // asserts + STAssertEqualObjects(parsedHtml, mediaSettings.parsedHtml, @"parsedHtml"); +} + +- (void)testParseSettingsForSingleImageWithoutLink { + // setup + NSString *content = @"

Previous content

\n\n and some post content
end
"; + MediaSettings *expectedMediaSettings = [[MediaSettings alloc] init]; + NSString *parsedHtml = @""; + expectedMediaSettings.alignment = @"alignnone"; + expectedMediaSettings.customHeight = [NSNumber numberWithInt:405]; + expectedMediaSettings.customWidth = [NSNumber numberWithInt:540]; + + // test + MediaSettings *mediaSettings = [MediaSettings createMediaSettingsForUrl:@"http://www.someurl.com/image.jpg" content:content]; + //NSLog(@"MediaSettings: %@", mediaSettings); + + // asserts + STAssertEqualObjects(parsedHtml, mediaSettings.parsedHtml, @"parsedHtml"); + STAssertEqualObjects(expectedMediaSettings.alignment, mediaSettings.alignment, @"alignment"); + STAssertEqualObjects(expectedMediaSettings.customHeight, mediaSettings.customHeight, @"customHeight"); + STAssertEqualObjects(expectedMediaSettings.customWidth, mediaSettings.customWidth, @"customWidth"); +} + +- (void)testParseSettingsForSingleImageWithLink { + // setup + NSString *content = @"

Previous content

\n\n and some post content
end
"; + MediaSettings *expectedMediaSettings = [[MediaSettings alloc] init]; + NSString *parsedHtml = @""; + expectedMediaSettings.alignment = @"alignnone"; + expectedMediaSettings.customHeight = [NSNumber numberWithInt:405]; + expectedMediaSettings.customWidth = [NSNumber numberWithInt:540]; + expectedMediaSettings.linkHref = @"http://www.someurl.com/image.jpg"; + + // test + MediaSettings *mediaSettings = [MediaSettings createMediaSettingsForUrl:@"http://www.someurl.com/image.jpg" content:content]; + //NSLog(@"MediaSettings: %@", mediaSettings); + + // asserts + STAssertEqualObjects(parsedHtml, mediaSettings.parsedHtml, @"parsedHtml"); + STAssertEqualObjects(expectedMediaSettings.alignment, mediaSettings.alignment, @"alignment"); + STAssertEqualObjects(expectedMediaSettings.customHeight, mediaSettings.customHeight, @"customHeight"); + STAssertEqualObjects(expectedMediaSettings.customWidth, mediaSettings.customWidth, @"customWidth"); + STAssertEqualObjects(expectedMediaSettings.linkHref, mediaSettings.linkHref, @"linkHref"); +} + +- (void)testParseSettingsForMultipleImageWithCaption { + // setup + NSString *content = @"

Previous content

\n\n[caption id=\"captionid2\" align=\"aligncenter\" width=\"302\"]\"\" asdfsdf[/caption] and some post content
end
[caption id=\"caption_id1\" align=\"aligncenter\" width=\"302\"]\"\" asdfsdf[/caption]"; + MediaSettings *expectedMediaSettings = [[MediaSettings alloc] init]; + NSString *parsedHtml = @"[caption id=\"caption_id1\" align=\"aligncenter\" width=\"302\"]\"\" asdfsdf[/caption]"; + expectedMediaSettings.customHeight = [NSNumber numberWithInt:227]; + expectedMediaSettings.customWidth = [NSNumber numberWithInt:302]; + expectedMediaSettings.linkHref = @"http://www.someurl.com/image1.jpg"; + expectedMediaSettings.captionText = @" asdfsdf"; + expectedMediaSettings.alignment = @"aligncenter"; + + // test + MediaSettings *mediaSettings = [MediaSettings createMediaSettingsForUrl:@"http://www.someurl.com/image1.jpg" content:content]; + //NSLog(@"MediaSettings: %@", mediaSettings); + + // asserts + STAssertEqualObjects(parsedHtml, mediaSettings.parsedHtml, @"parsedHtml"); + STAssertEqualObjects(expectedMediaSettings.alignment, mediaSettings.alignment, @"alignment"); + STAssertEqualObjects(expectedMediaSettings.customHeight, mediaSettings.customHeight, @"customHeight"); + STAssertEqualObjects(expectedMediaSettings.customWidth, mediaSettings.customWidth, @"customWidth"); + STAssertEqualObjects(expectedMediaSettings.linkHref, mediaSettings.linkHref, @"linkHref"); + STAssertEqualObjects(expectedMediaSettings.captionText, mediaSettings.captionText, @"captionText"); +} + +- (void)testParseSettingsForMultipleImageWithCaptionAndNoLink { + // setup + NSString *content = @"

Previous content

\n\n[caption id=\"captionid2\" align=\"aligncenter\" width=\"302\"]\"\" asdfsdf[/caption] and some post content
end
[caption id=\"caption_id1\" align=\"aligncenter\" width=\"302\"]\"\"asdfsdf[/caption]"; + MediaSettings *expectedMediaSettings = [[MediaSettings alloc] init]; + NSString *parsedHtml = @"[caption id=\"caption_id1\" align=\"aligncenter\" width=\"302\"]\"\"asdfsdf[/caption]"; + expectedMediaSettings.customHeight = [NSNumber numberWithInt:227]; + expectedMediaSettings.customWidth = [NSNumber numberWithInt:302]; + expectedMediaSettings.captionText = @"asdfsdf"; + expectedMediaSettings.alignment = @"aligncenter"; + + // test + MediaSettings *mediaSettings = [MediaSettings createMediaSettingsForUrl:@"http://www.someurl.com/image1.jpg" content:content]; + //NSLog(@"MediaSettings: %@", mediaSettings); + + // asserts + STAssertEqualObjects(parsedHtml, mediaSettings.parsedHtml, @"parsedHtml"); + STAssertEqualObjects(expectedMediaSettings.customHeight, mediaSettings.customHeight, @"customHeight"); + STAssertEqualObjects(expectedMediaSettings.customWidth, mediaSettings.customWidth, @"customWidth"); + STAssertEqualObjects(expectedMediaSettings.captionText, mediaSettings.captionText, @"captionText"); + STAssertEqualObjects(expectedMediaSettings.alignment, mediaSettings.alignment, @"alignment"); +} + + +- (void)testParseSettingsAndUpdateWithoutLosingAttributes { + // setup + NSString *content = @"

Previous content

\n\n[caption id=\"captionid2\" align=\"aligncenter\" width=\"302\"]\"\" asdfsdf[/caption] and some post content
end
[caption id=\"caption_id1\" align=\"aligncenter\" width=\"302\"]\"\"asdfsdf[/caption]"; + NSString *expectedMediaHtml = @"[caption id=\"captionid2\" align=\"alignleft\" width=\"302\"]\"\" asdfsdf[/caption]"; + MediaSettings *mediaSettings = [MediaSettings createMediaSettingsForUrl:@"http://www.someurl.com/image2.jpg" content:content]; + + // test + mediaSettings.alignment = @"alignleft"; + //NSLog(@"MediaSettings: %@", mediaSettings); + + // asserts + STAssertEqualObjects(expectedMediaHtml, [mediaSettings html], @"html"); +} + +- (void)testUpdateWithAddingCaption { + // setup + NSString *content = @"

paragraph text

"; + NSString *expectedMediaHtml = @"[caption align=\"alignnone\"]brand new caption text[/caption]"; + MediaSettings *mediaSettings = [MediaSettings createMediaSettingsForUrl:@"http://www.someurl.com/image1.jpg" content:content]; + + // test + mediaSettings.captionText = @"brand new caption text"; + //NSLog(@"MediaSettings: %@", mediaSettings); + + // asserts + STAssertEqualObjects(expectedMediaHtml, [mediaSettings html], @"html"); +} + +- (void)testUpdateWithAddingCaptionAndAlignmentRemovedFromImage { + // setup + NSString *content = @"

paragraph text

"; + NSString *expectedMediaHtml = @"[caption align=\"alignleft\"]brand new caption text[/caption]"; + MediaSettings *mediaSettings = [MediaSettings createMediaSettingsForUrl:@"http://www.someurl.com/image1.jpg" content:content]; + + // test + mediaSettings.captionText = @"brand new caption text"; + //NSLog(@"MediaSettings: %@", mediaSettings); + + // asserts + STAssertEqualObjects(expectedMediaHtml, [mediaSettings html], @"html"); +} + +- (void)testUpdateWithRemovingCaptionAndAlignmentMovedToImage { + // setup + NSString *content = @"

paragraph text

[caption id=\"123\" align=' aligncenter ']existing caption[/caption]"; + NSString *expectedMediaHtml = @""; + MediaSettings *mediaSettings = [MediaSettings createMediaSettingsForUrl:@"http://www.someurl.com/image1.jpg" content:content]; + + // test + mediaSettings.captionText = @""; + //NSLog(@"MediaSettings: %@", mediaSettings); + + // asserts + STAssertEqualObjects(expectedMediaHtml, [mediaSettings html], @"html"); +} + +- (void)testUpdateWithAddingLink { + // setup + NSString *content = @"

paragraph text

[caption id=\"123\" align=' aligncenter ']existing caption[/caption]"; + NSString *expectedMediaHtml = @"[caption id=\"123\" align=\"aligncenter\"]existing caption[/caption]"; + MediaSettings *mediaSettings = [MediaSettings createMediaSettingsForUrl:@"http://www.someurl.com/image1.jpg" content:content]; + + // test + mediaSettings.linkHref = @"http://www.google.com"; + //NSLog(@"MediaSettings: %@", mediaSettings); + + // asserts + STAssertEqualObjects(expectedMediaHtml, [mediaSettings html], @"html"); +} + +- (void)testUpdateWithRemovingLink { + // setup + NSString *content = @"

paragraph text

[caption id=\"123\" align=' aligncenter ']existing caption[/caption]"; + NSString *expectedMediaHtml = @"[caption id=\"123\" align=\"aligncenter\"]existing caption[/caption]"; + MediaSettings *mediaSettings = [MediaSettings createMediaSettingsForUrl:@"http://www.someurl.com/image1.jpg" content:content]; + + // test + mediaSettings.linkHref = nil; + //NSLog(@"MediaSettings: %@", mediaSettings); + + // asserts + STAssertEqualObjects(expectedMediaHtml, [mediaSettings html], @"html"); +} +@end