From 4442a56f039b3676ddf7a8380a4112366b75fce4 Mon Sep 17 00:00:00 2001 From: Oliver Drobnik Date: Wed, 18 Sep 2019 10:12:34 +0200 Subject: [PATCH 01/13] Fixed unit tests under iOS 13 --- Test/Source/NSAttributedStringHTMLTest.m | 71 ++++++++++++------------ 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/Test/Source/NSAttributedStringHTMLTest.m b/Test/Source/NSAttributedStringHTMLTest.m index d8b72b623..7940c9e03 100644 --- a/Test/Source/NSAttributedStringHTMLTest.m +++ b/Test/Source/NSAttributedStringHTMLTest.m @@ -64,13 +64,13 @@ - (void)testParagraphs NSAttributedString *string = [self attributedStringFromHTML:html]; NSData *dump = [[string string] dataUsingEncoding:NSUTF8StringEncoding]; - NSString *resultOnIOS = [dump description]; + NSString *resultOnIOS = [self hexStringForData:dump]; - NSString *resultOnMac = @"<50726566 69780a4f 6e652074 776f20e2 80a87468 7265650a 4e657720 50617261 67726170 680a5375 66666978>"; + NSString *resultOnMac = @"5072656669780a4f6e652074776f20e280a874687265650a4e6577205061726167726170680a537566666978"; //[self dumpOneResult:resultOnIOS versusOtherResult:resultOnMac]; - XCTAssertEqualObjects(resultOnIOS, resultOnMac, @"Output on Paragraph Test differs"); + XCTAssertTrue([resultOnIOS isEqualToString:resultOnMac], @"Output on Paragraph Test differs"); } @@ -80,11 +80,11 @@ - (void)testHeaderParagraphs NSAttributedString *string = [self attributedStringFromHTML:html]; NSData *dump = [[string string] dataUsingEncoding:NSUTF8StringEncoding]; - NSString *resultOnIOS = [dump description]; + NSString *resultOnIOS = [self hexStringForData:dump]; - NSString *resultOnMac = @"<50726566 69780a4f 6e650a4f 6e650a4f 6e650a4f 6e650a4f 6e650a4e 65772050 61726167 72617068 0a537566 666978>"; + NSString *resultOnMac = @"5072656669780a4f6e650a4f6e650a4f6e650a4f6e650a4f6e650a4e6577205061726167726170680a537566666978"; - XCTAssertEqualObjects(resultOnIOS, resultOnMac, @"Output on Paragraph Test differs"); + XCTAssertTrue([resultOnIOS isEqualToString:resultOnMac], @"Output on Paragraph Test differs"); } @@ -94,11 +94,11 @@ - (void)testListParagraphs NSAttributedString *string = [self attributedStringFromHTML:html]; NSData *dump = [[string string] dataUsingEncoding:NSUTF8StringEncoding]; - NSString *resultOnIOS = [dump description]; + NSString *resultOnIOS = [self hexStringForData:dump]; - NSString *resultOnMac = @"<4265666f 72650a09 e280a209 4f6e650a 09e280a2 0954776f 0a416674 65720a>"; + NSString *resultOnMac = @"4265666f72650a09e280a2094f6e650a09e280a20954776f0a41667465720a"; - XCTAssertEqualObjects(resultOnIOS, resultOnMac, @"Output on List Test differs"); + XCTAssertTrue([resultOnIOS isEqualToString:resultOnMac], @"Output on List Test differs"); } - (void)testImageParagraphs @@ -108,11 +108,11 @@ - (void)testImageParagraphs NSAttributedString *string = [self attributedStringFromHTML:html]; NSData *dump = [[string string] dataUsingEncoding:NSUTF8StringEncoding]; - NSString *resultOnIOS = [dump description]; + NSString *resultOnIOS = [self hexStringForData:dump]; - NSString *resultOnMac = @"<4265666f 72650aef bfbc0a48 65616465 720a6166 7465720a 536f6d65 20696e6c 696e6520 efbfbc20 74657874 2e0a>"; + NSString *resultOnMac = @"4265666f72650aefbfbc0a4865616465720a61667465720a536f6d6520696e6c696e6520efbfbc20746578742e0a"; - XCTAssertEqualObjects(resultOnIOS, resultOnMac, @"Output on List Test differs"); + XCTAssertTrue([resultOnIOS isEqualToString:resultOnMac], @"Output on List Test differs"); } - (void)testSpaceNormalization @@ -121,11 +121,11 @@ - (void)testSpaceNormalization NSAttributedString *string = [self attributedStringFromHTML:html]; NSData *dump = [[string string] dataUsingEncoding:NSUTF8StringEncoding]; - NSString *resultOnIOS = [dump description]; + NSString *resultOnIOS = [self hexStringForData:dump]; - NSString *resultOnMac = @"<4e6f7720 74686572 65206973 20736f6d 6520626f 6c642074 65787420 616e6420 73706163 65732073 686f756c 64206265 206e6f72 6d616c69 7a65642e 0a>"; + NSString *resultOnMac = @"4e6f7720746865726520697320736f6d6520626f6c64207465787420616e64207370616365732073686f756c64206265206e6f726d616c697a65642e0a"; - XCTAssertEqualObjects(resultOnIOS, resultOnMac, @"Output on List Test differs"); + XCTAssertTrue([resultOnIOS isEqualToString:resultOnMac], @"Output on List Test differs"); } - (void)testSpaceAndNewlines @@ -134,11 +134,11 @@ - (void)testSpaceAndNewlines NSAttributedString *string = [self attributedStringFromHTML:html]; NSData *dump = [[string string] dataUsingEncoding:NSUTF8StringEncoding]; - NSString *resultOnIOS = [dump description]; + NSString *resultOnIOS = [self hexStringForData:dump]; - NSString *resultOnMac = @"<626c6120 666f6c6c 6f777320 4e535374 72696e67 202a7374 72203d20 40225468 65205175 69636b20 42726f77 6e20466f 78204272 6f776e22 3b>"; + NSString *resultOnMac = @"626c6120666f6c6c6f7773204e53537472696e67202a737472203d20402254686520517569636b2042726f776e20466f782042726f776e223b"; - XCTAssertEqualObjects(resultOnIOS, resultOnMac, @"Output on List Test differs"); + XCTAssertTrue([resultOnIOS isEqualToString:resultOnMac], @"Output on List Test differs"); } - (void)testMissingClosingTagAndSpacing @@ -147,28 +147,12 @@ - (void)testMissingClosingTagAndSpacing NSAttributedString *string = [self attributedStringFromHTML:html]; NSData *dump = [[string string] dataUsingEncoding:NSUTF8StringEncoding]; - NSString *resultOnIOS = [dump description]; + NSString *resultOnIOS = [self hexStringForData:dump]; - NSString *resultOnMac = @"<696d6167 65206c61 7374>"; + NSString *resultOnMac = @"696d616765206c617374"; - XCTAssertEqualObjects(resultOnIOS, resultOnMac, @"Output on Invalid Tag Test differs"); - -} - -/* -- (void)testAttributedStringColorToHTML -{ - NSMutableAttributedString *string = [[NSMutableAttributedString alloc]initWithString: @"test"]; - - UIColor *color = [ UIColor colorWithRed: 1.0 green: 0.0 blue: 0.0 alpha: 1.0 ]; - - [ string setAttributes: [ NSDictionary dictionaryWithObject: (id)color.CGColor forKey: (id)kCTForegroundColorAttributeName ] range: NSMakeRange(0, 2) ]; - - NSString *expected = @"test\n"; - - STAssertEqualObjects([ string htmlString ], expected, @"Output on HTML string color test differs"); + XCTAssertTrue([resultOnIOS isEqualToString:resultOnMac], @"Output on Invalid Tag Test differs"); } - */ - (void)testCrashAtEmptyNodeBeforeDivWithiOS6Attributes { @@ -182,4 +166,17 @@ - (void)testCrashAtEmptyNodeBeforeDivWithiOS6Attributes XCTAssert(string != nil); } + +- (NSString *)hexStringForData:(NSData *)data +{ + const unsigned char *bytes = (const unsigned char *)data.bytes; + NSMutableString *hex = [NSMutableString new]; + + for (NSInteger i = 0; i < data.length; i++) { + [hex appendFormat:@"%02x", bytes[i]]; + } + + return [hex copy]; +} + @end From 1f02fda59ce0872b27e6b28c6c3508fa5f92acd0 Mon Sep 17 00:00:00 2001 From: Oliver Drobnik Date: Wed, 18 Sep 2019 10:51:08 +0200 Subject: [PATCH 02/13] FIXED: URLs containing CJK characters are not parsed --- Core/Source/DTHTMLAttributedStringBuilder.m | 7 +++++-- Core/Source/NSCharacterSet+HTML.h | 7 +++++++ Core/Source/NSCharacterSet+HTML.m | 15 ++++++++++++++- Core/Source/NSString+HTML.h | 5 +++++ Core/Source/NSString+HTML.m | 10 ++++++++++ 5 files changed, 41 insertions(+), 3 deletions(-) diff --git a/Core/Source/DTHTMLAttributedStringBuilder.m b/Core/Source/DTHTMLAttributedStringBuilder.m index 9e3ce097b..9632a1078 100644 --- a/Core/Source/DTHTMLAttributedStringBuilder.m +++ b/Core/Source/DTHTMLAttributedStringBuilder.m @@ -422,8 +422,11 @@ - (void)_registerTagStartHandlers } NSURL *link = [NSURL URLWithString:cleanString]; - if (link == nil) { - link = [NSURL URLWithString:[cleanString stringByURLEncoding]]; + + if (link == nil) + { + cleanString = [cleanString stringByEncodingNonASCIICharacters]; + link = [NSURL URLWithString:cleanString]; } // deal with relative URL diff --git a/Core/Source/NSCharacterSet+HTML.h b/Core/Source/NSCharacterSet+HTML.h index 282ab327f..17a354e1b 100644 --- a/Core/Source/NSCharacterSet+HTML.h +++ b/Core/Source/NSCharacterSet+HTML.h @@ -76,4 +76,11 @@ */ + (NSCharacterSet *)cssLengthUnitCharacterSet; +/** +Characterset of ASCII Characters +@returns An NSCharacterSet +*/ + ++ (NSCharacterSet *)ASCIICharacterSet; + @end diff --git a/Core/Source/NSCharacterSet+HTML.m b/Core/Source/NSCharacterSet+HTML.m index 65c19a5a3..a3f5d1472 100644 --- a/Core/Source/NSCharacterSet+HTML.m +++ b/Core/Source/NSCharacterSet+HTML.m @@ -17,7 +17,7 @@ static NSCharacterSet *_cssStyleAttributeNameCharacterSet = nil; static NSCharacterSet *_cssLengthValueCharacterSet = nil; static NSCharacterSet *_cssLengthUnitCharacterSet = nil; - +static NSCharacterSet *_asciiCharacterSet = nil; @implementation NSCharacterSet (HTML) @@ -136,4 +136,17 @@ + (NSCharacterSet *)cssLengthUnitCharacterSet return _cssLengthUnitCharacterSet; } ++ (NSCharacterSet *)ASCIICharacterSet +{ + static dispatch_once_t predicate; + + dispatch_once(&predicate, ^{ + NSMutableCharacterSet *tmpSet = [NSMutableCharacterSet new]; + [tmpSet addCharactersInRange:NSMakeRange(32, 96)]; + _asciiCharacterSet = [tmpSet copy]; + }); + + return _asciiCharacterSet; +} + @end diff --git a/Core/Source/NSString+HTML.h b/Core/Source/NSString+HTML.h index 6f0263cf8..65ae324df 100644 --- a/Core/Source/NSString+HTML.h +++ b/Core/Source/NSString+HTML.h @@ -79,4 +79,9 @@ */ - (NSString *)stringByAddingAppleConvertedSpace; +/** +Percent-encodes all characters outside the normal ASCII range +*/ +- (NSString *)stringByEncodingNonASCIICharacters; + @end diff --git a/Core/Source/NSString+HTML.m b/Core/Source/NSString+HTML.m index 0216ddaf0..3ad08d0c8 100644 --- a/Core/Source/NSString+HTML.m +++ b/Core/Source/NSString+HTML.m @@ -9,6 +9,7 @@ #import "NSString+HTML.h" #import "NSCharacterSet+HTML.h" #import "DTCoreTextConstants.h" +#import static NSDictionary *entityLookup = nil; static NSDictionary *entityReverseLookup = nil; @@ -798,4 +799,13 @@ - (NSString *)stringByAddingAppleConvertedSpace return output; } +- (NSString *)stringByEncodingNonASCIICharacters +{ +#if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_7_0 + return [self stringByURLEncoding]; +#else + return [self stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet ASCIICharacterSet]]; +#endif +} + @end From 5412f51dddad970029a46a26b70c7cf7aff2ef7e Mon Sep 17 00:00:00 2001 From: Oliver Drobnik Date: Wed, 18 Sep 2019 10:58:17 +0200 Subject: [PATCH 03/13] Implemented unit test for CJK characters in URL --- Test/Source/DTHTMLAttributedStringBuilderTest.m | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Test/Source/DTHTMLAttributedStringBuilderTest.m b/Test/Source/DTHTMLAttributedStringBuilderTest.m index 07ee4fa9f..bdb26e3d2 100644 --- a/Test/Source/DTHTMLAttributedStringBuilderTest.m +++ b/Test/Source/DTHTMLAttributedStringBuilderTest.m @@ -316,6 +316,19 @@ - (void)testTransferOfHyperlinkURLToAttachment XCTAssertEqualObjects(URL, attachment.hyperLinkURL, @"Attachment URL and element URL should match!"); } +- (void)testURLwithCJKCharacters +{ + NSAttributedString *string = [self attributedStringFromHTMLString:@"hello" options:nil]; + + NSRange effectiveRange; + NSURL *link = [string attribute:NSLinkAttributeName atIndex:0 effectiveRange:&effectiveRange]; + + NSString *linkStr = link.absoluteString; + NSString *expected = @"http://www.example.com/%E4%BD%A0%E5%A5%BD"; + + XCTAssertTrue(effectiveRange.length==5, @"There should be 5 characters with the URL"); + XCTAssertTrue([linkStr isEqualToString: expected], @"Output incorrect for CJK URL"); +} // setting ordered list starting number - (void)testOrderedListStartingNumber From ee932eaca2afe3eea215caa88f6e44345669e6d2 Mon Sep 17 00:00:00 2001 From: Darren Jones Date: Sun, 6 Oct 2019 12:12:15 +0100 Subject: [PATCH 04/13] Fixed iOS 13 openURL crash --- Demo/Source/DemoTextViewController.m | 18 ++++++++++++++++-- Demo/Source/DemoWebVideoView.m | 9 ++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Demo/Source/DemoTextViewController.m b/Demo/Source/DemoTextViewController.m index f4b0be741..71c70ca47 100644 --- a/Demo/Source/DemoTextViewController.m +++ b/Demo/Source/DemoTextViewController.m @@ -630,7 +630,14 @@ - (void)linkPushed:(DTLinkButton *)button if ([[UIApplication sharedApplication] canOpenURL:[URL absoluteURL]]) { - [[UIApplication sharedApplication] openURL:[URL absoluteURL]]; + if (@available(iOS 10.0, *)) { + [[UIApplication sharedApplication] openURL:[URL absoluteURL] options:@{} completionHandler:nil]; + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[UIApplication sharedApplication] openURL:[URL absoluteURL]]; +#pragma clang diagnostic pop + } } else { @@ -652,7 +659,14 @@ - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger { if (buttonIndex != actionSheet.cancelButtonIndex) { - [[UIApplication sharedApplication] openURL:[self.lastActionLink absoluteURL]]; + if (@available(iOS 10.0, *)) { + [[UIApplication sharedApplication] openURL:[self.lastActionLink absoluteURL] options:@{} completionHandler:nil]; + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[UIApplication sharedApplication] openURL:[self.lastActionLink absoluteURL]]; +#pragma clang diagnostic pop + } } } diff --git a/Demo/Source/DemoWebVideoView.m b/Demo/Source/DemoWebVideoView.m index b74ef5acc..68d4143e0 100644 --- a/Demo/Source/DemoWebVideoView.m +++ b/Demo/Source/DemoWebVideoView.m @@ -98,7 +98,14 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *) #if !defined(DT_APP_EXTENSIONS) if (shouldOpenExternalURL) { - [[UIApplication sharedApplication] openURL:[request URL]]; + if (@available(iOS 10.0, *)) { + [[UIApplication sharedApplication] openURL:[request URL] options:@{} completionHandler:nil]; + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[UIApplication sharedApplication] openURL:[request URL]]; +#pragma clang diagnostic pop + } } #endif From 5ba3b0ee1acee951685352c621abd1a62a5d7b93 Mon Sep 17 00:00:00 2001 From: Darren Jones Date: Sun, 6 Oct 2019 12:25:38 +0100 Subject: [PATCH 05/13] Fixed UIActionSheet deprecated --- Demo/Source/DemoTextViewController.m | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Demo/Source/DemoTextViewController.m b/Demo/Source/DemoTextViewController.m index 71c70ca47..849024d03 100644 --- a/Demo/Source/DemoTextViewController.m +++ b/Demo/Source/DemoTextViewController.m @@ -655,7 +655,11 @@ - (void)linkPushed:(DTLinkButton *)button } } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#pragma clang diagnostic ignored "-Wdeprecated-implementations" - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex +#pragma clang diagnostic pop { if (buttonIndex != actionSheet.cancelButtonIndex) { @@ -680,8 +684,28 @@ - (void)linkLongPressed:(UILongPressGestureRecognizer *)gesture if ([[UIApplication sharedApplication] canOpenURL:[button.URL absoluteURL]]) { - UIActionSheet *action = [[UIActionSheet alloc] initWithTitle:[[button.URL absoluteURL] description] delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Open in Safari", nil]; - [action showFromRect:button.frame inView:button.superview animated:YES]; + if (@available(iOS 8.0, *)) { + UIAlertController *ac = [UIAlertController alertControllerWithTitle:[[button.URL absoluteURL] description] + message:nil + preferredStyle:UIAlertControllerStyleActionSheet]; + [ac addAction:[UIAlertAction actionWithTitle:@"Open in Safari" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * _Nonnull action) { + [[UIApplication sharedApplication] openURL:[self.lastActionLink absoluteURL] options:@{} completionHandler:nil]; + }]]; + + [ac addAction:[UIAlertAction actionWithTitle:@"Cancel" + style:UIAlertActionStyleCancel + handler:nil]]; + + [self presentViewController:ac animated:YES completion:nil]; + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + UIActionSheet *action = [[UIActionSheet alloc] initWithTitle:[[button.URL absoluteURL] description] delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Open in Safari", nil]; + [action showFromRect:button.frame inView:button.superview animated:YES]; +#pragma clang diagnostic pop + } } } } From 63a6f68a9497179d5f3573228aaa5d81b2fb5db2 Mon Sep 17 00:00:00 2001 From: Oliver Drobnik Date: Mon, 25 May 2020 15:28:36 +0200 Subject: [PATCH 06/13] change to use use WebKit Web View in demo vor videos --- DTCoreText.xcodeproj/project.pbxproj | 4 ++++ Demo/Source/DemoWebVideoView.h | 3 ++- Demo/Source/DemoWebVideoView.m | 25 ++++++++++++------------- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/DTCoreText.xcodeproj/project.pbxproj b/DTCoreText.xcodeproj/project.pbxproj index f6ca1cdae..ddde91e6a 100644 --- a/DTCoreText.xcodeproj/project.pbxproj +++ b/DTCoreText.xcodeproj/project.pbxproj @@ -216,6 +216,7 @@ A76E5B4912DD9AF500711782 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A76E5B4812DD9AF500711782 /* QuartzCore.framework */; }; A776DBE81716A8EE00E71F36 /* NSStringParagraphTest.m in Sources */ = {isa = PBXBuildFile; fileRef = A776DBE71716A8EE00E71F36 /* NSStringParagraphTest.m */; }; A77A3E421779BF04000B290B /* NSMutableAttributedStringHTMLTest.m in Sources */ = {isa = PBXBuildFile; fileRef = A77A3E411779BF03000B290B /* NSMutableAttributedStringHTMLTest.m */; }; + A786FBAB247BFC1D00890B3D /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A786FB91247BFC1D00890B3D /* WebKit.framework */; }; A788CA3A14863EF100E1AFD9 /* Alignment.html in Resources */ = {isa = PBXBuildFile; fileRef = A788CA1B14863EF100E1AFD9 /* Alignment.html */; }; A788CA3B14863EF100E1AFD9 /* APOD.html in Resources */ = {isa = PBXBuildFile; fileRef = A788CA1C14863EF100E1AFD9 /* APOD.html */; }; A788CA3C14863EF100E1AFD9 /* ArabicTest.html in Resources */ = {isa = PBXBuildFile; fileRef = A788CA1D14863EF100E1AFD9 /* ArabicTest.html */; }; @@ -882,6 +883,7 @@ A77A3E411779BF03000B290B /* NSMutableAttributedStringHTMLTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSMutableAttributedStringHTMLTest.m; sourceTree = ""; }; A783CE6717D11D0100C84C28 /* CSSOOMCrash.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = CSSOOMCrash.plist; sourceTree = ""; }; A785701C17FAA69D0080AB0A /* DTFoundation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = DTFoundation.xcodeproj; path = DTFoundation/DTFoundation.xcodeproj; sourceTree = ""; }; + A786FB91247BFC1D00890B3D /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.5.sdk/System/Library/Frameworks/WebKit.framework; sourceTree = DEVELOPER_DIR; }; A788C91014863E8700E1AFD9 /* DTAttributedTextCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTAttributedTextCell.h; sourceTree = ""; }; A788C91114863E8700E1AFD9 /* DTAttributedTextCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = DTAttributedTextCell.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; A788C91214863E8700E1AFD9 /* DTAttributedTextContentView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTAttributedTextContentView.h; sourceTree = ""; }; @@ -1082,6 +1084,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + A786FBAB247BFC1D00890B3D /* WebKit.framework in Frameworks */, A7949A0014C6256B00A8CCDE /* libxml2.dylib in Frameworks */, A75C6C72141798CE00AEE350 /* MobileCoreServices.framework in Frameworks */, A7D29D661CB68D470068F043 /* DTCoreText.framework in Frameworks */, @@ -1194,6 +1197,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + A786FB91247BFC1D00890B3D /* WebKit.framework */, A74A7AAC1B617250004163BE /* QuartzCore.framework */, A74A7AAA1B617227004163BE /* CoreGraphics.framework */, A74A7AA81B617222004163BE /* UIKit.framework */, diff --git a/Demo/Source/DemoWebVideoView.h b/Demo/Source/DemoWebVideoView.h index 0408e7397..248dd77e1 100644 --- a/Demo/Source/DemoWebVideoView.h +++ b/Demo/Source/DemoWebVideoView.h @@ -7,6 +7,7 @@ // #import +#import @class DemoWebVideoView; @class DTTextAttachment; @@ -37,7 +38,7 @@ To add additional video services please add them in the mentioned location and submit a pull request for the addition. */ -@interface DemoWebVideoView : UIView +@interface DemoWebVideoView : UIView /** The delegate of the video view diff --git a/Demo/Source/DemoWebVideoView.m b/Demo/Source/DemoWebVideoView.m index 68d4143e0..ba71cadd9 100644 --- a/Demo/Source/DemoWebVideoView.m +++ b/Demo/Source/DemoWebVideoView.m @@ -22,7 +22,7 @@ @implementation DemoWebVideoView DT_WEAK_VARIABLE id _delegate; - UIWebView *_webView; + WKWebView *_webView; } - (id)initWithFrame:(CGRect)frame @@ -32,25 +32,20 @@ - (id)initWithFrame:(CGRect)frame { self.userInteractionEnabled = YES; - _webView = [[UIWebView alloc] initWithFrame:self.bounds]; + _webView = [[WKWebView alloc] initWithFrame:self.bounds]; _webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; [self addSubview:_webView]; [self disableScrolling]; - _webView.delegate = self; - - if ([_webView respondsToSelector:@selector(setAllowsInlineMediaPlayback:)]) - { - _webView.allowsInlineMediaPlayback = YES; - } + _webView.navigationDelegate = self; } return self; } - (void)dealloc { - _webView.delegate = nil; + _webView.navigationDelegate = nil; } @@ -74,18 +69,22 @@ - (void)disableScrolling #pragma mark UIWebViewDelegate -- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType +- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { + NSURLRequest *request = navigationAction.request; + // allow the embed request for YouTube if (NSNotFound != [[[request URL] absoluteString] rangeOfString:@"www.youtube.com/embed/"].location) { - return YES; + decisionHandler(WKNavigationActionPolicyAllow); + return; } // allow the embed request for DailyMotion Cloud if (NSNotFound != [[[request URL] absoluteString] rangeOfString:@"api.dmcloud.net/player/embed/"].location) { - return YES; + decisionHandler(WKNavigationActionPolicyAllow); + return; } BOOL shouldOpenExternalURL = YES; @@ -109,7 +108,7 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *) } #endif - return NO; + decisionHandler(WKNavigationActionPolicyCancel); } From 5a704171bdb4f7cc585d89beef2a95137dd928d4 Mon Sep 17 00:00:00 2001 From: wangliang Date: Mon, 1 Jun 2020 15:10:29 +0800 Subject: [PATCH 07/13] fix css attribute like p.Text { font-family: ; font-size: 1em; line-height: 1.5em; text-align: left; text-indent: 2em; margin: 0.6em 0; letter-spacing: auto; } --- Core/Source/NSScanner+HTML.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Source/NSScanner+HTML.m b/Core/Source/NSScanner+HTML.m index e8f1a48e4..79f9ab761 100644 --- a/Core/Source/NSScanner+HTML.m +++ b/Core/Source/NSScanner+HTML.m @@ -57,7 +57,7 @@ - (BOOL)scanCSSAttribute:(NSString * __autoreleasing*)name value:(id __autorelea NSMutableArray *results = [NSMutableArray array]; BOOL nextIterationAddsNewEntry = YES; - while (![self isAtEnd] && ![self scanString:@";" intoString:NULL]) + while (![self isAtEnd] && ![self scanString:@";" intoString:NULL] && ![self scanString:@"'';" intoString:NULL] && ![self scanString:@"\"\";" intoString:NULL]) { // skip whitespace [self scanCharactersFromSet:whiteCharacterSet intoString:NULL]; From f86d195073e3adfac6b2fef5f36b977c9f618b21 Mon Sep 17 00:00:00 2001 From: Savio Figueiredo Date: Sat, 27 Jun 2020 00:25:04 -0700 Subject: [PATCH 08/13] Fix: Fixing iOS 14 implict conversion error from NSWritingDirection to CTWritingDirection This is the error message: Implicit conversion from enumeration type enum NSWritingDirection to different enumeration type CTWritingDirection --- Core/Source/DTHTMLElement.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/Source/DTHTMLElement.m b/Core/Source/DTHTMLElement.m index 1a1bcdfd8..156decd11 100644 --- a/Core/Source/DTHTMLElement.m +++ b/Core/Source/DTHTMLElement.m @@ -1572,15 +1572,15 @@ - (void)interpretAttributes if ([directionStr isEqualToString:@"rtl"]) { - _paragraphStyle.baseWritingDirection = NSWritingDirectionRightToLeft; + _paragraphStyle.baseWritingDirection = kCTWritingDirectionRightToLeft; } else if ([directionStr isEqualToString:@"ltr"]) { - _paragraphStyle.baseWritingDirection = NSWritingDirectionLeftToRight; + _paragraphStyle.baseWritingDirection = kCTWritingDirectionLeftToRight; } else if ([directionStr isEqualToString:@"auto"]) { - _paragraphStyle.baseWritingDirection = NSWritingDirectionNatural; // that's also default + _paragraphStyle.baseWritingDirection = kCTWritingDirectionNatural; // that's also default } else { From 5f8ac0f48a1d8a3c0c6ad990340a160b8c5eb791 Mon Sep 17 00:00:00 2001 From: Oliver Drobnik Date: Fri, 31 Jul 2020 11:06:13 +0200 Subject: [PATCH 09/13] removed UIWebView reference #1194 --- Readme.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.markdown b/Readme.markdown index 55c9f3391..7ffbb16d6 100644 --- a/Readme.markdown +++ b/Readme.markdown @@ -8,7 +8,7 @@ The project covers two broad areas: 1. **Layouting** - Interfacing with CoreText, generating attributed strings from HTML code 2. **User Interface** - UI-related classes render these objects, specifically `DTAttributedTextView`, `DTAttributedLabel` and `DTAttributedTextCell`. -This is useful for drawing simple rich text like any HTML document without having to use a `UIWebView`. For text selection and highlighting (as you might need for an Editor or Reader) there is the commercial **DTRichTextEditor** component which can be purchased in the [Cocoanetics Parts Store](http://www.cocoanetics.com/parts/dtrichtexteditor/). +This is useful for drawing simple rich text like any HTML document without having to use a web view. For text selection and highlighting (as you might need for an Editor or Reader) there is the commercial **DTRichTextEditor** component which can be purchased in the [Cocoanetics Parts Store](http://www.cocoanetics.com/parts/dtrichtexteditor/). Documentation ------------- From 6a8f9e3b103b116a5e085d48e8c0aaa3caaa1503 Mon Sep 17 00:00:00 2001 From: Oliver Drobnik Date: Fri, 31 Jul 2020 11:07:56 +0200 Subject: [PATCH 10/13] removed mentioning of UIWebView where it makes sense #1194 --- .../DTCoreTextLayoutFrameAccessibilityElementGenerator.m | 2 +- Demo/Resources/README.html | 4 ++-- Demo/Source/DemoWebVideoView.h | 2 +- Demo/Source/DemoWebVideoView.m | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Core/Source/DTCoreTextLayoutFrameAccessibilityElementGenerator.m b/Core/Source/DTCoreTextLayoutFrameAccessibilityElementGenerator.m index f30428b74..87e1a292b 100644 --- a/Core/Source/DTCoreTextLayoutFrameAccessibilityElementGenerator.m +++ b/Core/Source/DTCoreTextLayoutFrameAccessibilityElementGenerator.m @@ -77,7 +77,7 @@ - (DTAccessibilityElement *)accessibilityElementForTextInAttributedString:(NSAtt element.accessibilityLabel = text; element.localCoordinateAccessibilityFrame = [self frameForRuns:runs]; - // We're trying to keep the accessibility frame behavior consistent with UIWebView, which seems to do a union of the rects for all the runs composing a single accessibility group, + // We're trying to keep the accessibility frame behavior consistent with web view, which seems to do a union of the rects for all the runs composing a single accessibility group, // even if that spans across multiple lines. Set the local coordinate activation point to support multi-line links. A link that is at the end of one line and // wraps to the beginning of the next would have a rect that's the size of both lines combined. The center of that rect would be outside the hit areas for either of the // runs individually, so we set the accessibility activation point to be the origin of the first run. diff --git a/Demo/Resources/README.html b/Demo/Resources/README.html index 07951297f..e84351e59 100644 --- a/Demo/Resources/README.html +++ b/Demo/Resources/README.html @@ -1,7 +1,7 @@

NSAttributedString HTML Additions

Introduction

This project aims to duplicate the methods present on Mac OSX which allow creation of NSAttributedString from HTML code. -This is useful for drawing simple rich text - like this document - without having to use a UIWebView.

+This is useful for drawing simple rich text - like this document - without having to use a web view.

Hi! I'm Oliver and I appreciate your help!

Features

@@ -30,4 +30,4 @@

Please Help!

If you find brief test cases where the created NSAttributedString differs from the version on OSX please send them to us!

Also there are many small things that you could help this project with. You can either implement these yourself or sponsor their development.

Follow @cocoanetics on Twitter

-

This code is covered by a BSD License. © 2011 Oliver Drobnik

\ No newline at end of file +

This code is covered by a BSD License. © 2011 Oliver Drobnik

diff --git a/Demo/Source/DemoWebVideoView.h b/Demo/Source/DemoWebVideoView.h index 248dd77e1..03d0a6540 100644 --- a/Demo/Source/DemoWebVideoView.h +++ b/Demo/Source/DemoWebVideoView.h @@ -34,7 +34,7 @@ /** The class represents a custom subview for use in to represent an embedded video. - Embedded videos work by loading the video URL in a UIWebView which iOS then replaces with the built-in media player view. The URL of the embed script depends on the service and needs to be added to the webView:shouldStartLoadWithRequest:navigationType:. You want to allow the URL for the embed script, but disallow all other requests which for example occur if a user taps on the YouTube logo. If you were to allow this type of navigation then the YouTube website would be loaded in the video view. For these scenarios there is the videoView:shouldOpenExternalURL: method in DemoWebVideoViewDelegate. If you respond with `YES` (which is default if the method is not implemented) then the URL will be opened in Safari. + Embedded videos work by loading the video URL in a web view which iOS then replaces with the built-in media player view. The URL of the embed script depends on the service and needs to be added to the webView:shouldStartLoadWithRequest:navigationType:. You want to allow the URL for the embed script, but disallow all other requests which for example occur if a user taps on the YouTube logo. If you were to allow this type of navigation then the YouTube website would be loaded in the video view. For these scenarios there is the videoView:shouldOpenExternalURL: method in DemoWebVideoViewDelegate. If you respond with `YES` (which is default if the method is not implemented) then the URL will be opened in Safari. To add additional video services please add them in the mentioned location and submit a pull request for the addition. */ diff --git a/Demo/Source/DemoWebVideoView.m b/Demo/Source/DemoWebVideoView.m index ba71cadd9..498beb5a5 100644 --- a/Demo/Source/DemoWebVideoView.m +++ b/Demo/Source/DemoWebVideoView.m @@ -67,7 +67,7 @@ - (void)disableScrolling } } -#pragma mark UIWebViewDelegate +#pragma mark WKWebViewDelegate - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { From ce48bdf44dc66623e643d2cee0ae0155a08de485 Mon Sep 17 00:00:00 2001 From: Oliver Drobnik Date: Fri, 31 Jul 2020 11:15:30 +0200 Subject: [PATCH 11/13] fixed warning about case --- Test/Source/DTCSSStylesheetTest.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/Source/DTCSSStylesheetTest.m b/Test/Source/DTCSSStylesheetTest.m index f36a3abcc..9b58b193e 100644 --- a/Test/Source/DTCSSStylesheetTest.m +++ b/Test/Source/DTCSSStylesheetTest.m @@ -6,7 +6,7 @@ // Copyright (c) 2012 Drobnik.com. All rights reserved. // -#import "DTCSSStyleSheetTest.h" +#import "DTCSSStylesheetTest.h" #import "DTCSSStylesheet.h" #import "DTHTMLElement.h" From 27ab92f3e42f31a27e3f68db004a5583f502e101 Mon Sep 17 00:00:00 2001 From: Oliver Drobnik Date: Fri, 31 Jul 2020 11:22:18 +0200 Subject: [PATCH 12/13] Added unit test #1183 --- Test/Source/DTCSSStylesheetTest.m | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Test/Source/DTCSSStylesheetTest.m b/Test/Source/DTCSSStylesheetTest.m index 9b58b193e..1be494474 100644 --- a/Test/Source/DTCSSStylesheetTest.m +++ b/Test/Source/DTCSSStylesheetTest.m @@ -47,6 +47,35 @@ - (void)testAttributeWithWhitespace XCTAssertEqualObjects(empty2, @"", @"empty2 should match"); } +// Issue 1183 + +- (void)testEmptyFontFamily +{ + NSString *string = @"span { font-family: ''; empty: ; empty2:; font-size: 16px; line-height: 20 px; font-style: italic }"; + + DTCSSStylesheet *stylesheet = [[DTCSSStylesheet alloc] initWithStyleBlock:string]; + + NSDictionary *styles = [stylesheet.styles objectForKey:@"span"]; + + NSString *fontFamily = [styles objectForKey:@""]; + XCTAssertNil(fontFamily, @"font-family should be nil"); + + NSString *fontSize = [styles objectForKey:@"font-size"]; + XCTAssertEqualObjects(fontSize, @"16px", @"font-size should match"); + + NSString *lineHeight = [styles objectForKey:@"line-height"]; + XCTAssertEqualObjects(lineHeight, @"20 px", @"line-height should match"); + + NSString *fontStyle = [styles objectForKey:@"font-style"]; + XCTAssertEqualObjects(fontStyle, @"italic", @"font-style should match"); + + NSString *empty = [styles objectForKey:@"empty"]; + XCTAssertEqualObjects(empty, @"", @"empty should match"); + + NSString *empty2 = [styles objectForKey:@"empty2"]; + XCTAssertEqualObjects(empty2, @"", @"empty2 should match"); +} + // the !important CSS tag should be ignored - (void)testImportant { From 5e192b2ea505d4c0c54bc90d35010ceeda2dc54a Mon Sep 17 00:00:00 2001 From: Oliver Drobnik Date: Thu, 6 Aug 2020 11:43:43 +0200 Subject: [PATCH 13/13] Updated version --- DTCoreText.podspec | 2 +- DTCoreText.xcodeproj/project.pbxproj | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DTCoreText.podspec b/DTCoreText.podspec index 2eb6e72fd..d2dcc967c 100644 --- a/DTCoreText.podspec +++ b/DTCoreText.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'DTCoreText' - spec.version = '1.6.23' + spec.version = '1.6.24' spec.platforms = {:ios => '4.3', :tvos => '9.0' } spec.license = 'BSD' spec.source = { :git => 'https://github.com/Cocoanetics/DTCoreText.git', :tag => spec.version.to_s } diff --git a/DTCoreText.xcodeproj/project.pbxproj b/DTCoreText.xcodeproj/project.pbxproj index ddde91e6a..0fdad9724 100644 --- a/DTCoreText.xcodeproj/project.pbxproj +++ b/DTCoreText.xcodeproj/project.pbxproj @@ -3262,7 +3262,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 1.6.23; + CURRENT_PROJECT_VERSION = 1.6.24; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; GCC_C_LANGUAGE_STANDARD = c99; @@ -3404,7 +3404,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 1.6.23; + CURRENT_PROJECT_VERSION = 1.6.24; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; @@ -3460,7 +3460,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 1.6.23; + CURRENT_PROJECT_VERSION = 1.6.24; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; GCC_C_LANGUAGE_STANDARD = c99;