diff --git a/Wikipedia/Code/NSURL+WMFLinkParsing.h b/Wikipedia/Code/NSURL+WMFLinkParsing.h index 8520c34010..6974565f08 100644 --- a/Wikipedia/Code/NSURL+WMFLinkParsing.h +++ b/Wikipedia/Code/NSURL+WMFLinkParsing.h @@ -1,124 +1,124 @@ // // NSURL+WMFLinkParsing.h // Wikipedia // // Created by Brian Gerstle on 8/5/15. // Copyright (c) 2015 Wikimedia Foundation. All rights reserved. // #import NS_ASSUME_NONNULL_BEGIN @interface NSURL (WMFLinkParsing) /** * Initialize a new URL with a Wikimedia `domain` and `language`. * * @param domain Wikimedia domain - for example: `wikimedia.org`. * @param language An optional Wikimedia language code. Should be ISO 639-x/IETF BCP 47 @see kCFLocaleLanguageCode - for exmaple: `en`. * * @return A new URL with the given domain and language. **/ -+ (NSURL*)wmf_URLWithDomain:(NSString*)domain language:(NSString* __nullable)language; ++ (NSURL*)wmf_URLWithDomain:(NSString*)domain language:(nullable NSString*)language; /** * Initialize a new URL with a Wikimedia `domain`, `language`, `title` and `fragment`. * * @param domain Wikimedia domain - for example: `wikimedia.org`. * @param language An optional Wikimedia language code. Should be ISO 639-x/IETF BCP 47 @see kCFLocaleLanguageCode - for exmaple: `en`. * @param title An optional Wikimedia title. For exmaple: `Main Page`. * @param fragment An optional fragment, for example if you want the URL to contain `#section`, the fragment is `section`. * * @return A new URL with the given domain, language, title and fragment. **/ -+ (NSURL*)wmf_URLWithDomain:(NSString*)domain language:(NSString* __nullable)language title:(NSString* __nullable)title fragment:(NSString* __nullable)fragment; ++ (NSURL*)wmf_URLWithDomain:(NSString*)domain language:(nullable NSString*)language title:(nullable NSString*)title fragment:(nullable NSString*)fragment; /** * Return a new URL constructed from the `siteURL`, replacing the `title` and `fragment` with the given values. * * @param siteURL A Wikimedia site URL. For exmaple: `https://en.wikipedia.org`. * @param title A Wikimedia title. For exmaple: `Main Page`. * @param fragment An optional fragment, for example if you want the URL to contain `#section`, the fragment is `section`. * * @return A new URL constructed from the `siteURL`, replacing the `title` and `fragment` with the given values. **/ -+ (NSURL*)wmf_URLWithSiteURL:(NSURL*)siteURL title:(NSString* __nullable)title fragment:(NSString* __nullable)fragment; ++ (NSURL*)wmf_URLWithSiteURL:(NSURL*)siteURL title:(nullable NSString*)title fragment:(nullable NSString*)fragment; /** * Return a new URL constructed from the `siteURL`, replacing the `path` with the `internalLink`. * * @param siteURL A Wikimedia site URL. For exmaple: `https://en.wikipedia.org`. * @param internalLink A Wikimedia internal link path. For exmaple: `/wiki/Main_Page`. * * @return A new URL constructed from the `siteURL`, replacing the `path` with the `internalLink`. **/ + (NSURL*)wmf_URLWithSiteURL:(NSURL*)siteURL internalLink:(NSString*)internalLink; /** * Return a new URL constructed from the `siteURL`, replacing the `path` with the internal link prefix and the `path`. * * @param siteURL A Wikimedia site URL. For exmaple: `https://en.wikipedia.org`. * @param path A Wikimedia path. For exmaple: `/Main_Page`. * * @return A new URL constructed from the `siteURL`, replacing the `path` with the internal link prefix and the `path`. **/ + (NSURL*)wmf_URLWithSiteURL:(NSURL*)siteURL path:(NSString*)path; /** * Return a new URL similar to the URL you call this method on but replace the title. * * @param title A Wikimedia title. For exmaple: `Main Page`. * * @return A new URL based on the URL you call this method on with the given title. **/ - (NSURL*)wmf_URLWithTitle:(NSString*)title; /** * Return a new URL similar to the URL you call this method on but replace the title and fragemnt. * * @param title A Wikimedia title. For exmaple: `Main Page`. * @param fragment An optional fragment, for example if you want the URL to contain `#section`, the fragment is `section`. * * @return A new URL based on the URL you call this method on with the given title and fragment. **/ -- (NSURL*)wmf_URLWithTitle:(NSString*)title fragment:(NSString* __nullable)fragment; +- (NSURL*)wmf_URLWithTitle:(NSString*)title fragment:(nullable NSString*)fragment; /** * Return a new URL similar to the URL you call this method on but replace the path. * * @param path A full path - for example `/w/api.php` * * @return A new URL based on the URL you call this method on with the given path. **/ - (NSURL*)wmf_URLWithPath:(NSString*)path isMobile:(BOOL)isMobile; @property (nonatomic, readonly) BOOL wmf_isInternalLink; @property (nonatomic, readonly) BOOL wmf_isCitation; @property (nonatomic, readonly) BOOL wmf_isMobile; @property (nonatomic, copy, readonly, nullable) NSString* wmf_internalLinkPath; @property (nonatomic, copy, readonly, nullable) NSString* wmf_domain; @property (nonatomic, copy, readonly, nullable) NSString* wmf_language; @property (nonatomic, copy, readonly) NSString* wmf_title; @property (nonatomic, copy, readonly) NSURL* wmf_mobileURL; @property (nonatomic, copy, readonly) NSURL* wmf_desktopURL; @property (nonatomic, readonly) BOOL wmf_isNonStandardURL; @property (nonatomic, readonly) UIUserInterfaceLayoutDirection wmf_layoutDirection; @property (nonatomic, readonly) NSTextAlignment wmf_textAlignment; @end NS_ASSUME_NONNULL_END diff --git a/Wikipedia/Code/NSURL+WMFLinkParsing.m b/Wikipedia/Code/NSURL+WMFLinkParsing.m index 1461cab77d..32108720d0 100644 --- a/Wikipedia/Code/NSURL+WMFLinkParsing.m +++ b/Wikipedia/Code/NSURL+WMFLinkParsing.m @@ -1,188 +1,188 @@ // // NSURL+WMFLinkParsing.m // Wikipedia // // Created by Brian Gerstle on 8/5/15. // Copyright (c) 2015 Wikimedia Foundation. All rights reserved. // #import "NSURL+WMFLinkParsing.h" #import "NSString+WMFExtras.h" #import "NSString+WMFPageUtilities.h" #import "NSURL+WMFExtras.h" #import "NSURLComponents+WMFLinkParsing.h" #import "Wikipedia-Swift.h" @interface NSURL (WMFLinkParsing_Private) @property (nonatomic, readonly) NSInteger wmf_domainIndex; @end @implementation NSURL (WMFLinkParsing) #pragma mark - Constructors -+ (NSURL*)wmf_URLWithDomain:(NSString*)domain language:(NSString* __nullable)language { ++ (NSURL*)wmf_URLWithDomain:(NSString*)domain language:(nullable NSString*)language { return [[NSURLComponents wmf_componentsWithDomain:domain language:language] URL]; } -+ (NSURL*)wmf_URLWithDomain:(NSString*)domain language:(NSString* __nullable)language title:(NSString*)title fragment:(NSString* __nullable)fragment { ++ (NSURL*)wmf_URLWithDomain:(NSString*)domain language:(nullable NSString*)language title:(NSString*)title fragment:(nullable NSString*)fragment { return [[NSURLComponents wmf_componentsWithDomain:domain language:language title:title fragment:fragment] URL]; } -+ (NSURL*)wmf_URLWithSiteURL:(NSURL*)siteURL title:(NSString* __nullable)title fragment:(NSString* __nullable)fragment { ++ (NSURL*)wmf_URLWithSiteURL:(NSURL*)siteURL title:(nullable NSString*)title fragment:(nullable NSString*)fragment { return [siteURL wmf_URLWithTitle:title fragment:fragment]; } + (NSURL*)wmf_URLWithSiteURL:(NSURL*)siteURL path:(NSString*)path { NSAssert(![path wmf_isInternalLink], @"Didn't expect %@ to be an internal link. Use initWithInternalLink:site: instead.", path); if ([path wmf_isInternalLink]) { // recurse here after stripping internal link prefix return [NSURL wmf_URLWithSiteURL:siteURL internalLink:path]; } else { NSArray* bits = [path componentsSeparatedByString:@"#"]; return [NSURL wmf_URLWithSiteURL:siteURL title:[[bits firstObject] wmf_unescapedNormalizedPageTitle] fragment:[bits wmf_safeObjectAtIndex:1]]; } } + (NSURL*)wmf_URLWithSiteURL:(NSURL*)siteURL internalLink:(NSString*)internalLink { NSAssert(internalLink.length == 0 || [internalLink wmf_isInternalLink], @"Expected string with internal link prefix but got: %@", internalLink); return [self wmf_URLWithSiteURL:siteURL path:[internalLink wmf_internalLinkPath]]; } - (NSURL*)wmf_URLWithTitle:(NSString*)title { NSURLComponents* components = [NSURLComponents componentsWithURL:self resolvingAgainstBaseURL:NO]; components.wmf_title = title; return components.URL; } - (NSURL*)wmf_URLWithTitle:(NSString*)title fragment:(NSString*)fragment { NSURLComponents* components = [NSURLComponents componentsWithURL:self resolvingAgainstBaseURL:NO]; components.wmf_title = title; components.wmf_fragment = fragment; return components.URL; } - (NSURL*)wmf_URLWithPath:(NSString*)path isMobile:(BOOL)isMobile { NSURLComponents* components = [NSURLComponents componentsWithURL:self resolvingAgainstBaseURL:NO]; components.path = path; if (isMobile != self.wmf_isMobile) { components.host = [NSURLComponents wmf_hostWithDomain:self.wmf_domain language:self.wmf_language isMobile:isMobile]; } return components.URL; } #pragma mark - Properties - (BOOL)wmf_isInternalLink { return [self.path wmf_isInternalLink]; } - (BOOL)wmf_isCitation { return [self.fragment wmf_isCitationFragment]; } - (BOOL)wmf_isMobile { NSArray* hostComponents = [self.host componentsSeparatedByString:@"."]; return hostComponents.count > 1 && [hostComponents[1] isEqualToString:@"m"]; } - (NSString*)wmf_internalLinkPath { return [self.path wmf_internalLinkPath]; } - (NSString*)wmf_domain { return [self.host substringFromIndex:self.wmf_domainIndex]; } - (NSString*)wmf_language { NSRange dotRange = [self.host rangeOfString:@"."]; if (dotRange.location != NSNotFound) { return [self.host substringToIndex:dotRange.location]; } else { return nil; } } - (NSString*)wmf_title { NSString* title = [[self.path wmf_internalLinkPath] wmf_unescapedNormalizedPageTitle]; if (title == nil) { title = @""; } return title; } - (NSURL*)wmf_mobileURL { NSURLComponents* components = [NSURLComponents componentsWithURL:self resolvingAgainstBaseURL:NO]; components.host = [NSURLComponents wmf_hostWithDomain:self.wmf_domain language:self.wmf_language isMobile:YES]; NSURL* mobileURL = components.URL ? : self; return mobileURL; } - (NSURL*)wmf_desktopURL { NSURLComponents* components = [NSURLComponents componentsWithURL:self resolvingAgainstBaseURL:NO]; components.host = [NSURLComponents wmf_hostWithDomain:self.wmf_domain language:self.wmf_language isMobile:NO]; NSURL* desktopURL = components.URL ? : self; return desktopURL; } - (BOOL)wmf_isNonStandardURL { return self.wmf_language == nil; } - (UIUserInterfaceLayoutDirection)wmf_layoutDirection { switch (CFLocaleGetLanguageCharacterDirection((__bridge CFStringRef)self.wmf_language)) { case kCFLocaleLanguageDirectionRightToLeft: return UIUserInterfaceLayoutDirectionRightToLeft; default: return UIUserInterfaceLayoutDirectionLeftToRight; } } - (NSTextAlignment)wmf_textAlignment { switch (self.wmf_layoutDirection) { case UIUserInterfaceLayoutDirectionRightToLeft: return NSTextAlignmentRight; case UIUserInterfaceLayoutDirectionLeftToRight: return NSTextAlignmentLeft; } } @end @implementation NSURL (WMFLinkParsing_Private) + (NSRegularExpression*)WMFURLParsingDomainIndexRegularExpression { static NSRegularExpression* WMFURLParsingDomainIndexRegularExpression = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSError* regexError = nil; WMFURLParsingDomainIndexRegularExpression = [NSRegularExpression regularExpressionWithPattern:@"^[^.]*(.m){0,1}[.]" options:NSRegularExpressionCaseInsensitive error:®exError]; if (regexError) { DDLogError(@"Error creating domain parsing regex: %@", regexError); } }); return WMFURLParsingDomainIndexRegularExpression; } - (NSInteger)wmf_domainIndex { if (self.host == nil) { return 0; } NSTextCheckingResult* regexResult = [[NSURL WMFURLParsingDomainIndexRegularExpression] firstMatchInString:self.host options:NSMatchingAnchored range:NSMakeRange(0, self.host.length)]; NSInteger index = 0; if (regexResult != nil) { index = regexResult.range.location + regexResult.range.length; } return index; } @end diff --git a/Wikipedia/Code/NSURLComponents+WMFLinkParsing.h b/Wikipedia/Code/NSURLComponents+WMFLinkParsing.h index b2ef7ad43a..43b9afa84c 100644 --- a/Wikipedia/Code/NSURLComponents+WMFLinkParsing.h +++ b/Wikipedia/Code/NSURLComponents+WMFLinkParsing.h @@ -1,91 +1,91 @@ #import @interface NSURLComponents (WMFLinkParsing) /** * Create new NSURLComponents with a Wikimedia `domain` and `language`. * * @param domain Wikimedia domain - for example: `wikimedia.org`. * * @param language An optional Wikimedia language code. Should be ISO 639-x/IETF BCP 47 @see kCFLocaleLanguageCode - for exmaple: `en`. * * @return New NSURLComponents with the given domain and language. **/ -+ (NSURLComponents* __nonnull)wmf_componentsWithDomain:(NSString* __nonnull)domain - language:(NSString* __nullable)language; ++ (nonnull NSURLComponents*)wmf_componentsWithDomain:(nonnull NSString*)domain + language:(nullable NSString*)language; /** * Create new NSURLComponents with a Wikimedia `domain` and `language` for the mobile or desktop site. * * @param domain Wikimedia domain - for example: `wikimedia.org`. * @param language An optional Wikimedia language code. Should be ISO 639-x/IETF BCP 47 @see kCFLocaleLanguageCode - for exmaple: `en`. * @param isMobile A boolean indicating whether or not the returned URL components should be for the mobile version of the site. * * @return New NSURLComponents with the given domain and language. **/ -+ (NSURLComponents* __nonnull)wmf_componentsWithDomain:(NSString* __nonnull)domain - language:(NSString* __nullable)language - isMobile:(BOOL)isMobile; ++ (nonnull NSURLComponents*)wmf_componentsWithDomain:(nonnull NSString*)domain + language:(nullable NSString*)language + isMobile:(BOOL)isMobile; /** * Create new NSURLComponents with a Wikimedia `domain`, `language` and `title`. * * @param domain Wikimedia domain - for example: `wikimedia.org`. * @param language An optional Wikimedia language code. Should be ISO 639-x/IETF BCP 47 @see kCFLocaleLanguageCode - for exmaple: `en`. * @param title An optional Wikimedia title. For exmaple: `Main Page`. * * @return New NSURLComponents with the given domain, language and title. **/ -+ (NSURLComponents* __nonnull)wmf_componentsWithDomain:(NSString* __nonnull)domain - language:(NSString* __nullable)language - title:(NSString* __nullable)title; ++ (nonnull NSURLComponents*)wmf_componentsWithDomain:(nonnull NSString*)domain + language:(nullable NSString*)language + title:(nullable NSString*)title; /** * Create new NSURLComponents with a Wikimedia `domain`, `language`, `title` and `fragment`. * * @param domain Wikimedia domain - for example: `wikimedia.org`. * @param language An optional Wikimedia language code. Should be ISO 639-x/IETF BCP 47 @see kCFLocaleLanguageCode - for exmaple: `en`. * @param title An optional Wikimedia title. For exmaple: `Main Page`. * @param fragment An optional fragment, for example if you want the URL to contain `#section`, the fragment is `section`. * * * @return New NSURLComponents with the given domain, language, title and fragment. **/ -+ (NSURLComponents* __nonnull)wmf_componentsWithDomain:(NSString* __nonnull)domain - language:(NSString* __nullable)language - title:(NSString* __nullable)title - fragment:(NSString* __nullable)fragment; ++ (NSURLComponents* __nonnull)wmf_componentsWithDomain:(nonnull NSString*)domain + language:(nullable NSString*)language + title:(nullable NSString*)title + fragment:(nullable NSString*)fragment; /** * Create new NSURLComponents with a Wikimedia `domain`, `language`, `title` and `fragment` for mobile or desktop based on `isMobile`. * * @param domain Wikimedia domain - for example: `wikimedia.org`. * @param language An optional Wikimedia language code. Should be ISO 639-x/IETF BCP 47 @see kCFLocaleLanguageCode - for exmaple: `en`. * @param title An optional Wikimedia title. For exmaple: `Main Page`. * @param fragment An optional fragment, for example if you want the URL to contain `#section`, the fragment is `section`. * @param isMobile A boolean indicating whether or not the returned URL components should be for the mobile version of the site. * * @return New NSURLComponents with the given domain, language, title and fragment for mobile or desktop based on `isMobile`. **/ -+ (NSURLComponents* __nonnull)wmf_componentsWithDomain:(NSString* __nonnull)domain - language:(NSString* __nullable)language - title:(NSString* __nullable)title - fragment:(NSString* __nullable)fragment - isMobile:(BOOL)isMobile; ++ (nonnull NSURLComponents*)wmf_componentsWithDomain:(nonnull NSString*)domain + language:(nullable NSString*)language + title:(nullable NSString*)title + fragment:(nullable NSString*)fragment + isMobile:(BOOL)isMobile; /** * Create new NSString containing the full host for a Wikimedia `domain` and `language` for mobile or desktop based on `isMobile`. * * @param domain Wikimedia domain - for example: `wikimedia.org`. * @param language An optional Wikimedia language code. Should be ISO 639-x/IETF BCP 47 @see kCFLocaleLanguageCode - for exmaple: `en`. * @param isMobile A boolean indicating whether or not the returned URL components should be for the mobile version of the site. * * @return A new NSString containing the full host for a Wikimedia `domain` and `language` for mobile or desktop based on `isMobile`. **/ -+ (NSString* __nonnull)wmf_hostWithDomain:(NSString* __nonnull)domain - language:(NSString* __nullable)language - isMobile:(BOOL)isMobile; ++ (nonnull NSString*)wmf_hostWithDomain:(nonnull NSString*)domain + language:(nullable NSString*)language + isMobile:(BOOL)isMobile; @property (nonatomic, copy, nullable) NSString* wmf_title; @property (nullable, copy) NSString* wmf_fragment; @end